<|start_filename|>resources/ui/widget/components/SetNewWorkItemValues/SetNewWorkItemValues.js<|end_filename|>
define([
    "dojo/_base/declare",
    "dojo/dom-style",
    "../../services/MainDataStore",
    "../SetNewWorkItemAttributes/SetNewWorkItemAttributes",
    "../SetNewWorkItemLinks/SetNewWorkItemLinks",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dijit/_WidgetsInTemplateMixin",
    "dojo/text!./SetNewWorkItemValues.html",
    "jazz/css!./SetNewWorkItemValues.css"
], function (declare, domStyle,
    MainDataStore,
    SetNewWorkItemAttributes, SetNewWorkItemLinks,
    _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin,
    template) {
    return declare("com.siemens.bt.jazz.workitemeditor.rtcGitConnector.ui.widget.setNewWorkItemValues",
        [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin],
    {
        templateString: template,

        visible: false,
        _setVisibleAttr: function (visible) {
            domStyle.set(this.domNode, "display", visible ? "block" : "none");
            this._set("visible", visible);
        },

        constructor: function () {
            this.mainDataStore = MainDataStore.getInstance();
        },

        startup: function () {
            if (this.mainDataStore.newWorkItemMode) {
                this.watchDataStore();
            }
        },

        watchDataStore: function () {
            var self = this;

            // Only show the attributes when the list of selected issues isn't empty
            this.mainDataStore.selectedRepositoryData.issuesToLink.watchElements(function () {
                var hasItems = self.mainDataStore.selectedRepositoryData.issuesToLink.length > 0;
                self.set("visible", hasItems);

                if (hasItems) {
                    self.setNewWorkItemAttributes.show();
                    self.setNewWorkItemLinks.show();
                }
            });
        }
    });
});

<|start_filename|>resources/ui/widget/components/NewWorkItemList/NewWorkItemList.js<|end_filename|>
define([
    "dojo/_base/declare",
    "dojo/_base/array",
    "dojo/dom-construct",
    "dojo/on",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dijit/registry",
    "dojo/text!./NewWorkItemList.html",
    "jazz/css!./NewWorkItemList.css",
    "com.ibm.team.workitem.web.cache.internal.Cache",
    "com.ibm.team.workitem.web.cache.internal.QueryProxy",
    "com.ibm.team.workitem.web.client.internal.query.AttributeExpression",
    "com.ibm.team.workitem.web.client.internal.query.Operator",
    "com.ibm.team.workitem.web.client.internal.query.QueryDescriptor",
    "com.ibm.team.workitem.web.client.internal.query.Term",
    "com.ibm.team.workitem.web.client.internal.query.UIItem",
    "com.ibm.team.workitem.web.client.internal.query.Variable",
    "com.ibm.team.workitem.web.client.util"
], function (declare, array, domConstruct, on,
    _WidgetBase, _TemplatedMixin, registry,
    template) {
    var Cache = com.ibm.team.workitem.web.cache.internal.Cache;
    var QueryProxy = com.ibm.team.workitem.web.cache.internal.QueryProxy;
    var AttributeExpression = com.ibm.team.workitem.web.client.internal.query.AttributeExpression;
    var Operator = com.ibm.team.workitem.web.client.internal.query.Operator;
    var QueryDescriptor = com.ibm.team.workitem.web.client.internal.query.QueryDescriptor;
    var Term = com.ibm.team.workitem.web.client.internal.query.Term;
    var UIItem = com.ibm.team.workitem.web.client.internal.query.UIItem;
    var Variable = com.ibm.team.workitem.web.client.internal.query.Variable;
    var util = com.ibm.team.workitem.web.client.util;

    var NewWorkItemList = declare("com.siemens.bt.jazz.workitemeditor.rtcGitConnector.ui.widget.newWorkItemList",
        [_WidgetBase, _TemplatedMixin,],
    {
        templateString: template,
        id: "rtcGitConnectorNewWorkItemListWidget",
        newWorkItems: [],
        subscriptionHandles: [],

        // Add the widget above the work item editor on the work item editor page.
        addToPage: function () {
            try {
                jazz.app.currentApplication.workbench._pageWidgetCache["com.ibm.team.workitem"]
                    .domNode.lastElementChild.insertAdjacentElement("beforebegin", this.domNode);
            } catch (e) {
                console.log("Error placing NewWorkItemList on the page.");
            }
        },

        // Update from the current list of new work items.
        // If there are no more items in the list the specified handles
        // are unsubscribed and the widget is destroyed.
        updateContent: function (subscriptionHandles) {
            this._updateSubscriptions(subscriptionHandles);
            this._getNewWorkItems();

            if (this.newWorkItems.length) {
                // Set the updated list in the view
                this._clearContent();
                this._addNewWorkItemsToView();
            } else {
                // Unsubscribe from all handles before destroying
                this._updateSubscriptions();

                // Add success message with query for new work items created from git issues
                this._createSuccessMessage();

                // Destroy the widget when when the list is empty
                this.destroyRecursive(false);
            }
        },

        // Get all new work items from the work item cache
        _getNewWorkItems: function () {
            this.newWorkItems = Cache.getAllItems({
                filterSelectors: [ "isNew" ],
                filterAttributes: [ "isWorkItem"]
            });
        },

        // Only keep the current subscriptions. Unsubscribe any old ones.
        // Unsubscribes all handles if the new list of handles is empty or not present.
        _updateSubscriptions: function (newSubscriptionHandles) {
            if (!newSubscriptionHandles) {
                newSubscriptionHandles = [];
            }

            if (this.subscriptionHandles.length) {
                this.subscriptionHandles.forEach(function (oldSubscriptionHandle) {
                    if (!newSubscriptionHandles.some(function (newSubscriptionHandle) {
                        return newSubscriptionHandle === oldSubscriptionHandle;
                    })) {
                        dojo.unsubscribe(oldSubscriptionHandle);
                    }
                });
            }

            this.subscriptionHandles = newSubscriptionHandles;
        },

        // Empty the links container so that in can be recreated
        _clearContent: function () {
            domConstruct.empty(this.linksContainer);
        },

        // Add all new work items to the view in the form of links
        _addNewWorkItemsToView: function () {
            var self = this;

            if (this.newWorkItems && this.newWorkItems.length) {
                array.forEach(this.newWorkItems, function (newWorkItem) {
                    self._addNewWorkItemToView(newWorkItem);
                });
            }
        },

        // Add a link to a single work item to the view
        _addNewWorkItemToView: function (workItem) {
            var workItemUrl = workItem.getUrl(true);
            var workItemSummary = workItem.object.attributes.summary;

            if (typeof workItemSummary.content === "string") {
                workItemSummary = workItemSummary.content;
            }

            var newWorkItemRow = domConstruct.create("a", {
                "class": "rtcGitConnectorNewWorkItemListRow",
                href: workItemUrl
            }, this.linksContainer);

            if (window.location.href === workItemUrl) {
                var bulletSpan = domConstruct.create("span", {
                    "class": "rtcGitConnectorNewWorkItemListRowBullet"
                }, newWorkItemRow);
                domConstruct.create("span", {
                    innerHTML: "•"
                }, bulletSpan);
            }

            domConstruct.create("img", {
                "src": workItem.getTypeIconUrl(),
                "alt": workItem.object.attributes.workItemType.label
            }, newWorkItemRow);
            domConstruct.create("span", {
                innerHTML: " * [New " + workItem.object.attributes.workItemType.label + "] "
                    + workItemSummary
            }, newWorkItemRow);
        },

        // Add success message with query for new work items created from git issues
        _createSuccessMessage: function () {
            var newWorkItemsQuery = this._createNewWorkItemsQuery();
            var successMessageDiv = domConstruct.create("div", {
                "id": "rtcGitConnectorNewWorkItemListSuccessMessageDiv",
                "class": "rtcGitConnectorNewWorkItemList"
            });
            domConstruct.create("div", {
                "class": "rtcGitConnectorNewWorkItemListTitle",
                innerHTML: "Finished creating work items from git issues"
            }, successMessageDiv);
            var flexContainer = domConstruct.create("div", {
                "class": "rtcGitConnectorNewWorkItemListFlex"
            }, successMessageDiv);
            var queryRow = domConstruct.create("a", {
                "class": "rtcGitConnectorNewWorkItemListRow",
                href: this._getQueryNewWorkItemsUrl(newWorkItemsQuery)
            }, flexContainer);
            domConstruct.create("img", {
                "class": "rtcGitConnectorNewWorkItemQueryIcon",
                "src": this._getQueryIconUrl(newWorkItemsQuery),
                "alt": "Query for all new work items created from git issues"
            }, queryRow);
            domConstruct.create("span", {
                innerHTML: "Click here to view all new work items created from git issues"
            }, queryRow);
            var removeButton = domConstruct.create("button", {
                "class": "rtcGitConnectorNewWorkItemListButton",
                type: "button",
                innerHTML: "Hide"
            }, flexContainer);

            on(queryRow, "click", this._removeSuccessMessageFromPage);
            on(removeButton, "click", this._removeSuccessMessageFromPage);

            this.domNode.insertAdjacentElement("beforebegin", successMessageDiv);
        },

        // Remove the success message div from the page
        _removeSuccessMessageFromPage: function () {
            domConstruct.destroy("rtcGitConnectorNewWorkItemListSuccessMessageDiv");
        },

        // Get the url of the query for all new work items created from git issues
        _getQueryNewWorkItemsUrl: function (query) {
            return window.location.pathname + util.getRunNewQueryUri(query);
        },

        // Get the url of the query icon
        _getQueryIconUrl: function (query) {
            var queryProxy = new QueryProxy({
                query: query
            });

            return queryProxy.getMenuIconUri();
        },

        // Create a query for all work items with the tag "from-git-issue" and
        // created today and created by the current user.
        _createNewWorkItemsQuery: function () {
            // Create a query term with the "AND" operator
            var term = new Term(Operator.AND);

            // Create an attribute expression that matches the tag "from-git-issue"
            var tagsExpression = new AttributeExpression("internalTags", new Operator("is", null), [new UIItem("from-git-issue")]);
            term.addAttributeExpression(tagsExpression);

            // Create an attribute expression that matches the creationDate and the value of "today"
            var creationExpression = new AttributeExpression("creationDate", new Operator("is", null));
            var creationVariable = new Variable("now", "0d");
            creationExpression.setVariables([creationVariable]);
            term.addAttributeExpression(creationExpression);

            // Create an attribute expression that matches the creator and the value "currentUser"
            var creatorExpression = new AttributeExpression("creator", new Operator("is", null));
            var creatorVariable = new Variable("currentUser", "");
            creatorExpression.setVariables([creatorVariable]);
            term.addAttributeExpression(creatorExpression);

            // Create a query object with a title for the UI and the created query terms
            var queryDto = {
                name: "My new work items from git issues (created today)",
                itemId: "",
                expression: term.createDTO()
            };
            var query = QueryDescriptor.createFromEditableQueryDTO(queryDto);

            return query;
        }
    });

    // Don't expose the class directly but rather just the update function.
    return new function () {
        // Updates the list of new work items. Creates and places the widget in the dom
        // if it doesn't exist. Removes and destroys the widget if the list is empty.
        // Also unsubscribes from the specified handles when destroying the widget.
        this.UpdateNewWorkItemList = function (subscriptionHandles) {
            // Get the existing widget by id
            var newWorkItemListWidget = registry.byId('rtcGitConnectorNewWorkItemListWidget');

            if (!newWorkItemListWidget) {
                // Create a new instance if the widget wasn't found
                newWorkItemListWidget = new NewWorkItemList();

                // Remove the success message if it exists before adding the new widget to the page
                newWorkItemListWidget._removeSuccessMessageFromPage();

                // Add the new widget to the page
                newWorkItemListWidget.addToPage();
            }

            // Create the list of new work items and add it to the view
            newWorkItemListWidget.updateContent(subscriptionHandles);
        };
    };
});

<|start_filename|>resources/ui/widget/components/SetNewWorkItemLinks/SetNewWorkItemLinks.css<|end_filename|>
.setNewWorkItemLinksContainer {
    padding-top: 0.5em;
}

<|start_filename|>resources/ui/widget/components/ViewIssuesToLink/ViewIssuesToLink.js<|end_filename|>
define([
    "dojo/_base/declare",
    "dojo/_base/array",
    "dojo/_base/lang",
    "dojo/dom-construct",
    "dojo/dom-style",
    "../../services/MainDataStore",
    "../../js/ViewHelper",
    "../ListItem/ListItem",
    "dijit/Tooltip",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dijit/_WidgetsInTemplateMixin",
    "dojo/text!./ViewIssuesToLink.html"
], function (declare, array, lang, domConstruct, domStyle,
    MainDataStore, ViewHelper, ListItem,
    Tooltip, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin,
    template) {
    return declare("com.siemens.bt.jazz.workitemeditor.rtcGitConnector.ui.widget.viewIssuesToLink",
        [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin],
    {
        templateString: template,
        mainDataStore: null,

        constructor: function () {
            this.mainDataStore = MainDataStore.getInstance();
        },

        startup: function () {
            this.watchDataStore();
        },

        watchDataStore: function () {
            var self = this;

            // React when issues are added or removed from the issues to link list
            this.mainDataStore.selectedRepositoryData.issuesToLink.watchElements(function () {
                if (self.mainDataStore.selectedRepositoryData.issuesToLink.length > 0) {
                    // show issues to link list
                    domStyle.set("viewIssuesToLinkContainer", "display", "block");
                    domStyle.set("rtcGitConnectorIssuesListToLink", "width", "100%");
                    domStyle.set("rtcGitConnectorIssuesListToLink", "margin-right", "10px");
                } else {
                    // hide issues to link list
                    domStyle.set("rtcGitConnectorIssuesListToLink", "width", "0");
                    domStyle.set("rtcGitConnectorIssuesListToLink", "margin-right", "0");
                    domStyle.set("viewIssuesToLinkContainer", "display", "none");
                }

                self.drawIssuesToLink(self.mainDataStore.selectedRepositoryData.issuesToLink);
            });
        },

        // Draw the issues to link list in the view
        drawIssuesToLink: function (issuesToLink) {
            var self = this;
            var gitHost = this.mainDataStore.selectedRepositorySettings.get("gitHost");
            domConstruct.empty(this.listItemsContainer);

            if (self.tooltip) {
                self.tooltip.destroy();
                self.tooltip = null;
            }

            self.tooltip = new Tooltip({
                position: ["above", "below"],
                showDelay: 0
            });

            array.forEach(issuesToLink, function (issue) {
                var details;
                var buttonType;
                var duplicate = false;

                if (issue.id < 0) {
                    var workItemTags = self.mainDataStore.workItem.getValue({
                        path: ["attributes", "internalTags", "content"]
                    });

                    if (workItemTags.length && workItemTags.indexOf("created-as-git-issue") !== -1) {
                        duplicate = true;
                        self.tooltip.set("label", "This work item has already been created as a git issue.");
                    }

                    details = "This will create a new issue in " + gitHost.displayName + " using the information from the current work item";
                    buttonType = "times";
                } else {
                    if (self.mainDataStore.newWorkItemMode && issue.labels && issue.labels.indexOf("created-as-rtc-work-item") !== -1) {
                        duplicate = true;
                        self.tooltip.set("label", "This git issue has already been created as a work item.");
                    }

                    details = ViewHelper.GetIssueOrRequestDateString(issue);
                    buttonType = "trash";
                }

                var listItem = new ListItem(issue.id);
                listItem.set("title", issue.title);
                listItem.set("details", details);
                listItem.set("buttonType", buttonType);
                listItem.set("duplicate", duplicate);
                listItem.set("notClickable", true);

                listItem.onButtonClick = lang.hitch(self, self.listItemButtonClick);

                issue.listItem = listItem;
                domConstruct.place(listItem.domNode, self.listItemsContainer);

                if (duplicate) {
                    self.tooltip.addTarget(listItem.itemRightButton);
                }
            });

            // Get the mainDialog and resize to fit the new content
            ViewHelper.ResizeMainDialog();
        },

        // Remove the issue with the specified id from the issues to link list in store and add to the issues list
        listItemButtonClick: function (itemId) {
            var selectedIssue = null;

            for (var i = this.mainDataStore.selectedRepositoryData.issuesToLink.length - 1; i >= 0; i--) {
                if (this.mainDataStore.selectedRepositoryData.issuesToLink[i].id == itemId) {
                    selectedIssue = this.mainDataStore.selectedRepositoryData.issuesToLink.splice(i, 1)[0];
                    break;
                }
            }

            if (selectedIssue && !this.mainDataStore.selectedRepositoryData.issues.find(function (issue) {
                return issue.id == selectedIssue.id;
            })) {
                this.mainDataStore.selectedRepositoryData.issues.push(selectedIssue);
            }
        }
    });
});

<|start_filename|>resources/ui/widget/components/SetNewWorkItemLinks/SetNewWorkItemLinks.js<|end_filename|>
define([
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/dom-construct",
    "dojo/dom-style",
    "dojo/string",
    "../../services/MainDataStore",
    "dijit/MenuItem",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dojo/text!./SetNewWorkItemLinks.html",
    "jazz/css!./SetNewWorkItemLinks.css",
    "com.ibm.jdojox.util.ArrayList",
    "com.ibm.jdojox.util.JDojoX",
    "com.ibm.team.rtc.foundation.web.model.Bindable",
    "com.ibm.team.rtc.foundation.web.model.BindableList",
    "com.ibm.team.rtc.foundation.web.model.Label",
    "com.ibm.team.rtc.foundation.web.model.ListBindings",
    "com.ibm.team.rtc.foundation.web.ui.util.Sprites",
    "com.ibm.team.rtc.foundation.web.ui.views.controller.ActionDropdown",
    "com.ibm.team.rtc.foundation.web.ui.views.controller.ArtifactMultiList",
    "com.ibm.team.workitem.web.model.links.WorkItemEndpoints",
    "com.ibm.team.workitem.web.ui.internal.view.editor.presentations.nonattribute.links.LinksDialogLauncher"
], function (declare, lang, domConstruct, domStyle, string,
    MainDataStore,
    MenuItem,
    _WidgetBase, _TemplatedMixin,
    template) {
    var ArrayList = com.ibm.jdojox.util.ArrayList;
    var JDojoX = com.ibm.jdojox.util.JDojoX;
    var Bindable = com.ibm.team.rtc.foundation.web.model.Bindable;
    var BindableList = com.ibm.team.rtc.foundation.web.model.BindableList;
    var Label = com.ibm.team.rtc.foundation.web.model.Label;
    var ListBindings = com.ibm.team.rtc.foundation.web.model.ListBindings;
    var Sprites = com.ibm.team.rtc.foundation.web.ui.util.Sprites;
    var ActionDropdown = com.ibm.team.rtc.foundation.web.ui.views.controller.ActionDropdown;
    var ArtifactMultiList = com.ibm.team.rtc.foundation.web.ui.views.controller.ArtifactMultiList;
    var WorkItemEndpoints = com.ibm.team.workitem.web.model.links.WorkItemEndpoints;
    var LinksDialogLauncher = com.ibm.team.workitem.web.ui.internal.view.editor.presentations.nonattribute.links.LinksDialogLauncher;

    return declare("com.siemens.bt.jazz.workitemeditor.rtcGitConnector.ui.widget.setNewWorkItemLinks",
        [_WidgetBase, _TemplatedMixin,],
    {
        templateString: template,
        mainDataStore: null,
        hasPresentation: false,
        enabledEndpoints: null,
        enabledEndpointsWithValues: null,
        workingCopy: null,

        constructor: function () {
            this.mainDataStore = MainDataStore.getInstance();
            this.workingCopy = this.mainDataStore.workItem.getWorkingCopy();

            // Create the list of link types to show
            this.enabledEndpoints = new ArrayList();
            this.enabledEndpoints.add(WorkItemEndpoints.PARENT_WORK_ITEM);

            // Create a list to keep track of what link types have links set
            // This is used for the view to dynamically show/hide when links
            // are added or removed
            this.enabledEndpointsWithValues = new BindableList();
        },

        // Only create the presentation once the show method is called
        show: function () {
            if (!this.hasPresentation) {
                this.hasPresentation = true;
                this.createLinksDropdown();
                this.createLinksList();
            }
        },

        // Create the dropdown for selecting work items to link. Will be
        // styled as a single button if there is only one item
        createLinksDropdown: function () {
            var self = this;
            var workItemReferences = this.workingCopy.getWorkItemReferences();

            // Create a list of endpoints to show in the dropdown
            var endpointList = new BindableList();
            endpointList.add(this.enabledEndpoints);

            // Set the first endpoint in the list to be the default
            var defaultEndpoint = new Bindable();
            defaultEndpoint.setValue(this.enabledEndpoints.at(0));

            // Create a div for placing the dropdown in
            var actionsMenuDiv = domConstruct.create("div", null, this.linksContainer);

            // Create the ActionDropdown and place it
            var actionsMenu = ActionDropdown.create({}, actionsMenuDiv);

            // Setup the ActionDropdown
            actionsMenu.renderer(lang.hitch(this, function (endpoint) {
                return new MenuItem({
                    label: this._getEndpointLabel(endpoint),
                    iconClass: Sprites.cssClassName(endpoint.getIcon())
                });
            })).values(endpointList).defaultValue(defaultEndpoint).bind();

            // Open the links chooser dialog when a menu item is clicked
            actionsMenu.valueChosen.addListener(lang.hitch(this, function (chosenDescriptor) {
                this._launchLinksDialog(self.workingCopy, workItemReferences, chosenDescriptor);
            }));

            // Hide the menu dropdown part when there is only a single item
            if (this.enabledEndpoints.size() === 1) {
                this._hideDropdown(actionsMenu._view);
            }
        },

        // Create the presentation of the set links. Can be used to remove the links
        createLinksList: function () {
            var self = this;
            var workItemReferences = this.workingCopy.getWorkItemReferences();

            // Create a div for placing the list view in
            var listViewDiv = domConstruct.create("div", null, this.linksContainer);

            // Create the ArtifactMultiList and place it
            var listView = ArtifactMultiList.create(listViewDiv);

            // Initialize empty BindableLists to bind with the enabledEndpointsWithValues later
            var headers= new BindableList();
            var readOnly= new BindableList();
            var typesMap= new BindableList();

            // Bind the headers to the endpoint display names and icons
            ListBindings.bindWithAdapter(this.enabledEndpointsWithValues, headers, function (endpoint) {
                return new Label(endpoint.getDisplayName()).iconUrl(endpoint.getIcon().toUri());
            });

            // Bind the readOnly attribute to reflect whether links from this endpoint can be deleted or not
            ListBindings.bindWithAdapter(this.enabledEndpointsWithValues, readOnly, function (endpoint) {
                return new Bindable(!endpoint.isUserDeleteable());
            });

            // Bind the typesMap to the work item references for each endpoint
            ListBindings.bindWithAdapter(this.enabledEndpointsWithValues, typesMap, function (endpoint) {
                var result = new BindableList();
                var references = workItemReferences.getReferences(endpoint);

                // Bind result to the work item references for this endpoint
                ListBindings.bind(references, result);

                // Listen for changes in the result list
                result.onListChanged().addListener(function (callbackArg) {
                    // Check if a reference has been removed from the result list
                    if (!JDojoX.isEqual(result, references) && callbackArg.type === 'remove') {
                        // Remove the reference from the work item references
                        workItemReferences.remove(endpoint, callbackArg.elements[0]);

                        // Remove the endpoint from the list of endpoints with values
                        // if the endpoint doesn't have any more references
                        if (!workItemReferences.hasReferences(endpoint)) {
                            self.enabledEndpointsWithValues.remove(endpoint);
                        }
                    }
                });

                return result;
            });

            // Setup the ArtifactMultiList
            listView.renderer(function (itemReference) {
                return new Label(itemReference.getComment()).iconUrl(itemReference.getIconUrl()).url(itemReference.getUrl());
            }).headers(headers).sections(typesMap).readOnly(readOnly).compact(new Bindable(false)).bind();
        },

        // Get the label for the specified endpoint
        _getEndpointLabel: function (endpoint) {
            return string.substitute(endpoint.isSingleValued() ? "Set ${0}" : "Add ${0}", [endpoint.getDisplayName()]);
        },

        // Launch a dialog for selecting links of a specific type for the specified work item
        _launchLinksDialog: function (workItem, workItemReferences, chosenDescriptor) {
            var self = this;

            LinksDialogLauncher.launchDialog(workItem, chosenDescriptor, function (endpoint) {
                // Get an array of all the endpoint references (passed as multiple arguments after endpoint)
                var references = Array.prototype.slice.call(arguments, 1);

                // Remove the existing reference if this is a single valued endpoint
                // and the work item already has a reference
                if (endpoint.isSingleValued() && workItemReferences.hasReferences(endpoint)) {
                    workItemReferences.remove(endpoint, workItemReferences.getReferences(endpoint).at(0));
                }

                // Add the new references to the endpoint
                workItemReferences.add.apply(workItemReferences, [endpoint].concat(references));

                // Add the endpoint to the custom list so that it will be shown in the view
                // Only add each endpoint to the list once. The individual references will be added to the endpoint
                if (!self.enabledEndpointsWithValues.contains(endpoint)) {
                    self.enabledEndpointsWithValues.add(endpoint);
                }
            });
        },

        // Hide the arrow drop down from the actions menu. This is useful when the menu only contains a single item
        _hideDropdown: function (actionsMenuView) {
            domStyle.set(actionsMenuView._dropdownElement, "float", "none");
            domStyle.set(actionsMenuView._dropdownElement, "border-right", "none");
            domStyle.set(actionsMenuView._dropdownArrow, "display", "none");
        }
    });
});

<|start_filename|>src/RtcGitConnectorModules.js<|end_filename|>
const pako = require('pako');
const base64js = require('base64-js');
const Buffer = require('buffer/').Buffer;

// Replace some characters in the input string (needed due to the strange implementation)
function base64UrlEncode(string) {
    string = string.replace(/\+/g, '-');
    string = string.replace(/\//g, '_');
    string = string.replace(/=/g, '.');
    return string;
}

// Replace some characters in the input string (needed due to the strange implementation)
function base64UrlDecode(string) {
    string = string.replace(/-/g, '+');
    string = string.replace(/_/g, '/');
    string = string.replace(/\./g, '=');
    return string;
}

// Export the functions needed for encoding and decoding data in git commit links
export function encoder () {
    // Creates an encoded string from a stringified json object
    this.encode = function encode(value) {
        const compressed = pako.gzip(Buffer.from(value));
        const encoded = base64js.fromByteArray(compressed);
        const urlEncoded = base64UrlEncode(encoded);
        return urlEncoded;
    };

    // Creates a stringified json object from the encoded string
    this.decode = function decode(value) {
        const urlDecoded = base64UrlDecode(value);
        const compressed = base64js.toByteArray(urlDecoded);
        const deflated = pako.ungzip(compressed);
        const buffer = Buffer.from(deflated);
        return buffer.toString();
    };
}

// Handlebars for the browser (templating)
export const Handlebars = require('handlebars/dist/handlebars.min.js');

// Helpers for using in Handlebars templates
export const JustHandlebarsHelpers = require('just-handlebars-helpers/dist/h.min.js');

// Turndown service for the browser (html to markdown)
export const TurndownService = require('turndown/lib/turndown.browser.umd');

// Clipboard.js for copying directly to the clipboard with wide browser support
export const ClipboardJS = require('clipboard/dist/clipboard.min');

// GitHub API client library
export const GitHubApi = require('@octokit/rest');

// GitLab API client library
export const GitLabApi = require('gitlab/dist/es5').default;

// Fontawesome fonts
export const FontAwesome = require('@fortawesome/fontawesome');
const FaCheck = require('@fortawesome/fontawesome-free-solid/faCheck');
const FaExclamationTriangle = require('@fortawesome/fontawesome-free-solid/faExclamationTriangle');
const FaLink = require('@fortawesome/fontawesome-free-solid/faLink');
const FaMinus = require('@fortawesome/fontawesome-free-solid/faMinus');
const FaPlus = require('@fortawesome/fontawesome-free-solid/faPlus');
const FaSpinner = require('@fortawesome/fontawesome-free-solid/faSpinner');
const FaTimes = require('@fortawesome/fontawesome-free-solid/faTimes');
const FaTrash = require('@fortawesome/fontawesome-free-solid/faTrash');

// Build version
export const buildVersion = '__BUILD_VERSION__';

// Adding the entire solid library doesn't seem to work in the frontend.
// So we have no other choice than adding them one by one.
FontAwesome.library.add(FaCheck);
FontAwesome.library.add(FaExclamationTriangle);
FontAwesome.library.add(FaLink);
FontAwesome.library.add(FaMinus);
FontAwesome.library.add(FaPlus);
FontAwesome.library.add(FaSpinner);
FontAwesome.library.add(FaTimes);
FontAwesome.library.add(FaTrash);