Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-08-16 15:12:38 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-08-16 15:12:38 +0300
commit93fb07b8c9edb0f3e860d7670b47e03a136d1a57 (patch)
tree3a0def9b247850b5510e11faafd628101bb9c06f /app
parentd75ac09b4a880ba2d36d510a5720dd550b0809e9 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/blob/blob_links_tracking.js25
-rw-r--r--app/assets/javascripts/content_editor/extensions/sourcemap.js2
-rw-r--r--app/assets/javascripts/content_editor/services/markdown_serializer.js4
-rw-r--r--app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js11
-rw-r--r--app/assets/javascripts/lib/gfm/index.js8
-rw-r--r--app/assets/javascripts/pages/projects/init_blob.js9
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue5
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_item.vue3
-rw-r--r--app/assets/javascripts/repository/queries/blob_info.query.graphql1
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue5
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue25
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_assignees.vue7
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue1
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item.fragment.graphql1
-rw-r--r--app/assets/stylesheets/framework/files.scss4
-rw-r--r--app/assets/stylesheets/framework/highlight.scss55
-rw-r--r--app/assets/stylesheets/highlight/common.scss31
-rw-r--r--app/assets/stylesheets/highlight/themes/dark.scss10
-rw-r--r--app/assets/stylesheets/highlight/themes/monokai.scss10
-rw-r--r--app/assets/stylesheets/highlight/themes/none.scss10
-rw-r--r--app/assets/stylesheets/highlight/themes/solarized-dark.scss10
-rw-r--r--app/assets/stylesheets/highlight/themes/solarized-light.scss10
-rw-r--r--app/assets/stylesheets/highlight/white_base.scss10
-rw-r--r--app/assets/stylesheets/page_bundles/pipeline.scss14
-rw-r--r--app/controllers/projects/blob_controller.rb1
-rw-r--r--app/controllers/projects/tree_controller.rb1
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/graphql/types/namespace_type.rb6
-rw-r--r--app/graphql/types/project_type.rb4
-rw-r--r--app/models/approval.rb3
-rw-r--r--app/models/loose_foreign_keys/deleted_record.rb4
-rw-r--r--app/services/issues/create_service.rb2
-rw-r--r--app/views/projects/commit/_same_user_different_email_signature_badge.html.haml2
-rw-r--r--app/views/shared/_file_highlight.html.haml10
-rw-r--r--app/workers/new_issue_worker.rb10
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