2017-05-04 04:09:21 -04:00
|
|
|
/* eslint-disable no-new */
|
2020-04-21 11:21:10 -04:00
|
|
|
import { debounce } from 'lodash';
|
2018-01-26 05:27:50 -05:00
|
|
|
import axios from './lib/utils/axios_utils';
|
2020-08-20 05:09:55 -04:00
|
|
|
import { deprecatedCreateFlash as Flash } from './flash';
|
2017-05-04 04:09:21 -04:00
|
|
|
import DropLab from './droplab/drop_lab';
|
|
|
|
import ISetter from './droplab/plugins/input_setter';
|
2017-11-25 06:33:05 -05:00
|
|
|
import { __, sprintf } from './locale';
|
2019-07-05 06:14:56 -04:00
|
|
|
import {
|
|
|
|
init as initConfidentialMergeRequest,
|
|
|
|
isConfidentialIssue,
|
|
|
|
canCreateConfidentialMergeRequest,
|
|
|
|
} from './confidential_merge_request';
|
|
|
|
import confidentialMergeRequestState from './confidential_merge_request/state';
|
2017-05-04 04:09:21 -04:00
|
|
|
|
|
|
|
// Todo: Remove this when fixing issue in input_setter plugin
|
2020-05-07 17:09:26 -04:00
|
|
|
const InputSetter = { ...ISetter };
|
2017-05-04 04:09:21 -04:00
|
|
|
|
|
|
|
const CREATE_MERGE_REQUEST = 'create-mr';
|
|
|
|
const CREATE_BRANCH = 'create-branch';
|
|
|
|
|
2019-07-05 06:14:56 -04:00
|
|
|
function createEndpoint(projectPath, endpoint) {
|
|
|
|
if (canCreateConfidentialMergeRequest()) {
|
|
|
|
return endpoint.replace(
|
|
|
|
projectPath,
|
|
|
|
confidentialMergeRequestState.selectedProject.pathWithNamespace,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return endpoint;
|
|
|
|
}
|
|
|
|
|
2017-05-04 04:09:21 -04:00
|
|
|
export default class CreateMergeRequestDropdown {
|
|
|
|
constructor(wrapperEl) {
|
|
|
|
this.wrapperEl = wrapperEl;
|
2017-11-25 06:33:05 -05:00
|
|
|
this.availableButton = this.wrapperEl.querySelector('.available');
|
|
|
|
this.branchInput = this.wrapperEl.querySelector('.js-branch-name');
|
|
|
|
this.branchMessage = this.wrapperEl.querySelector('.js-branch-message');
|
2017-05-04 04:09:21 -04:00
|
|
|
this.createMergeRequestButton = this.wrapperEl.querySelector('.js-create-merge-request');
|
2017-11-25 06:33:05 -05:00
|
|
|
this.createTargetButton = this.wrapperEl.querySelector('.js-create-target');
|
2017-05-04 04:09:21 -04:00
|
|
|
this.dropdownList = this.wrapperEl.querySelector('.dropdown-menu');
|
2017-11-25 06:33:05 -05:00
|
|
|
this.dropdownToggle = this.wrapperEl.querySelector('.js-dropdown-toggle');
|
|
|
|
this.refInput = this.wrapperEl.querySelector('.js-ref');
|
|
|
|
this.refMessage = this.wrapperEl.querySelector('.js-ref-message');
|
2017-05-04 04:09:21 -04:00
|
|
|
this.unavailableButton = this.wrapperEl.querySelector('.unavailable');
|
2020-03-09 02:09:55 -04:00
|
|
|
this.unavailableButtonSpinner = this.unavailableButton.querySelector('.spinner');
|
2017-05-04 04:09:21 -04:00
|
|
|
this.unavailableButtonText = this.unavailableButton.querySelector('.text');
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
this.branchCreated = false;
|
|
|
|
this.branchIsValid = true;
|
2017-05-04 04:09:21 -04:00
|
|
|
this.canCreatePath = this.wrapperEl.dataset.canCreatePath;
|
2017-11-25 06:33:05 -05:00
|
|
|
this.createBranchPath = this.wrapperEl.dataset.createBranchPath;
|
2017-05-04 04:09:21 -04:00
|
|
|
this.createMrPath = this.wrapperEl.dataset.createMrPath;
|
|
|
|
this.droplabInitialized = false;
|
2017-11-25 06:33:05 -05:00
|
|
|
this.isCreatingBranch = false;
|
2017-05-04 04:09:21 -04:00
|
|
|
this.isCreatingMergeRequest = false;
|
2017-11-25 06:33:05 -05:00
|
|
|
this.isGettingRef = false;
|
2017-05-04 04:09:21 -04:00
|
|
|
this.mergeRequestCreated = false;
|
2020-04-21 11:21:10 -04:00
|
|
|
this.refDebounce = debounce((value, target) => this.getRef(value, target), 500);
|
2017-11-25 06:33:05 -05:00
|
|
|
this.refIsValid = true;
|
|
|
|
this.refsPath = this.wrapperEl.dataset.refsPath;
|
|
|
|
this.suggestedRef = this.refInput.value;
|
2019-07-05 06:14:56 -04:00
|
|
|
this.projectPath = this.wrapperEl.dataset.projectPath;
|
|
|
|
this.projectId = this.wrapperEl.dataset.projectId;
|
2017-05-04 04:09:21 -04:00
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
// These regexps are used to replace
|
|
|
|
// a backend generated new branch name and its source (ref)
|
|
|
|
// with user's inputs.
|
|
|
|
this.regexps = {
|
|
|
|
branch: {
|
|
|
|
createBranchPath: new RegExp('(branch_name=)(.+?)(?=&issue)'),
|
|
|
|
createMrPath: new RegExp('(branch_name=)(.+?)(?=&ref)'),
|
|
|
|
},
|
|
|
|
ref: {
|
|
|
|
createBranchPath: new RegExp('(ref=)(.+?)$'),
|
|
|
|
createMrPath: new RegExp('(ref=)(.+?)$'),
|
|
|
|
},
|
|
|
|
};
|
2017-05-04 04:09:21 -04:00
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
this.init();
|
2019-07-05 06:14:56 -04:00
|
|
|
|
|
|
|
if (isConfidentialIssue()) {
|
|
|
|
this.createMergeRequestButton.setAttribute(
|
|
|
|
'data-dropdown-trigger',
|
|
|
|
'#create-merge-request-dropdown',
|
|
|
|
);
|
|
|
|
initConfidentialMergeRequest();
|
|
|
|
}
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
available() {
|
2018-04-19 20:16:13 -04:00
|
|
|
this.availableButton.classList.remove('hidden');
|
|
|
|
this.unavailableButton.classList.add('hidden');
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
bindEvents() {
|
2018-06-13 18:48:59 -04:00
|
|
|
this.createMergeRequestButton.addEventListener(
|
|
|
|
'click',
|
|
|
|
this.onClickCreateMergeRequestButton.bind(this),
|
|
|
|
);
|
|
|
|
this.createTargetButton.addEventListener(
|
|
|
|
'click',
|
|
|
|
this.onClickCreateMergeRequestButton.bind(this),
|
|
|
|
);
|
2017-11-25 06:33:05 -05:00
|
|
|
this.branchInput.addEventListener('keyup', this.onChangeInput.bind(this));
|
|
|
|
this.dropdownToggle.addEventListener('click', this.onClickSetFocusOnBranchNameInput.bind(this));
|
|
|
|
this.refInput.addEventListener('keyup', this.onChangeInput.bind(this));
|
|
|
|
this.refInput.addEventListener('keydown', CreateMergeRequestDropdown.processTab.bind(this));
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
checkAbilityToCreateBranch() {
|
2018-01-26 05:27:50 -05:00
|
|
|
this.setUnavailableButtonState();
|
|
|
|
|
2018-06-13 18:48:59 -04:00
|
|
|
axios
|
|
|
|
.get(this.canCreatePath)
|
2018-01-26 05:27:50 -05:00
|
|
|
.then(({ data }) => {
|
|
|
|
this.setUnavailableButtonState(false);
|
|
|
|
|
|
|
|
if (data.can_create_branch) {
|
|
|
|
this.available();
|
|
|
|
this.enable();
|
2018-04-05 11:17:02 -04:00
|
|
|
this.updateBranchName(data.suggested_branch_name);
|
2018-01-26 05:27:50 -05:00
|
|
|
|
|
|
|
if (!this.droplabInitialized) {
|
|
|
|
this.droplabInitialized = true;
|
|
|
|
this.initDroplab();
|
|
|
|
this.bindEvents();
|
|
|
|
}
|
2018-04-05 11:17:02 -04:00
|
|
|
} else {
|
2018-01-26 05:27:50 -05:00
|
|
|
this.hide();
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
2018-01-26 05:27:50 -05:00
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
this.unavailable();
|
|
|
|
this.disable();
|
2018-04-05 11:17:02 -04:00
|
|
|
Flash(__('Failed to check related branches.'));
|
2018-01-26 05:27:50 -05:00
|
|
|
});
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
createBranch() {
|
2018-01-26 05:27:50 -05:00
|
|
|
this.isCreatingBranch = true;
|
|
|
|
|
2018-06-13 18:48:59 -04:00
|
|
|
return axios
|
2019-07-05 06:14:56 -04:00
|
|
|
.post(createEndpoint(this.projectPath, this.createBranchPath), {
|
|
|
|
confidential_issue_project_id: canCreateConfidentialMergeRequest() ? this.projectId : null,
|
|
|
|
})
|
2018-01-26 05:27:50 -05:00
|
|
|
.then(({ data }) => {
|
|
|
|
this.branchCreated = true;
|
|
|
|
window.location.href = data.url;
|
|
|
|
})
|
2019-05-21 06:40:24 -04:00
|
|
|
.catch(() => Flash(__('Failed to create a branch for this issue. Please try again.')));
|
2017-11-25 06:33:05 -05:00
|
|
|
}
|
2017-05-04 04:09:21 -04:00
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
createMergeRequest() {
|
2018-01-26 05:27:50 -05:00
|
|
|
this.isCreatingMergeRequest = true;
|
|
|
|
|
2018-06-13 18:48:59 -04:00
|
|
|
return axios
|
2019-07-05 06:14:56 -04:00
|
|
|
.post(this.createMrPath, {
|
|
|
|
target_project_id: canCreateConfidentialMergeRequest()
|
|
|
|
? confidentialMergeRequestState.selectedProject.id
|
|
|
|
: null,
|
|
|
|
})
|
2018-01-26 05:27:50 -05:00
|
|
|
.then(({ data }) => {
|
|
|
|
this.mergeRequestCreated = true;
|
|
|
|
window.location.href = data.url;
|
|
|
|
})
|
2019-05-21 06:40:24 -04:00
|
|
|
.catch(() => Flash(__('Failed to create Merge Request. Please try again.')));
|
2017-11-25 06:33:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
disable() {
|
|
|
|
this.disableCreateAction();
|
|
|
|
}
|
|
|
|
|
|
|
|
disableCreateAction() {
|
|
|
|
this.createMergeRequestButton.classList.add('disabled');
|
|
|
|
this.createMergeRequestButton.setAttribute('disabled', 'disabled');
|
|
|
|
|
|
|
|
this.createTargetButton.classList.add('disabled');
|
|
|
|
this.createTargetButton.setAttribute('disabled', 'disabled');
|
|
|
|
}
|
|
|
|
|
|
|
|
enable() {
|
2019-07-16 06:02:37 -04:00
|
|
|
if (isConfidentialIssue() && !canCreateConfidentialMergeRequest()) return;
|
2019-07-05 06:14:56 -04:00
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
this.createMergeRequestButton.classList.remove('disabled');
|
|
|
|
this.createMergeRequestButton.removeAttribute('disabled');
|
|
|
|
|
|
|
|
this.createTargetButton.classList.remove('disabled');
|
|
|
|
this.createTargetButton.removeAttribute('disabled');
|
|
|
|
}
|
|
|
|
|
|
|
|
static findByValue(objects, ref, returnFirstMatch = false) {
|
|
|
|
if (!objects || !objects.length) return false;
|
|
|
|
if (objects.indexOf(ref) > -1) return ref;
|
2020-12-23 16:10:24 -05:00
|
|
|
if (returnFirstMatch) return objects.find((item) => new RegExp(`^${ref}`).test(item));
|
2017-11-25 06:33:05 -05:00
|
|
|
|
|
|
|
return false;
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
getDroplabConfig() {
|
|
|
|
return {
|
2017-11-25 06:33:05 -05:00
|
|
|
addActiveClassToDropdownButton: true,
|
|
|
|
InputSetter: [
|
|
|
|
{
|
|
|
|
input: this.createMergeRequestButton,
|
|
|
|
valueAttribute: 'data-value',
|
|
|
|
inputAttribute: 'data-action',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: this.createMergeRequestButton,
|
|
|
|
valueAttribute: 'data-text',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: this.createTargetButton,
|
|
|
|
valueAttribute: 'data-value',
|
|
|
|
inputAttribute: 'data-action',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: this.createTargetButton,
|
|
|
|
valueAttribute: 'data-text',
|
|
|
|
},
|
|
|
|
],
|
2018-02-01 09:19:27 -05:00
|
|
|
hideOnClick: false,
|
2017-05-04 04:09:21 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
static getInputSelectedText(input) {
|
|
|
|
const start = input.selectionStart;
|
|
|
|
const end = input.selectionEnd;
|
|
|
|
|
|
|
|
return input.value.substr(start, end - start);
|
|
|
|
}
|
|
|
|
|
|
|
|
getRef(ref, target = 'all') {
|
|
|
|
if (!ref) return false;
|
|
|
|
|
2018-06-13 18:48:59 -04:00
|
|
|
return axios
|
2019-07-05 06:14:56 -04:00
|
|
|
.get(`${createEndpoint(this.projectPath, this.refsPath)}${encodeURIComponent(ref)}`)
|
2018-01-26 05:27:50 -05:00
|
|
|
.then(({ data }) => {
|
|
|
|
const branches = data[Object.keys(data)[0]];
|
|
|
|
const tags = data[Object.keys(data)[1]];
|
|
|
|
let result;
|
|
|
|
|
|
|
|
if (target === 'branch') {
|
|
|
|
result = CreateMergeRequestDropdown.findByValue(branches, ref);
|
|
|
|
} else {
|
2018-06-13 18:48:59 -04:00
|
|
|
result =
|
|
|
|
CreateMergeRequestDropdown.findByValue(branches, ref, true) ||
|
2018-01-26 05:27:50 -05:00
|
|
|
CreateMergeRequestDropdown.findByValue(tags, ref, true);
|
|
|
|
this.suggestedRef = result;
|
|
|
|
}
|
2017-11-25 06:33:05 -05:00
|
|
|
|
2018-01-26 05:27:50 -05:00
|
|
|
this.isGettingRef = false;
|
2017-11-25 06:33:05 -05:00
|
|
|
|
2018-01-26 05:27:50 -05:00
|
|
|
return this.updateInputState(target, ref, result);
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
this.unavailable();
|
|
|
|
this.disable();
|
2019-05-21 06:40:24 -04:00
|
|
|
new Flash(__('Failed to get ref.'));
|
2017-11-25 06:33:05 -05:00
|
|
|
|
2018-01-26 05:27:50 -05:00
|
|
|
this.isGettingRef = false;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
});
|
2017-11-25 06:33:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
getTargetData(target) {
|
|
|
|
return {
|
|
|
|
input: this[`${target}Input`],
|
|
|
|
message: this[`${target}Message`],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
hide() {
|
2018-04-19 20:16:13 -04:00
|
|
|
this.wrapperEl.classList.add('hidden');
|
2017-11-25 06:33:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
|
|
this.checkAbilityToCreateBranch();
|
|
|
|
}
|
|
|
|
|
|
|
|
initDroplab() {
|
|
|
|
this.droplab = new DropLab();
|
|
|
|
|
|
|
|
this.droplab.init(
|
|
|
|
this.dropdownToggle,
|
|
|
|
this.dropdownList,
|
|
|
|
[InputSetter],
|
|
|
|
this.getDroplabConfig(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
inputsAreValid() {
|
|
|
|
return this.branchIsValid && this.refIsValid;
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
isBusy() {
|
2018-06-13 18:48:59 -04:00
|
|
|
return (
|
|
|
|
this.isCreatingMergeRequest ||
|
2017-05-04 04:09:21 -04:00
|
|
|
this.mergeRequestCreated ||
|
|
|
|
this.isCreatingBranch ||
|
2017-11-25 06:33:05 -05:00
|
|
|
this.branchCreated ||
|
2018-06-13 18:48:59 -04:00
|
|
|
this.isGettingRef
|
|
|
|
);
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
onChangeInput(event) {
|
2019-11-25 22:06:24 -05:00
|
|
|
this.disable();
|
2017-11-25 06:33:05 -05:00
|
|
|
let target;
|
|
|
|
let value;
|
|
|
|
|
2018-01-04 17:15:09 -05:00
|
|
|
if (event.target === this.branchInput) {
|
2017-11-25 06:33:05 -05:00
|
|
|
target = 'branch';
|
2018-06-16 17:50:13 -04:00
|
|
|
({ value } = this.branchInput);
|
2018-01-04 17:15:09 -05:00
|
|
|
} else if (event.target === this.refInput) {
|
2017-11-25 06:33:05 -05:00
|
|
|
target = 'ref';
|
2018-06-13 18:48:59 -04:00
|
|
|
value =
|
|
|
|
event.target.value.slice(0, event.target.selectionStart) +
|
2018-01-04 17:15:09 -05:00
|
|
|
event.target.value.slice(event.target.selectionEnd);
|
2017-11-25 06:33:05 -05:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.isGettingRef) return false;
|
|
|
|
|
|
|
|
// `ENTER` key submits the data.
|
|
|
|
if (event.keyCode === 13 && this.inputsAreValid()) {
|
|
|
|
event.preventDefault();
|
|
|
|
return this.createMergeRequestButton.click();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the input is empty, use the original value generated by the backend.
|
|
|
|
if (!value) {
|
|
|
|
this.createBranchPath = this.wrapperEl.dataset.createBranchPath;
|
|
|
|
this.createMrPath = this.wrapperEl.dataset.createMrPath;
|
|
|
|
|
|
|
|
if (target === 'branch') {
|
|
|
|
this.branchIsValid = true;
|
|
|
|
} else {
|
|
|
|
this.refIsValid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.enable();
|
|
|
|
this.showAvailableMessage(target);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.showCheckingMessage(target);
|
|
|
|
this.refDebounce(value, target);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
onClickCreateMergeRequestButton(event) {
|
2017-05-04 04:09:21 -04:00
|
|
|
let xhr = null;
|
2017-11-25 06:33:05 -05:00
|
|
|
event.preventDefault();
|
2017-05-04 04:09:21 -04:00
|
|
|
|
2019-07-05 06:14:56 -04:00
|
|
|
if (isConfidentialIssue() && !event.target.classList.contains('js-create-target')) {
|
2020-12-23 16:10:24 -05:00
|
|
|
this.droplab.hooks.forEach((hook) => hook.list.toggle());
|
2019-07-05 06:14:56 -04:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-04 04:09:21 -04:00
|
|
|
if (this.isBusy()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
if (event.target.dataset.action === CREATE_MERGE_REQUEST) {
|
2017-05-04 04:09:21 -04:00
|
|
|
xhr = this.createMergeRequest();
|
2017-11-25 06:33:05 -05:00
|
|
|
} else if (event.target.dataset.action === CREATE_BRANCH) {
|
2017-05-04 04:09:21 -04:00
|
|
|
xhr = this.createBranch();
|
|
|
|
}
|
|
|
|
|
2018-01-26 05:27:50 -05:00
|
|
|
xhr.catch(() => {
|
2017-05-04 04:09:21 -04:00
|
|
|
this.isCreatingMergeRequest = false;
|
|
|
|
this.isCreatingBranch = false;
|
|
|
|
|
2018-01-26 05:27:50 -05:00
|
|
|
this.enable();
|
|
|
|
});
|
2017-05-04 04:09:21 -04:00
|
|
|
|
|
|
|
this.disable();
|
|
|
|
}
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
onClickSetFocusOnBranchNameInput() {
|
|
|
|
this.branchInput.focus();
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
// `TAB` autocompletes the source.
|
|
|
|
static processTab(event) {
|
|
|
|
if (event.keyCode !== 9 || this.isGettingRef) return;
|
|
|
|
|
|
|
|
const selectedText = CreateMergeRequestDropdown.getInputSelectedText(this.refInput);
|
|
|
|
|
|
|
|
// if nothing selected, we don't need to autocomplete anything. Do the default TAB action.
|
|
|
|
// If a user manually selected text, don't autocomplete anything. Do the default TAB action.
|
|
|
|
if (!selectedText || this.refInput.dataset.value === this.suggestedRef) return;
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
window.getSelection().removeAllRanges();
|
|
|
|
}
|
|
|
|
|
|
|
|
removeMessage(target) {
|
|
|
|
const { input, message } = this.getTargetData(target);
|
|
|
|
const inputClasses = ['gl-field-error-outline', 'gl-field-success-outline'];
|
2018-06-19 17:22:31 -04:00
|
|
|
const messageClasses = ['text-muted', 'text-danger', 'text-success'];
|
2017-11-25 06:33:05 -05:00
|
|
|
|
2020-12-23 16:10:24 -05:00
|
|
|
inputClasses.forEach((cssClass) => input.classList.remove(cssClass));
|
|
|
|
messageClasses.forEach((cssClass) => message.classList.remove(cssClass));
|
2017-11-25 06:33:05 -05:00
|
|
|
message.style.display = 'none';
|
|
|
|
}
|
|
|
|
|
|
|
|
setUnavailableButtonState(isLoading = true) {
|
|
|
|
if (isLoading) {
|
2020-03-09 02:09:55 -04:00
|
|
|
this.unavailableButtonSpinner.classList.remove('hide');
|
2017-11-25 06:33:05 -05:00
|
|
|
this.unavailableButtonText.textContent = __('Checking branch availability...');
|
|
|
|
} else {
|
2020-03-09 02:09:55 -04:00
|
|
|
this.unavailableButtonSpinner.classList.add('hide');
|
2017-11-25 06:33:05 -05:00
|
|
|
this.unavailableButtonText.textContent = __('New branch unavailable');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
showAvailableMessage(target) {
|
|
|
|
const { input, message } = this.getTargetData(target);
|
|
|
|
const text = target === 'branch' ? __('Branch name') : __('Source');
|
|
|
|
|
|
|
|
this.removeMessage(target);
|
|
|
|
input.classList.add('gl-field-success-outline');
|
2018-06-19 17:22:31 -04:00
|
|
|
message.classList.add('text-success');
|
2017-11-25 06:33:05 -05:00
|
|
|
message.textContent = sprintf(__('%{text} is available'), { text });
|
|
|
|
message.style.display = 'inline-block';
|
|
|
|
}
|
|
|
|
|
|
|
|
showCheckingMessage(target) {
|
|
|
|
const { message } = this.getTargetData(target);
|
|
|
|
const text = target === 'branch' ? __('branch name') : __('source');
|
|
|
|
|
|
|
|
this.removeMessage(target);
|
2018-06-19 17:22:31 -04:00
|
|
|
message.classList.add('text-muted');
|
2017-11-25 06:33:05 -05:00
|
|
|
message.textContent = sprintf(__('Checking %{text} availability…'), { text });
|
|
|
|
message.style.display = 'inline-block';
|
|
|
|
}
|
|
|
|
|
|
|
|
showNotAvailableMessage(target) {
|
|
|
|
const { input, message } = this.getTargetData(target);
|
2018-06-13 18:48:59 -04:00
|
|
|
const text =
|
|
|
|
target === 'branch' ? __('Branch is already taken') : __('Source is not available');
|
2017-11-25 06:33:05 -05:00
|
|
|
|
|
|
|
this.removeMessage(target);
|
|
|
|
input.classList.add('gl-field-error-outline');
|
2018-06-19 17:22:31 -04:00
|
|
|
message.classList.add('text-danger');
|
2017-11-25 06:33:05 -05:00
|
|
|
message.textContent = text;
|
|
|
|
message.style.display = 'inline-block';
|
|
|
|
}
|
|
|
|
|
|
|
|
unavailable() {
|
2018-04-19 20:16:13 -04:00
|
|
|
this.availableButton.classList.add('hidden');
|
|
|
|
this.unavailableButton.classList.remove('hidden');
|
2017-11-25 06:33:05 -05:00
|
|
|
}
|
|
|
|
|
2018-04-05 11:17:02 -04:00
|
|
|
updateBranchName(suggestedBranchName) {
|
|
|
|
this.branchInput.value = suggestedBranchName;
|
|
|
|
this.updateCreatePaths('branch', suggestedBranchName);
|
|
|
|
}
|
|
|
|
|
2017-11-25 06:33:05 -05:00
|
|
|
updateInputState(target, ref, result) {
|
|
|
|
// target - 'branch' or 'ref' - which the input field we are searching a ref for.
|
|
|
|
// ref - string - what a user typed.
|
|
|
|
// result - string - what has been found on backend.
|
|
|
|
|
|
|
|
// If a found branch equals exact the same text a user typed,
|
|
|
|
// that means a new branch cannot be created as it already exists.
|
|
|
|
if (ref === result) {
|
|
|
|
if (target === 'branch') {
|
|
|
|
this.branchIsValid = false;
|
|
|
|
this.showNotAvailableMessage('branch');
|
|
|
|
} else {
|
|
|
|
this.refIsValid = true;
|
|
|
|
this.refInput.dataset.value = ref;
|
|
|
|
this.showAvailableMessage('ref');
|
2018-04-05 11:17:02 -04:00
|
|
|
this.updateCreatePaths(target, ref);
|
2017-11-25 06:33:05 -05:00
|
|
|
}
|
|
|
|
} else if (target === 'branch') {
|
|
|
|
this.branchIsValid = true;
|
|
|
|
this.showAvailableMessage('branch');
|
2018-04-05 11:17:02 -04:00
|
|
|
this.updateCreatePaths(target, ref);
|
2017-11-25 06:33:05 -05:00
|
|
|
} else {
|
|
|
|
this.refIsValid = false;
|
|
|
|
this.refInput.dataset.value = ref;
|
|
|
|
this.disableCreateAction();
|
|
|
|
this.showNotAvailableMessage('ref');
|
|
|
|
|
|
|
|
// Show ref hint.
|
|
|
|
if (result) {
|
|
|
|
this.refInput.value = result;
|
|
|
|
this.refInput.setSelectionRange(ref.length, result.length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.inputsAreValid()) {
|
|
|
|
this.enable();
|
|
|
|
} else {
|
|
|
|
this.disableCreateAction();
|
|
|
|
}
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|
2018-04-05 11:17:02 -04:00
|
|
|
|
|
|
|
// target - 'branch' or 'ref'
|
|
|
|
// ref - string - the new value to use as branch or ref
|
|
|
|
updateCreatePaths(target, ref) {
|
2018-06-13 18:48:59 -04:00
|
|
|
const pathReplacement = `$1${encodeURIComponent(ref)}`;
|
2018-04-05 11:17:02 -04:00
|
|
|
|
2018-06-13 18:48:59 -04:00
|
|
|
this.createBranchPath = this.createBranchPath.replace(
|
|
|
|
this.regexps[target].createBranchPath,
|
|
|
|
pathReplacement,
|
|
|
|
);
|
|
|
|
this.createMrPath = this.createMrPath.replace(
|
|
|
|
this.regexps[target].createMrPath,
|
|
|
|
pathReplacement,
|
|
|
|
);
|
2018-04-05 11:17:02 -04:00
|
|
|
}
|
2017-05-04 04:09:21 -04:00
|
|
|
}
|