diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-16 15:12:38 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-16 15:12:38 +0300 |
commit | 93fb07b8c9edb0f3e860d7670b47e03a136d1a57 (patch) | |
tree | 3a0def9b247850b5510e11faafd628101bb9c06f /app | |
parent | d75ac09b4a880ba2d36d510a5720dd550b0809e9 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
36 files changed, 263 insertions, 54 deletions
diff --git a/app/assets/javascripts/blob/blob_links_tracking.js b/app/assets/javascripts/blob/blob_links_tracking.js new file mode 100644 index 00000000000..9a49aa8b0fc --- /dev/null +++ b/app/assets/javascripts/blob/blob_links_tracking.js @@ -0,0 +1,25 @@ +import Tracking from '~/tracking'; + +function addBlobLinksTracking(containerSelector, eventsToTrack) { + const containerEl = document.querySelector(containerSelector); + + if (!containerEl) { + return; + } + + const eventName = 'click_link'; + const label = 'file_line_action'; + + containerEl.addEventListener('click', (e) => { + eventsToTrack.forEach((event) => { + if (e.target.matches(event.selector)) { + Tracking.event(undefined, eventName, { + label, + property: event.property, + }); + } + }); + }); +} + +export default addBlobLinksTracking; diff --git a/app/assets/javascripts/content_editor/extensions/sourcemap.js b/app/assets/javascripts/content_editor/extensions/sourcemap.js index fdac852e55c..f9de71f601b 100644 --- a/app/assets/javascripts/content_editor/extensions/sourcemap.js +++ b/app/assets/javascripts/content_editor/extensions/sourcemap.js @@ -6,6 +6,7 @@ import Code from './code'; import CodeBlockHighlight from './code_block_highlight'; import FootnoteReference from './footnote_reference'; import FootnoteDefinition from './footnote_definition'; +import Frontmatter from './frontmatter'; import Heading from './heading'; import HardBreak from './hard_break'; import HorizontalRule from './horizontal_rule'; @@ -37,6 +38,7 @@ export default Extension.create({ CodeBlockHighlight.name, FootnoteReference.name, FootnoteDefinition.name, + Frontmatter.name, HardBreak.name, Heading.name, HorizontalRule.name, diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js index 30336189d0d..472a0a4815b 100644 --- a/app/assets/javascripts/content_editor/services/markdown_serializer.js +++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js @@ -155,7 +155,7 @@ const defaultSerializerConfig = { }, inline: true, }), - [Frontmatter.name]: (state, node) => { + [Frontmatter.name]: preserveUnchanged((state, node) => { const { language } = node.attrs; const syntax = { toml: '+++', @@ -168,7 +168,7 @@ const defaultSerializerConfig = { state.ensureNewLine(); state.write(syntax); state.closeBlock(node); - }, + }), [Figure.name]: renderHTMLNode('figure'), [FigureCaption.name]: renderHTMLNode('figcaption'), [HardBreak.name]: preserveUnchanged(renderHardBreak), diff --git a/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js b/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js index d9c60ade00a..8a15633708f 100644 --- a/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js +++ b/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js @@ -185,6 +185,14 @@ const factorySpecs = { identifier: hastNode.properties.identifier, }), }, + + frontmatter: { + type: 'block', + selector: 'frontmatter', + getAttrs: (hastNode) => ({ + language: hastNode.properties.language, + }), + }, }; const SANITIZE_ALLOWLIST = ['level', 'identifier', 'numeric', 'language', 'url', 'isReference']; @@ -239,6 +247,9 @@ export default () => { 'definition', 'linkReference', 'imageReference', + 'yaml', + 'toml', + 'json', ], }); diff --git a/app/assets/javascripts/lib/gfm/index.js b/app/assets/javascripts/lib/gfm/index.js index 1ab9fc22705..eaf653e9924 100644 --- a/app/assets/javascripts/lib/gfm/index.js +++ b/app/assets/javascripts/lib/gfm/index.js @@ -2,10 +2,14 @@ import { pick } from 'lodash'; import normalize from 'mdurl/encode'; import { unified } from 'unified'; import remarkParse from 'remark-parse'; +import remarkFrontmatter from 'remark-frontmatter'; import remarkGfm from 'remark-gfm'; import remarkRehype, { all } from 'remark-rehype'; import rehypeRaw from 'rehype-raw'; +const skipFrontmatterHandler = (language) => (h, node) => + h(node.position, 'frontmatter', { language }, [{ type: 'text', value: node.value }]); + const skipRenderingHandlers = { footnoteReference: (h, node) => h(node.position, 'footnoteReference', { identifier: node.identifier, label: node.label }, []), @@ -61,12 +65,16 @@ const skipRenderingHandlers = { all(h, node), ); }, + toml: skipFrontmatterHandler('toml'), + yaml: skipFrontmatterHandler('yaml'), + json: skipFrontmatterHandler('json'), }; const createParser = ({ skipRendering = [] }) => { return unified() .use(remarkParse) .use(remarkGfm) + .use(remarkFrontmatter, ['yaml', 'toml', { type: 'json', marker: ';' }]) .use(remarkRehype, { allowDangerousHtml: true, handlers: { diff --git a/app/assets/javascripts/pages/projects/init_blob.js b/app/assets/javascripts/pages/projects/init_blob.js index 7db34816cfe..f7849e8d588 100644 --- a/app/assets/javascripts/pages/projects/init_blob.js +++ b/app/assets/javascripts/pages/projects/init_blob.js @@ -4,6 +4,7 @@ import BlobForkSuggestion from '~/blob/blob_fork_suggestion'; import BlobLinePermalinkUpdater from '~/blob/blob_line_permalink_updater'; import LineHighlighter from '~/blob/line_highlighter'; import initBlobBundle from '~/blob_edit/blob_bundle'; +import addBlobLinksTracking from '~/blob/blob_links_tracking'; export default () => { new LineHighlighter(); // eslint-disable-line no-new @@ -11,10 +12,16 @@ export default () => { // eslint-disable-next-line no-new new BlobLinePermalinkUpdater( document.querySelector('#blob-content-holder'), - '.diff-line-num[data-line-number], .diff-line-num[data-line-number] *', + '.file-line-num[data-line-number], .file-line-num[data-line-number] *', document.querySelectorAll('.js-data-file-blob-permalink-url, .js-blob-blame-link'), ); + const eventsToTrack = [ + { selector: '.file-line-blame', property: 'blame' }, + { selector: '.file-line-num', property: 'link' }, + ]; + addBlobLinksTracking('#blob-content-holder', eventsToTrack); + const fileBlobPermalinkUrlElement = document.querySelector('.js-data-file-blob-permalink-url'); const fileBlobPermalinkUrl = fileBlobPermalinkUrlElement && fileBlobPermalinkUrlElement.getAttribute('href'); diff --git a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue index 795ba91a164..8d764fad0c5 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue @@ -46,6 +46,9 @@ export default { const { name, status } = this.group; return `${name} - ${status.label}`; }, + jobGroupClasses() { + return [this.cssClassJobName, `job-${this.group.status.group}`]; + }, }, errorCaptured(err, _vm, info) { reportToSentry('job_group_dropdown', `error: ${err}, info: ${info}`); @@ -68,7 +71,7 @@ export default { type="button" data-toggle="dropdown" data-display="static" - :class="cssClassJobName" + :class="jobGroupClasses" class="dropdown-menu-toggle gl-pipeline-job-width! gl-pr-4!" > <div class="gl-display-flex gl-align-items-stretch gl-justify-content-space-between"> diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue index 362571930d6..377f21b299f 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_item.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue @@ -200,6 +200,9 @@ export default { }, { 'gl-rounded-lg': this.isBridge }, this.cssClassJobName, + { + [`job-${this.status.group}`]: this.isSingleItem, + }, ]; }, }, diff --git a/app/assets/javascripts/repository/queries/blob_info.query.graphql b/app/assets/javascripts/repository/queries/blob_info.query.graphql index 8baee80e5d6..45a7793e559 100644 --- a/app/assets/javascripts/repository/queries/blob_info.query.graphql +++ b/app/assets/javascripts/repository/queries/blob_info.query.graphql @@ -27,6 +27,7 @@ query getBlobInfo( fileType language path + blamePath editBlobPath gitpodBlobUrl ideEditPath diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue index 6babbca58c3..9683288f937 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue +++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue @@ -51,6 +51,10 @@ export default { required: false, default: null, }, + blamePath: { + type: String, + required: true, + }, }, computed: { lines() { @@ -76,6 +80,7 @@ export default { :number="startingFrom + index + 1" :content="line" :language="language" + :blame-path="blamePath" /> </div> <div v-else class="gl-display-flex"> diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue index a689433b503..257b9f57222 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue +++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue @@ -1,5 +1,6 @@ <script> import { GlSafeHtmlDirective } from '@gitlab/ui'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { setAttributes } from '~/lib/utils/dom_utils'; import { BIDI_CHARS, BIDI_CHARS_CLASS_LIST, BIDI_CHAR_TOOLTIP } from '../constants'; @@ -7,6 +8,7 @@ export default { directives: { SafeHtml: GlSafeHtmlDirective, }, + mixins: [glFeatureFlagMixin()], props: { number: { type: Number, @@ -20,6 +22,10 @@ export default { type: String, required: true, }, + blamePath: { + type: String, + required: true, + }, }, computed: { formattedContent() { @@ -33,9 +39,6 @@ export default { return content; }, - firstLineClass() { - return { 'gl-mt-3!': this.number === 1 }; - }, }, methods: { wrapBidiChar(bidiChar) { @@ -56,22 +59,26 @@ export default { </script> <template> <div class="gl-display-flex"> - <div class="gl-p-0! gl-absolute gl-z-index-3 gl-border-r diff-line-num line-numbers"> + <div + class="gl-p-0! gl-absolute gl-z-index-3 diff-line-num gl-border-r gl-display-flex line-links line-numbers" + > + <a + v-if="glFeatures.fileLineBlame" + class="gl-user-select-none gl-shadow-none! file-line-blame" + :href="`${blamePath}#L${number}`" + ></a> <a :id="`L${number}`" - class="gl-user-select-none gl-ml-5 gl-pr-3 gl-shadow-none! file-line-num diff-line-num" - :class="firstLineClass" + class="gl-user-select-none gl-shadow-none! file-line-num" :href="`#L${number}`" :data-line-number="number" - data-testid="line-number-anchor" > {{ number }} </a> </div> <pre - class="gl-p-0! gl-w-full gl-overflow-visible! gl-ml-11! gl-border-none! code highlight gl-line-height-normal" - :class="firstLineClass" + class="gl-p-0! gl-w-full gl-overflow-visible! gl-border-none! code highlight gl-line-height-normal" ><code><span :id="`LC${number}`" v-safe-html="formattedContent" :lang="language" class="line" data-testid="content"></span></code></pre> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue index 1bdae40332f..ccc8b44942a 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue @@ -199,6 +199,7 @@ export default { :starting-from="firstChunk.startingFrom" :is-highlighted="firstChunk.isHighlighted" :language="firstChunk.language" + :blame-path="blob.blamePath" /> <gl-loading-icon v-if="isLoading" size="sm" class="gl-my-5" /> @@ -213,6 +214,7 @@ export default { :is-highlighted="chunk.isHighlighted" :chunk-index="index" :language="chunk.language" + :blame-path="blob.blamePath" @appear="highlightChunk" /> </div> diff --git a/app/assets/javascripts/work_items/components/work_item_assignees.vue b/app/assets/javascripts/work_items/components/work_item_assignees.vue index fcf2bfdba80..7342f215b5e 100644 --- a/app/assets/javascripts/work_items/components/work_item_assignees.vue +++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue @@ -75,6 +75,11 @@ export default { required: false, default: false, }, + canInviteMembers: { + type: Boolean, + required: false, + default: false, + }, }, data() { return { @@ -321,7 +326,7 @@ export default { <rect width="280" height="20" x="10" y="130" rx="4" /> </gl-skeleton-loader> </template> - <template #dropdown-footer> + <template v-if="canInviteMembers" #dropdown-footer> <gl-dropdown-divider /> <gl-dropdown-item @click="closeDropdown"> <invite-members-trigger diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index 7b3eeab649b..8e862aa8b32 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -319,6 +319,7 @@ export default { :assignees="workItemAssignees.assignees.nodes" :allows-multiple-assignees="workItemAssignees.allowsMultipleAssignees" :work-item-type="workItemType" + :can-invite-members="workItemAssignees.canInviteMembers" @error="error = $event" /> <work-item-labels diff --git a/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql b/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql index fd6a71ae9b4..e8ef27ec778 100644 --- a/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql +++ b/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql @@ -24,6 +24,7 @@ fragment WorkItem on WorkItem { ... on WorkItemWidgetAssignees { type allowsMultipleAssignees + canInviteMembers assignees { nodes { ...User diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index c33882a9ca4..b980d7fdaa7 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -202,6 +202,10 @@ float: none; border-left: 1px solid $gray-100; + .file-line-num { + @include gl-min-w-9; + } + i { float: none; margin-right: 0; diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss index 4c5d8628696..2b76e70fa17 100644 --- a/app/assets/stylesheets/framework/highlight.scss +++ b/app/assets/stylesheets/framework/highlight.scss @@ -49,8 +49,9 @@ a { font-family: $monospace-font; - display: block; white-space: nowrap; + @include gl-display-flex; + @include gl-justify-content-end; i, svg { @@ -91,3 +92,55 @@ td.line-numbers { cursor: pointer; text-decoration: underline wavy $red-500; } + +.blob-viewer { + .line-numbers { + // for server-side-rendering + .line-links { + @include gl-display-flex; + + + &:first-child { + margin-top: 10px; + } + + &:last-child { + margin-bottom: 10px; + } + } + + // for client + &.line-links { + min-width: 6rem; + border-bottom-left-radius: 0; + + + pre { + margin-left: 6rem; + } + } + } + + .line-links { + &:hover a::before, + &:focus-within a::before { + @include gl-visibility-visible; + } + } + + .file-line-num { + min-width: 4.5rem; + @include gl-justify-content-end; + @include gl-flex-grow-1; + @include gl-pr-3; + } + + .file-line-blame { + @include gl-ml-3; + } + + .file-line-num, + .file-line-blame { + @include gl-align-items-center; + @include gl-display-flex; + } +} diff --git a/app/assets/stylesheets/highlight/common.scss b/app/assets/stylesheets/highlight/common.scss index fcbd05141b9..96df8487c0e 100644 --- a/app/assets/stylesheets/highlight/common.scss +++ b/app/assets/stylesheets/highlight/common.scss @@ -98,32 +98,33 @@ } } -@mixin line-number-link($color) { - min-width: $gl-spacing-scale-9; +@mixin line-link($color, $icon) { &::before { - @include gl-display-none; + @include gl-visibility-hidden; @include gl-align-self-center; - @include gl-mt-2; - @include gl-mr-2; - @include gl-w-4; - @include gl-h-4; - @include gl-absolute; - @include gl-left-3; - background-color: $color; - mask-image: asset_url('icons-stacked.svg#link'); + @include gl-mr-1; + @include gl-w-5; + @include gl-h-5; + background-color: rgba($color, 0.3); + mask-image: asset_url('icons-stacked.svg##{$icon}'); mask-repeat: no-repeat; mask-size: cover; mask-position: center; content: ''; } - &:hover::before { - @include gl-display-inline-block; + &:hover { + &::before { + background-color: rgba($color, 0.6); + } } +} - &:focus::before { - @include gl-display-inline-block; +@mixin line-hover-bg($color: $white-normal) { + &:hover, + &:focus-within { + background-color: darken($color, 10); } } diff --git a/app/assets/stylesheets/highlight/themes/dark.scss b/app/assets/stylesheets/highlight/themes/dark.scss index 709e7f5ae18..5e6e10e44be 100644 --- a/app/assets/stylesheets/highlight/themes/dark.scss +++ b/app/assets/stylesheets/highlight/themes/dark.scss @@ -127,7 +127,15 @@ $dark-il: #de935f; .code.dark { // Line numbers .file-line-num { - @include line-number-link($dark-line-num-color); + @include line-link($white, 'link'); + } + + .file-line-blame { + @include line-link($white, 'git'); + } + + .line-links { + @include line-hover-bg($dark-main-bg); } .line-numbers, diff --git a/app/assets/stylesheets/highlight/themes/monokai.scss b/app/assets/stylesheets/highlight/themes/monokai.scss index 0ed9c209417..19c3d6926e7 100644 --- a/app/assets/stylesheets/highlight/themes/monokai.scss +++ b/app/assets/stylesheets/highlight/themes/monokai.scss @@ -120,7 +120,15 @@ $monokai-gh: #75715e; // Line numbers .file-line-num { - @include line-number-link($monokai-line-num-color); + @include line-link($white, 'link'); + } + + .file-line-blame { + @include line-link($white, 'git'); + } + + .line-links { + @include line-hover-bg($monokai-bg); } .line-numbers, diff --git a/app/assets/stylesheets/highlight/themes/none.scss b/app/assets/stylesheets/highlight/themes/none.scss index 868e466b1f8..4c716d20ddf 100644 --- a/app/assets/stylesheets/highlight/themes/none.scss +++ b/app/assets/stylesheets/highlight/themes/none.scss @@ -25,7 +25,15 @@ // Line numbers .file-line-num { - @include line-number-link($black-transparent); + @include line-link($black, 'link'); + } + + .file-line-blame { + @include line-link($black, 'git'); + } + + .line-links { + @include line-hover-bg; } .line-numbers, diff --git a/app/assets/stylesheets/highlight/themes/solarized-dark.scss b/app/assets/stylesheets/highlight/themes/solarized-dark.scss index 6260339a48d..70086be1606 100644 --- a/app/assets/stylesheets/highlight/themes/solarized-dark.scss +++ b/app/assets/stylesheets/highlight/themes/solarized-dark.scss @@ -123,7 +123,15 @@ $solarized-dark-il: #2aa198; // Line numbers .file-line-num { - @include line-number-link($solarized-dark-line-color); + @include line-link($white, 'link'); + } + + .file-line-blame { + @include line-link($white, 'git'); + } + + .line-links { + @include line-hover-bg($solarized-dark-pre-bg); } .line-numbers, diff --git a/app/assets/stylesheets/highlight/themes/solarized-light.scss b/app/assets/stylesheets/highlight/themes/solarized-light.scss index e6f098f4cdf..8d223d1fdb1 100644 --- a/app/assets/stylesheets/highlight/themes/solarized-light.scss +++ b/app/assets/stylesheets/highlight/themes/solarized-light.scss @@ -109,7 +109,15 @@ $solarized-light-il: #2aa198; @include hljs-override('title.class_.inherited__', $solarized-light-no); // Line numbers .file-line-num { - @include line-number-link($solarized-light-line-color); + @include line-link($black, 'link'); + } + + .file-line-blame { + @include line-link($black, 'git'); + } + + .line-links { + @include line-hover-bg($solarized-light-pre-bg); } .line-numbers, diff --git a/app/assets/stylesheets/highlight/white_base.scss b/app/assets/stylesheets/highlight/white_base.scss index 770a90bbc57..9761e3961dd 100644 --- a/app/assets/stylesheets/highlight/white_base.scss +++ b/app/assets/stylesheets/highlight/white_base.scss @@ -95,7 +95,15 @@ $white-gc-bg: #eaf2f5; // Line numbers .file-line-num { - @include line-number-link($black-transparent); + @include line-link($black, 'link'); +} + +.file-line-blame { + @include line-link($black, 'git'); +} + +.line-links { + @include line-hover-bg; } .line-numbers, diff --git a/app/assets/stylesheets/page_bundles/pipeline.scss b/app/assets/stylesheets/page_bundles/pipeline.scss index 59d2c1bb6e6..98e9e2b3c27 100644 --- a/app/assets/stylesheets/page_bundles/pipeline.scss +++ b/app/assets/stylesheets/page_bundles/pipeline.scss @@ -228,3 +228,17 @@ .progress-bar.bg-primary { background-color: var(--blue-500, $blue-500) !important; } + +.ci-job-component { + .job-failed { + background-color: var(--red-50, $red-50); + } +} + +.gl-dark { + .ci-job-component { + .job-failed { + background-color: var(--gray-200, $gray-200); + } + } +} diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 97aae56c4ec..f5188e28b81 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -43,6 +43,7 @@ class Projects::BlobController < Projects::ApplicationController before_action do push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:file_line_blame, @project) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index ce51cbb6677..fea2689db14 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -19,6 +19,7 @@ class Projects::TreeController < Projects::ApplicationController before_action do push_frontend_feature_flag(:lazy_load_commits, @project) push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:file_line_blame, @project) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 55e4b37c34c..8a6bcb4b3fc 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -37,6 +37,7 @@ class ProjectsController < Projects::ApplicationController before_action do push_frontend_feature_flag(:lazy_load_commits, @project) push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:file_line_blame, @project) push_frontend_feature_flag(:increase_page_size_exponentially, @project) push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks) push_licensed_feature(:security_orchestration_policies) if @project.present? && @project.licensed_feature_available?(:security_orchestration_policies) diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index 8a50dae4a3e..0f634e7c2d3 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -61,10 +61,14 @@ module Types Types::TimeTracking::TimelogCategoryType.connection_type, null: true, description: "Timelog categories for the namespace.", - _deprecated_feature_flag: :timelog_categories + alpha: { milestone: '15.3' } markdown_field :description_html, null: true + def timelog_categories + object.timelog_categories if Feature.enabled?(:timelog_categories) + end + def cross_project_pipeline_available? object.licensed_feature_available?(:cross_project_pipelines) end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 668b3ec548b..ecc6c9d7811 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -442,14 +442,14 @@ module Types Types::TimeTracking::TimelogCategoryType.connection_type, null: true, description: "Timelog categories for the project.", - _deprecated_feature_flag: :timelog_categories + alpha: { milestone: '15.3' } field :fork_targets, Types::NamespaceType.connection_type, resolver: Resolvers::Projects::ForkTargetsResolver, description: 'Namespaces in which the current user can fork the project into.' def timelog_categories - object.project_namespace.timelog_categories + object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories) end def label(title:) diff --git a/app/models/approval.rb b/app/models/approval.rb index 899ea466315..9ded44fe425 100644 --- a/app/models/approval.rb +++ b/app/models/approval.rb @@ -2,11 +2,12 @@ class Approval < ApplicationRecord include CreatedAtFilterable + include Importable belongs_to :user belongs_to :merge_request - validates :merge_request_id, presence: true + validates :merge_request_id, presence: true, unless: :importing? validates :user_id, presence: true, uniqueness: { scope: [:merge_request_id] } scope :with_user, -> { joins(:user) } diff --git a/app/models/loose_foreign_keys/deleted_record.rb b/app/models/loose_foreign_keys/deleted_record.rb index 8534e26e8ff..94444f4b6d3 100644 --- a/app/models/loose_foreign_keys/deleted_record.rb +++ b/app/models/loose_foreign_keys/deleted_record.rb @@ -10,8 +10,6 @@ class LooseForeignKeys::DeletedRecord < Gitlab::Database::SharedModel partitioned_by :partition, strategy: :sliding_list, next_partition_if: -> (active_partition) do - return false if Feature.disabled?(:lfk_automatic_partition_creation) - oldest_record_in_partition = LooseForeignKeys::DeletedRecord .select(:id, :created_at) .for_partition(active_partition) @@ -23,8 +21,6 @@ class LooseForeignKeys::DeletedRecord < Gitlab::Database::SharedModel oldest_record_in_partition.created_at < PARTITION_DURATION.ago end, detach_partition_if: -> (partition) do - return false if Feature.disabled?(:lfk_automatic_partition_dropping) - !LooseForeignKeys::DeletedRecord .for_partition(partition) .status_pending diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb index 30d4cb68840..92cf4811439 100644 --- a/app/services/issues/create_service.rb +++ b/app/services/issues/create_service.rb @@ -45,7 +45,7 @@ module Issues # current_user (defined in BaseService) is not available within run_after_commit block user = current_user issue.run_after_commit do - NewIssueWorker.perform_async(issue.id, user.id) + NewIssueWorker.perform_async(issue.id, user.id, issue.class.to_s) Issues::PlacementWorker.perform_async(nil, issue.project_id) Namespaces::OnboardingIssueCreatedWorker.perform_async(issue.project.namespace_id) end diff --git a/app/views/projects/commit/_same_user_different_email_signature_badge.html.haml b/app/views/projects/commit/_same_user_different_email_signature_badge.html.haml index e56579b162f..629d3cfaf74 100644 --- a/app/views/projects/commit/_same_user_different_email_signature_badge.html.haml +++ b/app/views/projects/commit/_same_user_different_email_signature_badge.html.haml @@ -1,5 +1,5 @@ - title = capture do - = html_escape(_('This commit was signed with a verified signature, but the committer email is %{strong_open}not verified%{strong_close} to belong to the same user.')) % { strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe } + = html_escape(_('This commit was signed with a verified signature, but the committer email is not associated with the GPG Key.')) - locals = { signature: signature, title: title, label: _('Unverified'), css_class: ['invalid'], icon: 'status_notfound_borderless', show_user: true } diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index f8ac3832a77..23a17c07ea8 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -1,13 +1,17 @@ #blob-content.file-content.code.js-syntax-highlight - offset = defined?(first_line_number) ? first_line_number : 1 - .line-numbers + .line-numbers{ class: "gl-p-0\!" } - if blob.data.present? - link = blob_link if defined?(blob_link) + - blame_link = project_blame_path(@project, tree_join(@ref, blob.path)) - blob.data.each_line.each_with_index do |_, index| - i = index + offset -# We're not using `link_to` because it is too slow once we get to thousands of lines. - %a.file-line-num.diff-line-num{ href: "#{link}#L#{i}", id: "L#{i}", 'data-line-number' => i } - = i + .line-links.diff-line-num + - if Feature.enabled?(:file_line_blame) + %a.file-line-blame{ href: "#{blame_link}#L#{i}" } + %a.file-line-num{ href: "#{link}#L#{i}", id: "L#{i}", 'data-line-number' => i } + = i - highlight = defined?(highlight_line) && highlight_line ? highlight_line - offset : nil .blob-content{ data: { blob_id: blob.id, path: blob.path, highlight_line: highlight, qa_selector: 'file_content' } } %pre.code.highlight diff --git a/app/workers/new_issue_worker.rb b/app/workers/new_issue_worker.rb index 13936fac1e4..e14f0dc7dfe 100644 --- a/app/workers/new_issue_worker.rb +++ b/app/workers/new_issue_worker.rb @@ -13,7 +13,11 @@ class NewIssueWorker # rubocop:disable Scalability/IdempotentWorker worker_resource_boundary :cpu weight 2 - def perform(issue_id, user_id) + attr_reader :issuable_class + + def perform(issue_id, user_id, issuable_class = 'Issue') + @issuable_class = issuable_class.constantize + return unless objects_found?(issue_id, user_id) ::EventCreateService.new.open_issue(issuable, user) @@ -25,8 +29,4 @@ class NewIssueWorker # rubocop:disable Scalability/IdempotentWorker .new(project: issuable.project, current_user: user) .execute(issuable) end - - def issuable_class - Issue - end end |