diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-20 12:16:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-20 12:16:11 +0300 |
commit | edaa33dee2ff2f7ea3fac488d41558eb5f86d68c (patch) | |
tree | 11f143effbfeba52329fb7afbd05e6e2a3790241 /app/assets/javascripts/projects | |
parent | d8a5691316400a0f7ec4f83832698f1988eb27c1 (diff) |
Add latest changes from gitlab-org/gitlab@14-7-stable-eev14.7.0-rc42
Diffstat (limited to 'app/assets/javascripts/projects')
-rw-r--r-- | app/assets/javascripts/projects/project_find_file.js | 183 | ||||
-rw-r--r-- | app/assets/javascripts/projects/project_import.js | 7 | ||||
-rw-r--r-- | app/assets/javascripts/projects/project_visibility.js | 71 | ||||
-rw-r--r-- | app/assets/javascripts/projects/star.js | 38 |
4 files changed, 299 insertions, 0 deletions
diff --git a/app/assets/javascripts/projects/project_find_file.js b/app/assets/javascripts/projects/project_find_file.js new file mode 100644 index 00000000000..d295c06928f --- /dev/null +++ b/app/assets/javascripts/projects/project_find_file.js @@ -0,0 +1,183 @@ +/* eslint-disable func-names, consistent-return, no-return-assign */ + +import fuzzaldrinPlus from 'fuzzaldrin-plus'; +import $ from 'jquery'; +import createFlash from '~/flash'; +import { sanitize } from '~/lib/dompurify'; +import axios from '~/lib/utils/axios_utils'; +import { spriteIcon } from '~/lib/utils/common_utils'; +import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility'; +import { __ } from '~/locale'; + +// highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> ) +const highlighter = function (element, text, matches) { + let j = 0; + let len = 0; + let lastIndex = 0; + let matchedChars = []; + let matchIndex = matches[j]; + let unmatched = text.substring(lastIndex, matchIndex); + for (j = 0, len = matches.length; j < len; j += 1) { + matchIndex = matches[j]; + unmatched = text.substring(lastIndex, matchIndex); + if (unmatched) { + if (matchedChars.length) { + element.append(matchedChars.join('').bold()); + } + matchedChars = []; + element.append(document.createTextNode(unmatched)); + } + matchedChars.push(text[matchIndex]); + lastIndex = matchIndex + 1; + } + if (matchedChars.length) { + element.append(matchedChars.join('').bold()); + } + return element.append(document.createTextNode(text.substring(lastIndex))); +}; + +export default class ProjectFindFile { + constructor(element1, options) { + this.element = element1; + this.options = options; + this.goToBlob = this.goToBlob.bind(this); + this.goToTree = this.goToTree.bind(this); + this.selectRowDown = this.selectRowDown.bind(this); + this.selectRowUp = this.selectRowUp.bind(this); + this.filePaths = {}; + this.inputElement = this.element.find('.file-finder-input'); + // init event + this.initEvent(); + // focus text input box + this.inputElement.focus(); + // load file list + this.load(this.options.url); + } + + initEvent() { + // eslint-disable-next-line @gitlab/no-global-event-off + this.inputElement.off('keyup'); + this.inputElement.on('keyup', (event) => { + const target = $(event.target); + const value = target.val(); + const ref = target.data('oldValue'); + const oldValue = ref != null ? ref : ''; + if (value !== oldValue) { + target.data('oldValue', value); + this.findFile(); + return this.element.find('tr.tree-item').eq(0).addClass('selected').focus(); + } + }); + } + + findFile() { + const searchText = sanitize(this.inputElement.val()); + const result = + searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths; + return this.renderList(result, searchText); + // find file + } + + // files paths load + load(url) { + axios + .get(url) + .then(({ data }) => { + this.element.find('.loading').hide(); + this.filePaths = data; + this.findFile(); + this.element.find('.files-slider tr.tree-item').eq(0).addClass('selected').focus(); + }) + .catch(() => + createFlash({ + message: __('An error occurred while loading filenames'), + }), + ); + } + + // render result + renderList(filePaths, searchText) { + let i = 0; + let len = 0; + let matches = []; + const results = []; + this.element.find('.tree-table > tbody').empty(); + for (i = 0, len = filePaths.length; i < len; i += 1) { + const filePath = filePaths[i]; + if (i === 20) { + break; + } + if (searchText) { + matches = fuzzaldrinPlus.match(filePath, searchText); + } + const blobItemUrl = joinPaths(this.options.blobUrlTemplate, escapeFileUrl(filePath)); + const html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl); + results.push(this.element.find('.tree-table > tbody').append(html)); + } + + this.element.find('.empty-state').toggleClass('hidden', Boolean(results.length)); + + return results; + } + + // make tbody row html + static makeHtml(filePath, matches, blobItemUrl) { + const $tr = $( + `<tr class='tree-item'><td class='tree-item-file-name link-container'><a>${spriteIcon( + 'doc-text', + 's16 vertical-align-middle gl-mr-1', + )}<span class='str-truncated'></span></a></td></tr>`, + ); + if (matches) { + $tr + .find('a') + .replaceWith(highlighter($tr.find('a'), filePath, matches).attr('href', blobItemUrl)); + } else { + $tr.find('a').attr('href', blobItemUrl); + $tr.find('.str-truncated').text(filePath); + } + return $tr; + } + + selectRow(type) { + const rows = this.element.find('.files-slider tr.tree-item'); + let selectedRow = this.element.find('.files-slider tr.tree-item.selected'); + let next = selectedRow.prev(); + if (rows && rows.length > 0) { + if (selectedRow && selectedRow.length > 0) { + if (type === 'UP') { + next = selectedRow.prev(); + } else if (type === 'DOWN') { + next = selectedRow.next(); + } + if (next.length > 0) { + selectedRow.removeClass('selected'); + selectedRow = next; + } + } else { + selectedRow = rows.eq(0); + } + return selectedRow.addClass('selected').focus(); + } + } + + selectRowUp() { + return this.selectRow('UP'); + } + + selectRowDown() { + return this.selectRow('DOWN'); + } + + goToTree() { + return (window.location.href = this.options.treeUrl); + } + + goToBlob() { + const $link = this.element.find('.tree-item.selected .tree-item-file-name a'); + + if ($link.length) { + $link.get(0).click(); + } + } +} diff --git a/app/assets/javascripts/projects/project_import.js b/app/assets/javascripts/projects/project_import.js new file mode 100644 index 00000000000..27a218f1f52 --- /dev/null +++ b/app/assets/javascripts/projects/project_import.js @@ -0,0 +1,7 @@ +import { visitUrl } from '~/lib/utils/url_utility'; + +export default function projectImport() { + setTimeout(() => { + visitUrl(window.location.href); + }, 5000); +} diff --git a/app/assets/javascripts/projects/project_visibility.js b/app/assets/javascripts/projects/project_visibility.js new file mode 100644 index 00000000000..c962554c9f4 --- /dev/null +++ b/app/assets/javascripts/projects/project_visibility.js @@ -0,0 +1,71 @@ +import $ from 'jquery'; +import { escape } from 'lodash'; +import { __, sprintf } from '~/locale'; +import eventHub from '~/projects/new/event_hub'; + +// Values are from lib/gitlab/visibility_level.rb +const visibilityLevel = { + private: 0, + internal: 10, + public: 20, +}; + +function setVisibilityOptions({ name, visibility, showPath, editPath }) { + document.querySelectorAll('.visibility-level-setting .form-check').forEach((option) => { + // Don't change anything if the option is restricted by admin + if (option.classList.contains('restricted')) { + return; + } + + const optionInput = option.querySelector('input[type=radio]'); + const optionValue = optionInput ? parseInt(optionInput.value, 10) : 0; + + if (visibilityLevel[visibility] < optionValue) { + option.classList.add('disabled'); + optionInput.disabled = true; + const reason = option.querySelector('.option-disabled-reason'); + if (reason) { + const optionTitle = option.querySelector('.option-title'); + const optionName = optionTitle ? optionTitle.innerText.toLowerCase() : ''; + reason.innerHTML = sprintf( + __( + 'This project cannot be %{visibilityLevel} because the visibility of %{openShowLink}%{name}%{closeShowLink} is %{visibility}. To make this project %{visibilityLevel}, you must first %{openEditLink}change the visibility%{closeEditLink} of the parent group.', + ), + { + visibilityLevel: optionName, + name: escape(name), + visibility, + openShowLink: `<a href="${showPath}">`, + closeShowLink: '</a>', + openEditLink: `<a href="${editPath}">`, + closeEditLink: '</a>', + }, + false, + ); + } + } else { + option.classList.remove('disabled'); + optionInput.disabled = false; + } + }); +} + +function handleSelect2DropdownChange(namespaceSelector) { + if (!namespaceSelector || !('selectedIndex' in namespaceSelector)) { + return; + } + const selectedNamespace = namespaceSelector.options[namespaceSelector.selectedIndex]; + setVisibilityOptions(selectedNamespace.dataset); +} + +export default function initProjectVisibilitySelector() { + eventHub.$on('update-visibility', setVisibilityOptions); + + const namespaceSelector = document.querySelector('select.js-select-namespace'); + if (namespaceSelector) { + $('.select2.js-select-namespace').on('change', () => + handleSelect2DropdownChange(namespaceSelector), + ); + handleSelect2DropdownChange(namespaceSelector); + } +} diff --git a/app/assets/javascripts/projects/star.js b/app/assets/javascripts/projects/star.js new file mode 100644 index 00000000000..578e22ca25d --- /dev/null +++ b/app/assets/javascripts/projects/star.js @@ -0,0 +1,38 @@ +import $ from 'jquery'; +import createFlash from '~/flash'; +import axios from '~/lib/utils/axios_utils'; +import { spriteIcon } from '~/lib/utils/common_utils'; +import { __, s__ } from '~/locale'; + +export default class Star { + constructor(container = '.project-home-panel') { + $(`${container} .toggle-star`).on('click', function toggleStarClickCallback() { + const $this = $(this); + const $starSpan = $this.find('span'); + const $starIcon = $this.find('svg'); + const iconClasses = $starIcon.attr('class').split(' '); + + axios + .post($this.data('endpoint')) + .then(({ data }) => { + const isStarred = $starSpan.hasClass('starred'); + $this.parent().find('.count').text(data.star_count); + + if (isStarred) { + $starSpan.removeClass('starred').text(s__('StarProject|Star')); + $starIcon.remove(); + $this.prepend(spriteIcon('star-o', iconClasses)); + } else { + $starSpan.addClass('starred').text(__('Unstar')); + $starIcon.remove(); + $this.prepend(spriteIcon('star', iconClasses)); + } + }) + .catch(() => + createFlash({ + message: __('Star toggle failed. Try again later.'), + }), + ); + }); + } +} |