summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-08-28 06:10:17 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-28 06:10:17 +0000
commitcf73ed7d11fdf517c230038fe8c88c96b7e3d6f0 (patch)
tree2bff9cfe778217ae462963ff4c22bb80bd274969 /app
parentc01895daab6ec8bffc5466a8330fc154fd47a726 (diff)
downloadgitlab-ce-cf73ed7d11fdf517c230038fe8c88c96b7e3d6f0.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/playable.js43
-rw-r--r--app/assets/javascripts/content_editor/extensions/audio.js8
-rw-r--r--app/assets/javascripts/content_editor/extensions/playable.js71
-rw-r--r--app/assets/javascripts/content_editor/services/create_content_editor.js2
-rw-r--r--app/assets/javascripts/content_editor/services/markdown_serializer.js11
-rw-r--r--app/assets/javascripts/content_editor/services/serialization_helpers.js11
-rw-r--r--app/assets/stylesheets/framework/typography.scss6
-rw-r--r--app/models/commit_status.rb2
-rw-r--r--app/workers/stuck_ci_jobs_worker.rb10
9 files changed, 130 insertions, 34 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/playable.js b/app/assets/javascripts/behaviors/markdown/nodes/playable.js
index 33bb6e0c31c..64bc30e1fe7 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/playable.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/playable.js
@@ -1,9 +1,7 @@
/* eslint-disable class-methods-use-this */
-/* eslint-disable @gitlab/require-i18n-strings */
import { defaultMarkdownSerializer } from 'prosemirror-markdown';
import { Node } from 'tiptap';
-import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
/**
* Abstract base class for playable media, like video and audio.
@@ -32,34 +30,34 @@ export default class Playable extends Node {
const parseDOM = [
{
- tag: `.${this.mediaType}-container`,
- skip: true,
- },
- {
- tag: `.${this.mediaType}-container p`,
- priority: HIGHER_PARSE_RULE_PRIORITY,
- ignore: true,
- },
- {
- tag: `${this.mediaType}[src]`,
- getAttrs: (el) => ({ src: el.src, alt: el.dataset.title }),
+ tag: `.media-container`,
+ getAttrs: (el) => ({
+ src: el.querySelector('audio,video').src,
+ alt: el.querySelector('audio,video').dataset.title,
+ }),
},
];
const toDOM = (node) => [
- this.mediaType,
- {
- src: node.attrs.src,
- controls: true,
- 'data-setup': '{}',
- 'data-title': node.attrs.alt,
- ...this.extraElementAttrs,
- },
+ 'span',
+ { class: 'media-container' },
+ [
+ this.options.mediaType,
+ {
+ src: node.attrs.src,
+ controls: true,
+ 'data-setup': '{}',
+ 'data-title': node.attrs.alt,
+ ...this.extraElementAttrs,
+ },
+ ],
+ ['a', { href: node.attrs.src }, node.attrs.alt],
];
return {
attrs,
- group: 'block',
+ group: 'inline',
+ inline: true,
draggable: true,
parseDOM,
toDOM,
@@ -68,6 +66,5 @@ export default class Playable extends Node {
toMarkdown(state, node) {
defaultMarkdownSerializer.nodes.image(state, node);
- state.closeBlock(node);
}
}
diff --git a/app/assets/javascripts/content_editor/extensions/audio.js b/app/assets/javascripts/content_editor/extensions/audio.js
new file mode 100644
index 00000000000..3e746a632df
--- /dev/null
+++ b/app/assets/javascripts/content_editor/extensions/audio.js
@@ -0,0 +1,8 @@
+import Playable from './playable';
+
+export default Playable.extend({
+ defaultOptions: {
+ ...Playable.options,
+ mediaType: 'audio',
+ },
+});
diff --git a/app/assets/javascripts/content_editor/extensions/playable.js b/app/assets/javascripts/content_editor/extensions/playable.js
new file mode 100644
index 00000000000..fdc8f173c81
--- /dev/null
+++ b/app/assets/javascripts/content_editor/extensions/playable.js
@@ -0,0 +1,71 @@
+import { Node } from '@tiptap/core';
+
+const queryPlayableElement = (element, mediaType) => element.querySelector(mediaType);
+
+export default Node.create({
+ name: 'playable',
+ group: 'inline',
+ inline: true,
+ draggable: true,
+
+ addAttributes() {
+ return {
+ src: {
+ default: null,
+ parseHTML: (element) => {
+ const playable = queryPlayableElement(element, this.options.mediaType);
+
+ return {
+ src: playable.src,
+ };
+ },
+ },
+ canonicalSrc: {
+ default: null,
+ parseHTML: (element) => {
+ const playable = queryPlayableElement(element, this.options.mediaType);
+
+ return {
+ canonicalSrc: playable.dataset.canonicalSrc,
+ };
+ },
+ },
+ alt: {
+ default: null,
+ parseHTML: (element) => {
+ const playable = queryPlayableElement(element, this.options.mediaType);
+
+ return {
+ alt: playable.dataset.title,
+ };
+ },
+ },
+ };
+ },
+
+ parseHTML() {
+ return [
+ {
+ tag: '.media-container',
+ },
+ ];
+ },
+
+ renderHTML({ node }) {
+ return [
+ 'span',
+ { class: 'media-container' },
+ [
+ this.options.mediaType,
+ {
+ src: node.attrs.src,
+ controls: true,
+ 'data-setup': '{}',
+ 'data-title': node.attrs.alt,
+ ...this.extraElementAttrs,
+ },
+ ],
+ ['a', { href: node.attrs.src }, node.attrs.alt],
+ ];
+ },
+});
diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js
index 67d5a00b6c6..f6aa1a1150d 100644
--- a/app/assets/javascripts/content_editor/services/create_content_editor.js
+++ b/app/assets/javascripts/content_editor/services/create_content_editor.js
@@ -2,6 +2,7 @@ import { Editor } from '@tiptap/vue-2';
import { isFunction } from 'lodash';
import { PROVIDE_SERIALIZER_OR_RENDERER_ERROR } from '../constants';
import Attachment from '../extensions/attachment';
+import Audio from '../extensions/audio';
import Blockquote from '../extensions/blockquote';
import Bold from '../extensions/bold';
import BulletList from '../extensions/bullet_list';
@@ -63,6 +64,7 @@ export const createContentEditor = ({
const builtInContentEditorExtensions = [
Attachment.configure({ uploadsPath, renderMarkdown }),
+ Audio,
Blockquote,
Bold,
BulletList,
diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js
index aca8c2c8488..c49580ee91f 100644
--- a/app/assets/javascripts/content_editor/services/markdown_serializer.js
+++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js
@@ -3,6 +3,7 @@ import {
defaultMarkdownSerializer,
} from 'prosemirror-markdown/src/to_markdown';
import { DOMParser as ProseMirrorDOMParser } from 'prosemirror-model';
+import Audio from '../extensions/audio';
import Blockquote from '../extensions/blockquote';
import Bold from '../extensions/bold';
import BulletList from '../extensions/bullet_list';
@@ -40,6 +41,8 @@ import {
openTag,
closeTag,
renderOrderedList,
+ renderImage,
+ renderPlayable,
} from './serialization_helpers';
const defaultSerializerConfig = {
@@ -92,6 +95,7 @@ const defaultSerializerConfig = {
},
nodes: {
+ [Audio.name]: renderPlayable,
[Blockquote.name]: (state, node) => {
if (node.attrs.multiline) {
state.write('>>>');
@@ -120,12 +124,7 @@ const defaultSerializerConfig = {
[HardBreak.name]: renderHardBreak,
[Heading.name]: defaultMarkdownSerializer.nodes.heading,
[HorizontalRule.name]: defaultMarkdownSerializer.nodes.horizontal_rule,
- [Image.name]: (state, node) => {
- const { alt, canonicalSrc, src, title } = node.attrs;
- const quotedTitle = title ? ` ${state.quote(title)}` : '';
-
- state.write(`![${state.esc(alt || '')}](${state.esc(canonicalSrc || src)}${quotedTitle})`);
- },
+ [Image.name]: renderImage,
[ListItem.name]: defaultMarkdownSerializer.nodes.list_item,
[OrderedList.name]: renderOrderedList,
[Paragraph.name]: defaultMarkdownSerializer.nodes.paragraph,
diff --git a/app/assets/javascripts/content_editor/services/serialization_helpers.js b/app/assets/javascripts/content_editor/services/serialization_helpers.js
index 54c51703b59..a45f76e8d47 100644
--- a/app/assets/javascripts/content_editor/services/serialization_helpers.js
+++ b/app/assets/javascripts/content_editor/services/serialization_helpers.js
@@ -286,3 +286,14 @@ export function renderHardBreak(state, node, parent, index) {
}
}
}
+
+export function renderImage(state, node) {
+ const { alt, canonicalSrc, src, title } = node.attrs;
+ const quotedTitle = title ? ` ${state.quote(title)}` : '';
+
+ state.write(`![${state.esc(alt || '')}](${state.esc(canonicalSrc || src)}${quotedTitle})`);
+}
+
+export function renderPlayable(state, node) {
+ renderImage(state, node);
+}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 00a471497e6..aeb3bb2286f 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -41,6 +41,12 @@
}
}
+ .media-container {
+ display: inline-flex;
+ flex-direction: column;
+ margin-bottom: $gl-spacing-scale-2;
+ }
+
img:not(.emoji) {
margin: 0 0 8px;
}
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 8dd650751bf..0935db279df 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -58,8 +58,8 @@ class CommitStatus < Ci::ApplicationRecord
scope :in_pipelines, ->(pipelines) { where(pipeline: pipelines) }
scope :eager_load_pipeline, -> { eager_load(:pipeline, project: { namespace: :route }) }
scope :with_pipeline, -> { joins(:pipeline) }
- scope :updated_at_before, ->(date) { where('ci_builds.updated_at < ?', date) }
scope :created_at_before, ->(date) { where('ci_builds.created_at < ?', date) }
+ scope :updated_at_before, ->(date) { where('ci_builds.updated_at < ?', date) }
scope :updated_before, ->(lookback:, timeout:) {
where('(ci_builds.created_at BETWEEN ? AND ?) AND (ci_builds.updated_at BETWEEN ? AND ?)', lookback, timeout, lookback, timeout)
}
diff --git a/app/workers/stuck_ci_jobs_worker.rb b/app/workers/stuck_ci_jobs_worker.rb
index 7754f0d2d27..ddc6e17583f 100644
--- a/app/workers/stuck_ci_jobs_worker.rb
+++ b/app/workers/stuck_ci_jobs_worker.rb
@@ -63,10 +63,12 @@ class StuckCiJobsWorker # rubocop:disable Scalability/IdempotentWorker
end
def running_timed_out_builds
- Ci::Build.running.where( # rubocop: disable CodeReuse/ActiveRecord
- 'ci_builds.updated_at < ?',
- BUILD_RUNNING_OUTDATED_TIMEOUT.ago
- )
+ if Feature.enabled?(:ci_new_query_for_running_stuck_jobs)
+ running_builds = Ci::Build.running.created_at_before(BUILD_RUNNING_OUTDATED_TIMEOUT.ago).order(created_at: :asc, project_id: :asc) # rubocop: disable CodeReuse/ActiveRecord
+ Ci::Build.id_in(running_builds).updated_at_before(BUILD_RUNNING_OUTDATED_TIMEOUT.ago)
+ else
+ Ci::Build.running.updated_at_before(BUILD_RUNNING_OUTDATED_TIMEOUT.ago)
+ end
end
def try_obtain_lease