diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-23 15:09:58 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-23 15:09:58 +0300 |
commit | a071c2888d62f7a56349e99f5c070407df2e17c1 (patch) | |
tree | 47e5d2cb95920a1e28348c3af5a3d9987c2805c2 /app | |
parent | 8f2b51af416f4f4451632f6b3c2ada52c52eb44f (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
40 files changed, 478 insertions, 621 deletions
diff --git a/app/assets/javascripts/diffs/components/diff_row_utils.js b/app/assets/javascripts/diffs/components/diff_row_utils.js new file mode 100644 index 00000000000..998320c3245 --- /dev/null +++ b/app/assets/javascripts/diffs/components/diff_row_utils.js @@ -0,0 +1,99 @@ +import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; +import { __ } from '~/locale'; +import { + MATCH_LINE_TYPE, + CONTEXT_LINE_TYPE, + LINE_HOVER_CLASS_NAME, + OLD_NO_NEW_LINE_TYPE, + NEW_NO_NEW_LINE_TYPE, + EMPTY_CELL_TYPE, +} from '../constants'; + +export const isHighlighted = (state, line, isCommented) => { + if (isCommented) return true; + + const lineCode = line?.line_code; + return lineCode ? lineCode === state.diffs.highlightedRow : false; +}; + +export const isContextLine = type => type === CONTEXT_LINE_TYPE; + +export const isMatchLine = type => type === MATCH_LINE_TYPE; + +export const isMetaLine = type => + [OLD_NO_NEW_LINE_TYPE, NEW_NO_NEW_LINE_TYPE, EMPTY_CELL_TYPE].includes(type); + +export const shouldRenderCommentButton = ( + isLoggedIn, + isCommentButtonRendered, + featureMergeRefHeadComments = false, +) => { + if (!isCommentButtonRendered) { + return false; + } + + if (isLoggedIn) { + const isDiffHead = parseBoolean(getParameterByName('diff_head')); + return !isDiffHead || featureMergeRefHeadComments; + } + + return false; +}; + +export const hasDiscussions = line => line?.discussions?.length > 0; + +export const lineHref = line => `#${line?.line_code || ''}`; + +export const lineCode = line => { + if (!line) return undefined; + return line.line_code || line.left?.line_code || line.right?.line_code; +}; + +export const classNameMapCell = (line, hll, isLoggedIn, isHover) => { + if (!line) return []; + const { type } = line; + + return [ + type, + { + hll, + [LINE_HOVER_CLASS_NAME]: isLoggedIn && isHover && !isContextLine(type) && !isMetaLine(type), + }, + ]; +}; + +export const addCommentTooltip = line => { + let tooltip; + if (!line) return tooltip; + + tooltip = __('Add a comment to this line'); + const brokenSymlinks = line.commentsDisabled; + + if (brokenSymlinks) { + if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { + tooltip = __( + 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', + ); + } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { + tooltip = __( + 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', + ); + } + } + + return tooltip; +}; + +export const parallelViewLeftLineType = (line, hll) => { + if (line?.right?.type === NEW_NO_NEW_LINE_TYPE) { + return OLD_NO_NEW_LINE_TYPE; + } + + const lineTypeClass = line?.left ? line.left.type : EMPTY_CELL_TYPE; + + return [lineTypeClass, { hll }]; +}; + +export const shouldShowCommentButton = (hover, context, meta, discussions) => { + return hover && !context && !meta && !discussions; +}; diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue deleted file mode 100644 index 49982a81372..00000000000 --- a/app/assets/javascripts/diffs/components/diff_table_cell.vue +++ /dev/null @@ -1,206 +0,0 @@ -<script> -import { mapGetters, mapActions } from 'vuex'; -import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; -import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; -import DiffGutterAvatars from './diff_gutter_avatars.vue'; -import { __ } from '~/locale'; -import { - CONTEXT_LINE_TYPE, - LINE_POSITION_RIGHT, - EMPTY_CELL_TYPE, - OLD_NO_NEW_LINE_TYPE, - OLD_LINE_TYPE, - NEW_NO_NEW_LINE_TYPE, - LINE_HOVER_CLASS_NAME, -} from '../constants'; - -export default { - components: { - DiffGutterAvatars, - GlIcon, - }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - line: { - type: Object, - required: true, - }, - fileHash: { - type: String, - required: true, - }, - isHighlighted: { - type: Boolean, - required: true, - }, - showCommentButton: { - type: Boolean, - required: false, - default: false, - }, - linePosition: { - type: String, - required: false, - default: '', - }, - lineType: { - type: String, - required: false, - default: '', - }, - isBottom: { - type: Boolean, - required: false, - default: false, - }, - isHover: { - type: Boolean, - required: false, - default: false, - }, - }, - data() { - return { - isCommentButtonRendered: false, - }; - }, - computed: { - ...mapGetters(['isLoggedIn']), - lineCode() { - return ( - this.line.line_code || - (this.line.left && this.line.left.line_code) || - (this.line.right && this.line.right.line_code) - ); - }, - lineHref() { - return `#${this.line.line_code || ''}`; - }, - shouldShowCommentButton() { - return this.isHover && !this.isContextLine && !this.isMetaLine && !this.hasDiscussions; - }, - hasDiscussions() { - return this.line.discussions && this.line.discussions.length > 0; - }, - shouldShowAvatarsOnGutter() { - if (!this.line.type && this.linePosition === LINE_POSITION_RIGHT) { - return false; - } - return this.showCommentButton && this.hasDiscussions; - }, - shouldRenderCommentButton() { - if (!this.isCommentButtonRendered) { - return false; - } - - if (this.isLoggedIn && this.showCommentButton) { - const isDiffHead = parseBoolean(getParameterByName('diff_head')); - return !isDiffHead || gon.features?.mergeRefHeadComments; - } - - return false; - }, - isContextLine() { - return this.line.type === CONTEXT_LINE_TYPE; - }, - isMetaLine() { - const { type } = this.line; - - return ( - type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE - ); - }, - classNameMap() { - const { type } = this.line; - - return [ - type, - { - hll: this.isHighlighted, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && this.isHover && !this.isContextLine && !this.isMetaLine, - }, - ]; - }, - lineNumber() { - return this.lineType === OLD_LINE_TYPE ? this.line.old_line : this.line.new_line; - }, - addCommentTooltip() { - const brokenSymlinks = this.line.commentsDisabled; - let tooltip = __('Add a comment to this line'); - - if (brokenSymlinks) { - if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { - tooltip = __( - 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', - ); - } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { - tooltip = __( - 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', - ); - } - } - - return tooltip; - }, - }, - mounted() { - this.unwatchShouldShowCommentButton = this.$watch('shouldShowCommentButton', newVal => { - if (newVal) { - this.isCommentButtonRendered = true; - this.unwatchShouldShowCommentButton(); - } - }); - }, - beforeDestroy() { - this.unwatchShouldShowCommentButton(); - }, - methods: { - ...mapActions('diffs', ['showCommentForm', 'setHighlightedRow', 'toggleLineDiscussions']), - handleCommentButton() { - this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.fileHash }); - }, - }, -}; -</script> - -<template> - <td ref="td" :class="classNameMap"> - <span - ref="addNoteTooltip" - v-gl-tooltip - class="add-diff-note tooltip-wrapper" - :title="addCommentTooltip" - > - <button - v-if="shouldRenderCommentButton" - v-show="shouldShowCommentButton" - ref="addDiffNoteButton" - type="button" - class="add-diff-note note-button js-add-diff-note-button qa-diff-comment" - :disabled="line.commentsDisabled" - @click="handleCommentButton" - > - <gl-icon :size="12" name="comment" /> - </button> - </span> - <a - v-if="lineNumber" - ref="lineNumberRef" - :data-linenumber="lineNumber" - :href="lineHref" - @click="setHighlightedRow(lineCode)" - > - </a> - <diff-gutter-avatars - v-if="shouldShowAvatarsOnGutter" - :discussions="line.discussions" - :discussions-expanded="line.discussionsExpanded" - @toggleLineDiscussions=" - toggleLineDiscussions({ lineCode, fileHash, expanded: !line.discussionsExpanded }) - " - /> - </td> -</template> diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue index 7fab750089e..f9d491603cb 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue @@ -1,22 +1,9 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; -import { - MATCH_LINE_TYPE, - NEW_LINE_TYPE, - OLD_LINE_TYPE, - CONTEXT_LINE_TYPE, - CONTEXT_LINE_CLASS_NAME, - LINE_POSITION_LEFT, - LINE_POSITION_RIGHT, - LINE_HOVER_CLASS_NAME, - OLD_NO_NEW_LINE_TYPE, - NEW_NO_NEW_LINE_TYPE, - EMPTY_CELL_TYPE, -} from '../constants'; -import { __ } from '~/locale'; -import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; +import { CONTEXT_LINE_CLASS_NAME } from '../constants'; import DiffGutterAvatars from './diff_gutter_avatars.vue'; +import * as utils from './diff_row_utils'; export default { components: { @@ -61,14 +48,11 @@ export default { ...mapGetters('diffs', ['fileLineCoverage']), ...mapState({ isHighlighted(state) { - if (this.isCommented) return true; - - const lineCode = this.line.line_code; - return lineCode ? lineCode === state.diffs.highlightedRow : false; + return utils.isHighlighted(state, this.line, this.isCommented); }, }), isContextLine() { - return this.line.type === CONTEXT_LINE_TYPE; + return utils.isContextLine(this.line.type); }, classNameMap() { return [ @@ -82,82 +66,48 @@ export default { return this.line.line_code || `${this.fileHash}_${this.line.old_line}_${this.line.new_line}`; }, isMatchLine() { - return this.line.type === MATCH_LINE_TYPE; + return utils.isMatchLine(this.line.type); }, coverageState() { return this.fileLineCoverage(this.filePath, this.line.new_line); }, isMetaLine() { - const { type } = this.line; - - return ( - type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE - ); + return utils.isMetaLine(this.line.type); }, classNameMapCell() { - const { type } = this.line; - - return [ - type, - { - hll: this.isHighlighted, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && this.isHover && !this.isContextLine && !this.isMetaLine, - }, - ]; + return utils.classNameMapCell(this.line, this.isHighlighted, this.isLoggedIn, this.isHover); }, addCommentTooltip() { - const brokenSymlinks = this.line.commentsDisabled; - let tooltip = __('Add a comment to this line'); - - if (brokenSymlinks) { - if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { - tooltip = __( - 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', - ); - } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { - tooltip = __( - 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', - ); - } - } - - return tooltip; + return utils.addCommentTooltip(this.line); }, shouldRenderCommentButton() { - if (this.isLoggedIn) { - const isDiffHead = parseBoolean(getParameterByName('diff_head')); - return !isDiffHead || gon.features?.mergeRefHeadComments; - } - - return false; + return utils.shouldRenderCommentButton( + this.isLoggedIn, + true, + gon.features?.mergeRefHeadComments, + ); }, shouldShowCommentButton() { - return this.isHover && !this.isContextLine && !this.isMetaLine && !this.hasDiscussions; + return utils.shouldShowCommentButton( + this.isHover, + this.isContextLine, + this.isMetaLine, + this.hasDiscussions, + ); }, hasDiscussions() { - return this.line.discussions && this.line.discussions.length > 0; + return utils.hasDiscussions(this.line); }, lineHref() { - return `#${this.line.line_code || ''}`; + return utils.lineHref(this.line); }, lineCode() { - return ( - this.line.line_code || - (this.line.left && this.line.left.line_code) || - (this.line.right && this.line.right.line_code) - ); + return utils.lineCode(this.line); }, shouldShowAvatarsOnGutter() { return this.hasDiscussions; }, }, - created() { - this.newLineType = NEW_LINE_TYPE; - this.oldLineType = OLD_LINE_TYPE; - this.linePositionLeft = LINE_POSITION_LEFT; - this.linePositionRight = LINE_POSITION_RIGHT; - }, mounted() { this.scrollToLineIfNeededInline(this.line); }, @@ -242,6 +192,7 @@ export default { class="line-coverage" ></td> <td + :key="line.line_code" v-safe-html="line.rich_text" :class="[ line.type, diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index 0bf47dc77a6..06dcadb2dc1 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -2,21 +2,9 @@ import { mapActions, mapGetters, mapState } from 'vuex'; import $ from 'jquery'; import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; -import { - MATCH_LINE_TYPE, - NEW_LINE_TYPE, - OLD_LINE_TYPE, - CONTEXT_LINE_TYPE, - CONTEXT_LINE_CLASS_NAME, - OLD_NO_NEW_LINE_TYPE, - PARALLEL_DIFF_VIEW_TYPE, - NEW_NO_NEW_LINE_TYPE, - EMPTY_CELL_TYPE, - LINE_HOVER_CLASS_NAME, -} from '../constants'; -import { __ } from '~/locale'; -import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils'; +import { CONTEXT_LINE_CLASS_NAME, PARALLEL_DIFF_VIEW_TYPE } from '../constants'; import DiffGutterAvatars from './diff_gutter_avatars.vue'; +import * as utils from './diff_row_utils'; export default { components: { @@ -63,20 +51,15 @@ export default { ...mapGetters(['isLoggedIn']), ...mapState({ isHighlighted(state) { - if (this.isCommented) return true; - - const lineCode = - (this.line.left && this.line.left.line_code) || - (this.line.right && this.line.right.line_code); - - return lineCode ? lineCode === state.diffs.highlightedRow : false; + const line = this.line.left?.line_code ? this.line.left : this.line.right; + return utils.isHighlighted(state, line, this.isCommented); }, }), isContextLineLeft() { - return this.line.left && this.line.left.type === CONTEXT_LINE_TYPE; + return utils.isContextLine(this.line.left?.type); }, isContextLineRight() { - return this.line.right && this.line.right.type === CONTEXT_LINE_TYPE; + return utils.isContextLine(this.line.right?.type); }, classNameMap() { return { @@ -85,157 +68,84 @@ export default { }; }, parallelViewLeftLineType() { - if (this.line.right && this.line.right.type === NEW_NO_NEW_LINE_TYPE) { - return OLD_NO_NEW_LINE_TYPE; - } - - const lineTypeClass = this.line.left ? this.line.left.type : EMPTY_CELL_TYPE; - - return [ - lineTypeClass, - { - hll: this.isHighlighted, - }, - ]; + return utils.parallelViewLeftLineType(this.line, this.isHighlighted); }, isMatchLineLeft() { - return this.line.left && this.line.left.type === MATCH_LINE_TYPE; + return utils.isMatchLine(this.line.left?.type); }, isMatchLineRight() { - return this.line.right && this.line.right.type === MATCH_LINE_TYPE; + return utils.isMatchLine(this.line.right?.type); }, coverageState() { return this.fileLineCoverage(this.filePath, this.line.right.new_line); }, classNameMapCellLeft() { - const { type } = this.line.left; - - return [ - type, - { - hll: this.isHighlighted, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && this.isLeftHover && !this.isContextLineLeft && !this.isMetaLineLeft, - }, - ]; + return utils.classNameMapCell( + this.line.left, + this.isHighlighted, + this.isLoggedIn, + this.isLeftHover, + ); }, classNameMapCellRight() { - const { type } = this.line.right; - - return [ - type, - { - hll: this.isHighlighted, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && - this.isRightHover && - !this.isContextLineRight && - !this.isMetaLineRight, - }, - ]; + return utils.classNameMapCell( + this.line.right, + this.isHighlighted, + this.isLoggedIn, + this.isRightHover, + ); }, addCommentTooltipLeft() { - const brokenSymlinks = this.line.left.commentsDisabled; - let tooltip = __('Add a comment to this line'); - - if (brokenSymlinks) { - if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { - tooltip = __( - 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', - ); - } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { - tooltip = __( - 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', - ); - } - } - - return tooltip; + return utils.addCommentTooltip(this.line.left); }, addCommentTooltipRight() { - const brokenSymlinks = this.line.right.commentsDisabled; - let tooltip = __('Add a comment to this line'); - - if (brokenSymlinks) { - if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) { - tooltip = __( - 'Commenting on symbolic links that replace or are replaced by files is currently not supported.', - ); - } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) { - tooltip = __( - 'Commenting on files that replace or are replaced by symbolic links is currently not supported.', - ); - } - } - - return tooltip; + return utils.addCommentTooltip(this.line.right); }, shouldRenderCommentButton() { - if (!this.isCommentButtonRendered) { - return false; - } - - if (this.isLoggedIn) { - const isDiffHead = parseBoolean(getParameterByName('diff_head')); - return !isDiffHead || gon.features?.mergeRefHeadComments; - } - - return false; + return utils.shouldRenderCommentButton( + this.isLoggedIn, + this.isCommentButtonRendered, + gon.features?.mergeRefHeadComments, + ); }, shouldShowCommentButtonLeft() { - return ( - this.isLeftHover && - !this.isContextLineLeft && - !this.isMetaLineLeft && - !this.hasDiscussionsLeft + return utils.shouldShowCommentButton( + this.isLeftHover, + this.isContextLineLeft, + this.isMetaLineLeft, + this.hasDiscussionsLeft, ); }, shouldShowCommentButtonRight() { - return ( - this.isRightHover && - !this.isContextLineRight && - !this.isMetaLineRight && - !this.hasDiscussionsRight + return utils.shouldShowCommentButton( + this.isRightHover, + this.isContextLineRight, + this.isMetaLineRight, + this.hasDiscussionsRight, ); }, hasDiscussionsLeft() { - return this.line.left?.discussions?.length > 0; + return utils.hasDiscussions(this.line.left); }, hasDiscussionsRight() { - return this.line.right?.discussions?.length > 0; + return utils.hasDiscussions(this.line.right); }, lineHrefOld() { - return `#${this.line.left.line_code || ''}`; + return utils.lineHref(this.line.left); }, lineHrefNew() { - return `#${this.line.right.line_code || ''}`; + return utils.lineHref(this.line.right); }, lineCode() { - return ( - (this.line.left && this.line.left.line_code) || - (this.line.right && this.line.right.line_code) - ); + return utils.lineCode(this.line); }, isMetaLineLeft() { - const type = this.line.left?.type; - - return ( - type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE - ); + return utils.isMetaLine(this.line.left?.type); }, isMetaLineRight() { - const type = this.line.right?.type; - - return ( - type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE - ); + return utils.isMetaLine(this.line.right?.type); }, }, - created() { - this.newLineType = NEW_LINE_TYPE; - this.oldLineType = OLD_LINE_TYPE; - this.parallelDiffViewType = PARALLEL_DIFF_VIEW_TYPE; - }, mounted() { this.scrollToLineIfNeededParallel(this.line); this.unwatchShouldShowCommentButton = this.$watch( @@ -341,6 +251,7 @@ export default { <td :class="parallelViewLeftLineType" class="line-coverage left-side"></td> <td :id="line.left.line_code" + :key="line.left.line_code" v-safe-html="line.left.rich_text" :class="parallelViewLeftLineType" class="line_content with-coverage parallel left-side" @@ -401,6 +312,7 @@ export default { ></td> <td :id="line.right.line_code" + :key="line.right.rich_text" v-safe-html="line.right.rich_text" :class="[ line.right.type, diff --git a/app/assets/javascripts/pages/search/show/index.js b/app/assets/javascripts/pages/search/show/index.js index 92d01343bd5..8dcc5aee00e 100644 --- a/app/assets/javascripts/pages/search/show/index.js +++ b/app/assets/javascripts/pages/search/show/index.js @@ -1,7 +1,10 @@ import Search from './search'; import initStateFilter from '~/search/state_filter'; +import initConfidentialFilter from '~/search/confidential_filter'; document.addEventListener('DOMContentLoaded', () => { initStateFilter(); + initConfidentialFilter(); + return new Search(); }); diff --git a/app/assets/javascripts/search/components/dropdown_filter.vue b/app/assets/javascripts/search/components/dropdown_filter.vue new file mode 100644 index 00000000000..cd9237026f2 --- /dev/null +++ b/app/assets/javascripts/search/components/dropdown_filter.vue @@ -0,0 +1,111 @@ +<script> +import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui'; +import { setUrlParams, visitUrl } from '~/lib/utils/url_utility'; +import { sprintf, s__ } from '~/locale'; + +export default { + name: 'DropdownFilter', + components: { + GlDropdown, + GlDropdownItem, + GlDropdownDivider, + }, + props: { + initialFilter: { + type: String, + required: false, + default: null, + }, + filters: { + type: Object, + required: true, + }, + filtersArray: { + type: Array, + required: true, + }, + header: { + type: String, + required: true, + }, + param: { + type: String, + required: true, + }, + scope: { + type: String, + required: true, + }, + supportedScopes: { + type: Array, + required: true, + }, + }, + computed: { + filter() { + return this.initialFilter || this.filters.ANY.value; + }, + selectedFilterText() { + const f = this.filtersArray.find(({ value }) => value === this.selectedFilter); + if (!f || f === this.filters.ANY) { + return sprintf(s__('Any %{header}'), { header: this.header }); + } + + return f.label; + }, + showDropdown() { + return this.supportedScopes.includes(this.scope); + }, + selectedFilter: { + get() { + if (this.filtersArray.some(({ value }) => value === this.filter)) { + return this.filter; + } + + return this.filters.ANY.value; + }, + set(filter) { + visitUrl(setUrlParams({ [this.param]: filter })); + }, + }, + }, + methods: { + dropDownItemClass(filter) { + return { + 'gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2': + filter === this.filters.ANY, + }; + }, + isFilterSelected(filter) { + return filter === this.selectedFilter; + }, + handleFilterChange(filter) { + this.selectedFilter = filter; + }, + }, +}; +</script> + +<template> + <gl-dropdown + v-if="showDropdown" + :text="selectedFilterText" + class="col-3 gl-pt-4 gl-pl-0 gl-pr-0 gl-mr-4" + menu-class="gl-w-full! gl-pl-0" + > + <header class="gl-text-center gl-font-weight-bold gl-font-lg"> + {{ header }} + </header> + <gl-dropdown-divider /> + <gl-dropdown-item + v-for="f in filtersArray" + :key="f.value" + :is-check-item="true" + :is-checked="isFilterSelected(f.value)" + :class="dropDownItemClass(f)" + @click="handleFilterChange(f.value)" + > + {{ f.label }} + </gl-dropdown-item> + </gl-dropdown> +</template> diff --git a/app/assets/javascripts/search/confidential_filter/constants.js b/app/assets/javascripts/search/confidential_filter/constants.js new file mode 100644 index 00000000000..4665ce6a5d1 --- /dev/null +++ b/app/assets/javascripts/search/confidential_filter/constants.js @@ -0,0 +1,28 @@ +import { __ } from '~/locale'; + +export const FILTER_HEADER = __('Confidentiality'); + +export const FILTER_STATES = { + ANY: { + label: __('Any'), + value: null, + }, + CONFIDENTIAL: { + label: __('Confidential'), + value: 'yes', + }, + NOT_CONFIDENTIAL: { + label: __('Not confidential'), + value: 'no', + }, +}; + +export const SCOPES = { + ISSUES: 'issues', +}; + +export const FILTER_STATES_BY_SCOPE = { + [SCOPES.ISSUES]: [FILTER_STATES.ANY, FILTER_STATES.CONFIDENTIAL, FILTER_STATES.NOT_CONFIDENTIAL], +}; + +export const FILTER_PARAM = 'confidential'; diff --git a/app/assets/javascripts/search/confidential_filter/index.js b/app/assets/javascripts/search/confidential_filter/index.js new file mode 100644 index 00000000000..bec772be0dd --- /dev/null +++ b/app/assets/javascripts/search/confidential_filter/index.js @@ -0,0 +1,39 @@ +import Vue from 'vue'; +import Translate from '~/vue_shared/translate'; +import DropdownFilter from '../components/dropdown_filter.vue'; +import { + FILTER_HEADER, + FILTER_PARAM, + FILTER_STATES_BY_SCOPE, + FILTER_STATES, + SCOPES, +} from './constants'; + +Vue.use(Translate); + +export default () => { + const el = document.getElementById('js-search-filter-by-confidential'); + + if (!el) return false; + + return new Vue({ + el, + data() { + return { ...el.dataset }; + }, + + render(createElement) { + return createElement(DropdownFilter, { + props: { + initialFilter: this.filter, + filtersArray: FILTER_STATES_BY_SCOPE[this.scope], + filters: FILTER_STATES, + header: FILTER_HEADER, + param: FILTER_PARAM, + scope: this.scope, + supportedScopes: Object.values(SCOPES), + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/search/state_filter/components/state_filter.vue b/app/assets/javascripts/search/state_filter/components/state_filter.vue deleted file mode 100644 index f08adaf8c83..00000000000 --- a/app/assets/javascripts/search/state_filter/components/state_filter.vue +++ /dev/null @@ -1,94 +0,0 @@ -<script> -import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui'; -import { - FILTER_STATES, - SCOPES, - FILTER_STATES_BY_SCOPE, - FILTER_HEADER, - FILTER_TEXT, -} from '../constants'; -import { setUrlParams, visitUrl } from '~/lib/utils/url_utility'; - -const FILTERS_ARRAY = Object.values(FILTER_STATES); - -export default { - name: 'StateFilter', - components: { - GlDropdown, - GlDropdownItem, - GlDropdownDivider, - }, - props: { - scope: { - type: String, - required: true, - }, - state: { - type: String, - required: false, - default: FILTER_STATES.ANY.value, - validator: v => FILTERS_ARRAY.some(({ value }) => value === v), - }, - }, - computed: { - selectedFilterText() { - const filter = FILTERS_ARRAY.find(({ value }) => value === this.selectedFilter); - if (!filter || filter === FILTER_STATES.ANY) { - return FILTER_TEXT; - } - - return filter.label; - }, - showDropdown() { - return Object.values(SCOPES).includes(this.scope); - }, - selectedFilter: { - get() { - if (FILTERS_ARRAY.some(({ value }) => value === this.state)) { - return this.state; - } - - return FILTER_STATES.ANY.value; - }, - set(state) { - visitUrl(setUrlParams({ state })); - }, - }, - }, - methods: { - dropDownItemClass(filter) { - return { - 'gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2': - filter === FILTER_STATES.ANY, - }; - }, - isFilterSelected(filter) { - return filter === this.selectedFilter; - }, - handleFilterChange(state) { - this.selectedFilter = state; - }, - }, - filterStates: FILTER_STATES, - filterHeader: FILTER_HEADER, - filtersByScope: FILTER_STATES_BY_SCOPE, -}; -</script> - -<template> - <gl-dropdown v-if="showDropdown" :text="selectedFilterText" class="col-sm-3 gl-pt-4 gl-pl-0"> - <header class="gl-text-center gl-font-weight-bold gl-font-lg"> - {{ $options.filterHeader }} - </header> - <gl-dropdown-divider /> - <gl-dropdown-item - v-for="filter in $options.filtersByScope[scope]" - :key="filter.value" - :is-check-item="true" - :is-checked="isFilterSelected(filter.value)" - :class="dropDownItemClass(filter)" - @click="handleFilterChange(filter.value)" - >{{ filter.label }}</gl-dropdown-item - > - </gl-dropdown> -</template> diff --git a/app/assets/javascripts/search/state_filter/constants.js b/app/assets/javascripts/search/state_filter/constants.js index 2f11cab9044..00ae1bd9750 100644 --- a/app/assets/javascripts/search/state_filter/constants.js +++ b/app/assets/javascripts/search/state_filter/constants.js @@ -2,8 +2,6 @@ import { __ } from '~/locale'; export const FILTER_HEADER = __('Status'); -export const FILTER_TEXT = __('Any Status'); - export const FILTER_STATES = { ANY: { label: __('Any'), @@ -37,3 +35,5 @@ export const FILTER_STATES_BY_SCOPE = { FILTER_STATES.CLOSED, ], }; + +export const FILTER_PARAM = 'state'; diff --git a/app/assets/javascripts/search/state_filter/index.js b/app/assets/javascripts/search/state_filter/index.js index 13708574cfb..2c12885c40b 100644 --- a/app/assets/javascripts/search/state_filter/index.js +++ b/app/assets/javascripts/search/state_filter/index.js @@ -1,6 +1,13 @@ import Vue from 'vue'; import Translate from '~/vue_shared/translate'; -import StateFilter from './components/state_filter.vue'; +import DropdownFilter from '../components/dropdown_filter.vue'; +import { + FILTER_HEADER, + FILTER_PARAM, + FILTER_STATES_BY_SCOPE, + FILTER_STATES, + SCOPES, +} from './constants'; Vue.use(Translate); @@ -11,22 +18,20 @@ export default () => { return new Vue({ el, - components: { - StateFilter, - }, data() { - const { dataset } = this.$options.el; - return { - scope: dataset.scope, - state: dataset.state, - }; + return { ...el.dataset }; }, render(createElement) { - return createElement('state-filter', { + return createElement(DropdownFilter, { props: { + initialFilter: this.filter, + filtersArray: FILTER_STATES_BY_SCOPE[this.scope], + filters: FILTER_STATES, + header: FILTER_HEADER, + param: FILTER_PARAM, scope: this.scope, - state: this.state, + supportedScopes: Object.values(SCOPES), }, }); }, diff --git a/app/assets/stylesheets/framework/animations.scss b/app/assets/stylesheets/framework/animations.scss index 136ff82e0f8..196fb3a7088 100644 --- a/app/assets/stylesheets/framework/animations.scss +++ b/app/assets/stylesheets/framework/animations.scss @@ -112,8 +112,7 @@ a { } .dropdown-menu a, -.dropdown-menu button, -.dropdown-menu-nav a { +.dropdown-menu button { transition: none; } diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index ad5864ef6d9..7baaa26fbec 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -33,8 +33,7 @@ } .show.dropdown { - .dropdown-menu, - .dropdown-menu-nav { + .dropdown-menu { @include set-visible; min-height: $dropdown-min-height; max-height: $dropdown-max-height; @@ -258,8 +257,7 @@ } } -.dropdown-menu, -.dropdown-menu-nav { +.dropdown-menu { display: none; position: absolute; width: auto; @@ -393,49 +391,56 @@ pointer-events: none; } - .dropdown-menu li { - cursor: pointer; + .dropdown-menu { + display: none; + opacity: 1; + visibility: visible; + transform: translateY(0); - &.droplab-item-active button { - @include dropdown-item-hover; - } + li { + cursor: pointer; - > a, - > button { - display: flex; - margin: 0; - text-overflow: inherit; - text-align: left; + &.droplab-item-active button { + @include dropdown-item-hover; + } - &.btn .fa:not(:last-child) { - margin-left: 5px; + > a, + > button { + display: flex; + margin: 0; + text-overflow: inherit; + text-align: left; + + &.btn .fa:not(:last-child) { + margin-left: 5px; + } } - } - > button.dropdown-epic-button { - flex-direction: column; + > button.dropdown-epic-button { + flex-direction: column; - .reference { - color: $gray-300; - margin-top: $gl-padding-4; + .reference { + color: $gray-300; + margin-top: $gl-padding-4; + } } - } - &.droplab-item-selected i { - visibility: visible; - } + &.droplab-item-selected i { + visibility: visible; + } - .icon { - visibility: hidden; - } + .icon { + visibility: hidden; + } - .description { - display: inline-block; - white-space: normal; - margin-left: 5px; + .description { + display: inline-block; + white-space: normal; + margin-left: 5px; - p { - margin-bottom: 0; + p { + margin-bottom: 0; + } } } } @@ -447,21 +452,12 @@ } } -.droplab-dropdown .dropdown-menu, -.droplab-dropdown .dropdown-menu-nav { - display: none; - opacity: 1; - visibility: visible; - transform: translateY(0); -} - .comment-type-dropdown.show .dropdown-menu { display: block; } .filtered-search-box-input-container { - .dropdown-menu, - .dropdown-menu-nav { + .dropdown-menu { max-width: 280px; } } @@ -850,8 +846,7 @@ } header.navbar-gitlab .dropdown { - .dropdown-menu, - .dropdown-menu-nav { + .dropdown-menu { width: 100%; min-width: 100%; } diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index 4dc1f2034f3..ddffcf382c6 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -227,6 +227,10 @@ padding-left: 40px; } + .gl-label-scoped { + --label-inset-border: inset 0 0 0 1px currentColor; + } + @include media-breakpoint-up(lg) { margin-right: 5px; } diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 050f83edacb..c4f72372f19 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -9,6 +9,7 @@ class Admin::UsersController < Admin::ApplicationController def index @users = User.filter_items(params[:filter]).order_name_asc @users = @users.search_with_secondary_emails(params[:search_query]) if params[:search_query].present? + @users = @users.includes(:authorized_projects) # rubocop: disable CodeReuse/ActiveRecord @users = @users.sort_by_attribute(@sort = params[:sort]) @users = @users.page(params[:page]) end diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb index 1034ca6cd7b..df0b71d2cf0 100644 --- a/app/controllers/groups/labels_controller.rb +++ b/app/controllers/groups/labels_controller.rb @@ -60,13 +60,7 @@ class Groups::LabelsController < Groups::ApplicationController def destroy @label.destroy - - respond_to do |format| - format.html do - redirect_to group_labels_path(@group), status: :found, notice: "#{@label.name} deleted permanently" - end - format.js - end + redirect_to group_labels_path(@group), status: :found, notice: "#{@label.name} deleted permanently" end protected diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index 8746c79ed4d..d0d100fd88c 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -11,8 +11,6 @@ module Projects push_frontend_feature_flag(:ci_key_autocomplete, default_enabled: true) end - helper_method :highlight_badge - def show end @@ -52,10 +50,6 @@ module Projects private - def highlight_badge(name, content, language = nil) - Gitlab::Highlight.highlight(name, content, language: language) - end - def update_params params.require(:project).permit(*permitted_project_params) end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index e8141bbf448..dedaf0c903a 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -38,7 +38,6 @@ class SearchController < ApplicationController @show_snippets = search_service.show_snippets? @search_results = search_service.search_results @search_objects = search_service.search_objects(preload_method) - @search_highlight = search_service.search_highlight render_commits if @scope == 'commits' eager_load_user_status if @scope == 'users' diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 6d66db0e3fb..2eff87ae0ec 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -1,6 +1,12 @@ # frozen_string_literal: true module BlobHelper + def highlight(file_name, file_content, language: nil, plain: false) + highlighted = Gitlab::Highlight.highlight(file_name, file_content, plain: plain, language: language) + + raw %(<pre class="code highlight"><code>#{highlighted}</code></pre>) + end + def no_highlight_files %w(credits changelog news copying copyright license authors) end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index e4ab4fc7c9a..0dea6217276 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -299,13 +299,6 @@ module SearchHelper simple_search_highlight_and_truncate(issue.description, search_term, highlighter: '<span class="gl-text-black-normal gl-font-weight-bold">\1</span>') end - def simple_search_highlight_and_truncate(text, phrase, options = {}) - truncate_length = options.delete(:length) { 200 } - text = truncate(text, length: truncate_length) - phrase = phrase.split - highlight(text, phrase, options) - end - def show_user_search_tab? return false if Feature.disabled?(:users_search, default_enabled: true) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index b334da1ca91..1965c5dacc7 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1302,6 +1302,14 @@ class MergeRequest < ApplicationRecord unlock_mr end + def update_and_mark_in_progress_merge_commit_sha(commit_id) + self.update(in_progress_merge_commit_sha: commit_id) + # Since another process checks for matching merge request, we need + # to make it possible to detect whether the query should go to the + # primary. + target_project.mark_primary_write_location + end + def diverged_commits_count cache = Rails.cache.read(:"merge_request_#{id}_diverged_commits") diff --git a/app/models/project.rb b/app/models/project.rb index 4db0eaa0442..54925ae4ed8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2292,6 +2292,10 @@ class Project < ApplicationRecord [] end + def mark_primary_write_location + # Overriden in EE + end + def toggle_ci_cd_settings!(settings_attribute) ci_cd_settings.toggle!(settings_attribute) end diff --git a/app/models/repository.rb b/app/models/repository.rb index ef17e010ba8..6bc2ec24811 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -853,7 +853,7 @@ class Repository def merge(user, source_sha, merge_request, message) with_cache_hooks do raw_repository.merge(user, source_sha, merge_request.target_branch, message) do |commit_id| - merge_request.update(in_progress_merge_commit_sha: commit_id) + merge_request.update_and_mark_in_progress_merge_commit_sha(commit_id) nil # Return value does not matter. end end @@ -873,7 +873,7 @@ class Repository their_commit_id = commit(source)&.id raise 'Invalid merge source' if their_commit_id.nil? - merge_request&.update(in_progress_merge_commit_sha: their_commit_id) + merge_request&.update_and_mark_in_progress_merge_commit_sha(their_commit_id) with_cache_hooks { raw.ff_merge(user, their_commit_id, target_branch) } end diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb index d3b3a46bf74..c05bc80415a 100644 --- a/app/models/user_preference.rb +++ b/app/models/user_preference.rb @@ -8,6 +8,9 @@ class UserPreference < ApplicationRecord belongs_to :user + scope :with_user, -> { joins(:user) } + scope :gitpod_enabled, -> { where(gitpod_enabled: true) } + validates :issue_notes_filter, :merge_request_notes_filter, inclusion: { in: NOTES_FILTERS.values }, presence: true validates :tab_width, numericality: { only_integer: true, diff --git a/app/services/merge_requests/ff_merge_service.rb b/app/services/merge_requests/ff_merge_service.rb index 79011094e88..c5640047899 100644 --- a/app/services/merge_requests/ff_merge_service.rb +++ b/app/services/merge_requests/ff_merge_service.rb @@ -27,7 +27,7 @@ module MergeRequests rescue StandardError => e raise MergeError, "Something went wrong during merge: #{e.message}" ensure - merge_request.update(in_progress_merge_commit_sha: nil) + merge_request.update_and_mark_in_progress_merge_commit_sha(nil) end end end diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 437e87dadf7..ba22b458777 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -84,7 +84,7 @@ module MergeRequests merge_request.update!(merge_commit_sha: commit_id) ensure - merge_request.update_column(:in_progress_merge_commit_sha, nil) + merge_request.update_and_mark_in_progress_merge_commit_sha(nil) end def try_merge diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 3ccd67c8d30..278cf389e07 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -65,10 +65,6 @@ class SearchService @search_objects ||= redact_unauthorized_results(search_results.objects(scope, page: params[:page], per_page: per_page, preload_method: preload_method)) end - def search_highlight - search_results.highlight_map(scope) - end - private def per_page diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 4acfc96caf2..2f3bb19b955 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -19,7 +19,7 @@ %h3.text-center = s_('AdminArea|Projects: %{number_of_projects}') % { number_of_projects: approximate_count_with_delimiters(@counts, Project) } %hr - = link_to(s_('AdminArea|New project'), new_project_path, class: "btn btn-success gl-w-full") + = link_to(s_('AdminArea|New project'), new_project_path, class: "btn gl-button btn-success gl-w-full") .col-sm-4 .info-well.dark-well .well-segment.well-centered @@ -28,8 +28,8 @@ = s_('AdminArea|Users: %{number_of_users}') % { number_of_users: approximate_count_with_delimiters(@counts, User) } %hr .btn-group.d-flex{ role: 'group' } - = link_to s_('AdminArea|New user'), new_admin_user_path, class: "btn btn-success gl-w-full" - = link_to s_('AdminArea|Users statistics'), admin_dashboard_stats_path, class: 'btn btn-primary gl-w-full' + = link_to s_('AdminArea|New user'), new_admin_user_path, class: "btn gl-button btn-success gl-w-full" + = link_to s_('AdminArea|Users statistics'), admin_dashboard_stats_path, class: 'btn gl-button btn-info gl-w-full' .col-sm-4 .info-well.dark-well .well-segment.well-centered @@ -37,7 +37,7 @@ %h3.text-center = s_('AdminArea|Groups: %{number_of_groups}') % { number_of_groups: approximate_count_with_delimiters(@counts, Group) } %hr - = link_to s_('AdminArea|New group'), new_admin_group_path, class: "btn btn-success gl-w-full" + = link_to s_('AdminArea|New group'), new_admin_group_path, class: "btn gl-button btn-success gl-w-full" .row .col-md-4 #js-admin-statistics-container diff --git a/app/views/admin/labels/_form.html.haml b/app/views/admin/labels/_form.html.haml index 299d0a12e6c..664081339f3 100644 --- a/app/views/admin/labels/_form.html.haml +++ b/app/views/admin/labels/_form.html.haml @@ -27,5 +27,5 @@ = render_suggested_colors .form-actions - = f.submit _('Save'), class: 'btn btn-success js-save-button' - = link_to _("Cancel"), admin_labels_path, class: 'btn btn-cancel' + = f.submit _('Save'), class: 'btn gl-button btn-success js-save-button' + = link_to _("Cancel"), admin_labels_path, class: 'btn gl-button btn-cancel' diff --git a/app/views/admin/labels/_label.html.haml b/app/views/admin/labels/_label.html.haml index 6d934654c5d..b31b9bdab0a 100644 --- a/app/views/admin/labels/_label.html.haml +++ b/app/views/admin/labels/_label.html.haml @@ -1,7 +1,7 @@ %li.label-list-item{ id: dom_id(label) } = render "shared/label_row", label: label.present(issuable_subject: nil) .label-actions-list - = link_to edit_admin_label_path(label), class: 'btn btn-transparent label-action has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do + = link_to edit_admin_label_path(label), class: 'btn gl-button btn-transparent label-action has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do = sprite_icon('pencil') - = link_to admin_label_path(label), class: 'btn btn-transparent remove-row label-action has-tooltip', title: _('Delete'), data: { placement: 'bottom', confirm: "Delete this label? Are you sure?" }, aria_label: _('Delete'), method: :delete, remote: true do + = link_to admin_label_path(label), class: 'btn gl-button btn-transparent remove-row label-action has-tooltip', title: _('Delete'), data: { placement: 'bottom', confirm: "Delete this label? Are you sure?" }, aria_label: _('Delete'), method: :delete, remote: true do = sprite_icon('remove') diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml index 38137f360fd..76d37626fff 100644 --- a/app/views/admin/labels/index.html.haml +++ b/app/views/admin/labels/index.html.haml @@ -1,7 +1,7 @@ - page_title _("Labels") %div - = link_to new_admin_label_path, class: "float-right btn btn-nr btn-success" do + = link_to new_admin_label_path, class: "float-right btn gl-button btn-nr btn-success" do = _('New label') %h3.page-title = _('Labels') diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml index 160303890f5..284307d1d54 100644 --- a/app/views/admin/users/_user.html.haml +++ b/app/views/admin/users/_user.html.haml @@ -4,7 +4,12 @@ = _('Name') .table-mobile-content = render 'user_detail', user: user - .table-section.section-25 + .table-section.section-10 + .table-mobile-header{ role: 'rowheader' } + = _('Projects') + .table-mobile-content.gl-str-truncated{ data: { testid: "user-project-count-#{user.id}" } } + = user.authorized_projects.length + .table-section.section-15 .table-mobile-header{ role: 'rowheader' } = _('Created on') .table-mobile-content diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 118bdf7bb17..78c3e41278d 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -72,7 +72,8 @@ .table-holder .thead-white.text-nowrap.gl-responsive-table-row.table-row-header{ role: 'row' } .table-section.section-40{ role: 'rowheader' }= _('Name') - .table-section.section-25{ role: 'rowheader' }= _('Created on') + .table-section.section-10{ role: 'rowheader' }= _('Projects') + .table-section.section-15{ role: 'rowheader' }= _('Created on') .table-section.section-15{ role: 'rowheader' }= _('Last activity') = render partial: 'admin/users/user', collection: @users diff --git a/app/views/groups/labels/destroy.js.haml b/app/views/groups/labels/destroy.js.haml deleted file mode 100644 index 3dfbfc77c0d..00000000000 --- a/app/views/groups/labels/destroy.js.haml +++ /dev/null @@ -1,2 +0,0 @@ -- if @group.labels.empty? - $('.labels').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000) diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml index 293500a6c31..63cc96c2c05 100644 --- a/app/views/projects/commits/_commits.html.haml +++ b/app/views/projects/commits/_commits.html.haml @@ -28,7 +28,8 @@ = render partial: 'projects/commits/commit', collection: context_commits, locals: { project: project, ref: ref, merge_request: merge_request } - if hidden > 0 - %li.alert.alert-warning + %li.gl-alert.gl-alert-warning + = sprite_icon('warning', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') = n_('%s additional commit has been omitted to prevent performance issues.', '%s additional commits have been omitted to prevent performance issues.', hidden) % number_with_delimiter(hidden) - if project.context_commits_enabled? && can_update_merge_request && context_commits&.empty? diff --git a/app/views/projects/hook_logs/show.html.haml b/app/views/projects/hook_logs/show.html.haml index 8a8c396a9e4..ebe179c3454 100644 --- a/app/views/projects/hook_logs/show.html.haml +++ b/app/views/projects/hook_logs/show.html.haml @@ -7,6 +7,6 @@ %h4.gl-mt-0 Request details .col-lg-9 - = link_to 'Resend Request', @hook_log.present.retry_path, method: :post, class: "btn btn-default float-right gl-ml-3" + = link_to 'Resend Request', @hook_log.present.retry_path, method: :post, class: "btn gl-button btn-default float-right gl-ml-3" = render partial: 'shared/hook_logs/content', locals: { hook_log: @hook_log } diff --git a/app/views/projects/settings/ci_cd/_badge.html.haml b/app/views/projects/settings/ci_cd/_badge.html.haml index 2c3e6387972..82c8ec088e5 100644 --- a/app/views/projects/settings/ci_cd/_badge.html.haml +++ b/app/views/projects/settings/ci_cd/_badge.html.haml @@ -15,18 +15,18 @@ .col-md-2.text-center Markdown .col-md-10.code.js-syntax-highlight - = highlight_badge('.md', badge.to_markdown, language: 'markdown') + = highlight('.md', badge.to_markdown, language: 'markdown') .row %hr .row .col-md-2.text-center HTML .col-md-10.code.js-syntax-highlight - = highlight_badge('.html', badge.to_html, language: 'html') + = highlight('.html', badge.to_html, language: 'html') .row %hr .row .col-md-2.text-center AsciiDoc .col-md-10.code.js-syntax-highlight - = highlight_badge('.adoc', badge.to_asciidoc) + = highlight('.adoc', badge.to_asciidoc) diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml index e0dbb5135e9..b02a147af71 100644 --- a/app/views/search/_results.html.haml +++ b/app/views/search/_results.html.haml @@ -1,4 +1,5 @@ - if @search_objects.to_a.empty? + = render partial: "search/results/filters" = render partial: "search/results/empty" = render_if_exists 'shared/promotions/promote_advanced_search' = render_if_exists 'search/form_revert_to_basic' @@ -21,8 +22,7 @@ - link_to_group = link_to(@group.name, @group, class: 'ml-md-1') = _("in group %{link_to_group}").html_safe % { link_to_group: link_to_group } = render_if_exists 'shared/promotions/promote_advanced_search' - - #js-search-filter-by-state{ 'v-cloak': true, data: { scope: @scope, state: params[:state] } } + = render partial: "search/results/filters" .results.gl-mt-3 - if @scope == 'commits' diff --git a/app/views/search/results/_filters.html.haml b/app/views/search/results/_filters.html.haml new file mode 100644 index 00000000000..8c402ddb3d1 --- /dev/null +++ b/app/views/search/results/_filters.html.haml @@ -0,0 +1,7 @@ +.d-lg-flex.align-items-end + #js-search-filter-by-state{ 'v-cloak': true, data: { scope: @scope, filter: params[:state]} } + - if Feature.enabled?(:search_filter_by_confidential, @group) + #js-search-filter-by-confidential{ 'v-cloak': true, data: { scope: @scope, filter: params[:confidential] } } + + - if %w(issues merge_requests).include?(@scope) + %hr.gl-mt-4.gl-mb-4 diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml index a101e60f297..e0336d98f04 100644 --- a/app/views/search/results/_issue.html.haml +++ b/app/views/search/results/_issue.html.haml @@ -9,5 +9,6 @@ %span.term.str-truncated.gl-font-weight-bold.gl-ml-2= issue.title .gl-text-gray-500.gl-my-3 = sprintf(s_(' %{project_name}#%{issue_iid} · opened %{issue_created} by %{author}'), { project_name: issue.project.full_name, issue_iid: issue.iid, issue_created: time_ago_with_tooltip(issue.created_at, placement: 'bottom'), author: link_to_member(@project, issue.author, avatar: false) }).html_safe - .description.term.col-sm-10.gl-px-0 - = highlight_and_truncate_issue(issue, @search_term, @search_highlight) + - if issue.description.present? + .description.term.col-sm-10.gl-px-0 + = truncate(issue.description, length: 200) |