Read about our upcoming Code of Conduct on this issue

Commit 5e4d9729 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 954caaba1f6f
......@@ -12,6 +12,11 @@ stages:
- post-qa
- pages
# always use `gitlab-org` runners
default:
tags:
- gitlab-org
workflow:
rules:
# If `$FORCE_GITLAB_CI` is set, create a pipeline.
......
.run-dev-fixtures:
extends:
- .default-tags
- .default-retry
- .default-cache
- .default-before_script
......
.review-docs:
extends:
- .default-tags
- .default-retry
- .docs:rules:review-docs
allow_failure: true
......@@ -42,7 +41,6 @@ review-docs-cleanup:
docs lint:
extends:
- .default-tags
- .default-retry
- .docs:rules:docs-lint
image: "registry.gitlab.com/gitlab-org/gitlab-docs:lint"
......@@ -64,7 +62,6 @@ docs lint:
graphql-reference-verify:
extends:
- .default-tags
- .default-retry
- .default-cache
- .default-before_script
......
......@@ -10,7 +10,6 @@
.gitlab:assets:compile-metadata:
extends:
- .default-tags
- .default-retry
- .default-before_script
- .assets-compile-cache
......@@ -64,7 +63,6 @@ gitlab:assets:compile pull-cache:
.compile-assets-metadata:
extends:
- .default-tags
- .default-retry
- .default-before_script
- .assets-compile-cache
......@@ -122,7 +120,6 @@ compile-assets pull-cache as-if-foss:
.frontend-fixtures-base:
extends:
- .default-tags
- .default-retry
- .default-cache
- .default-before_script
......@@ -160,7 +157,6 @@ frontend-fixtures-as-if-foss:
.frontend-job-base:
extends:
- .default-tags
- .default-retry
- .default-cache
- .default-before_script
......@@ -242,7 +238,6 @@ jest-as-if-foss:
coverage-frontend:
extends:
- .default-tags
- .default-retry
- .frontend:rules:default-frontend-jobs
needs: ["jest"]
......@@ -262,7 +257,6 @@ coverage-frontend:
.qa-frontend-node:
extends:
- .default-tags
- .default-retry
- .default-cache
- .frontend:rules:qa-frontend-node
......@@ -290,7 +284,6 @@ qa-frontend-node:latest:
webpack-dev-server:
extends:
- .default-tags
- .default-retry
- .default-cache
- .frontend:rules:default-frontend-jobs
......
.default-tags:
tags:
- gitlab-org
.default-retry:
retry:
max: 2 # This is confusing but this means "3 runs at max".
......
.only-code-memory-job-base:
extends:
- .default-tags
- .default-retry
- .default-cache
- .default-before_script
......
pages:
extends:
- .default-tags
- .default-retry
- .default-cache
- .pages:rules
......
.qa-job-base:
extends:
- .default-tags
- .default-retry
stage: test
needs: []
......
......@@ -7,7 +7,6 @@
.rails-job-base:
extends:
- .default-tags
- .default-retry
- .default-cache
- .default-before_script
......
.review-docker:
extends:
- .default-tags
- .default-retry
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.6
services:
......@@ -29,7 +28,6 @@ build-qa-image:
review-cleanup:
extends:
- .default-tags
- .default-retry
- .review:rules:review-cleanup
stage: prepare
......@@ -46,7 +44,6 @@ review-cleanup:
review-build-cng:
extends:
- .default-tags
- .default-retry
- .review:rules:mr-and-schedule
image: ruby:2.6-alpine
......@@ -63,7 +60,6 @@ review-build-cng:
.review-workflow-base:
extends:
- .default-tags
- .default-retry
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
variables:
......@@ -217,7 +213,6 @@ review-performance:
parallel-spec-reports:
extends:
- .default-tags
- .review:rules:mr-only-manual
image: ruby:2.6-alpine
stage: post-qa
......@@ -244,7 +239,6 @@ parallel-spec-reports:
danger-review:
extends:
- .default-tags
- .default-retry
- .default-cache
- .review:rules:danger
......
......@@ -2,7 +2,6 @@
# rubygems.org in the future.
cache gems:
extends:
- .default-tags
- .default-retry
- .default-cache
- .default-before_script
......@@ -21,7 +20,6 @@ cache gems:
.minimal-job:
extends:
- .default-tags
- .default-retry
needs: []
......
......@@ -2,7 +2,6 @@
# This uses rules from project root `.yamllint`.
lint-ci-gitlab:
extends:
- .default-tags
- .default-retry
- .yaml:rules
image: sdesbure/yamllint:latest
......
......@@ -59,6 +59,10 @@ See the test engineering planning process and reach out to your counterpart Soft
<!-- Which leads to: in which enterprise tier should this feature go? See https://about.gitlab.com/handbook/product/pricing/#four-tiers -->
### Is this a cross-stage feature?
<!-- Communicate if this change will affect multiple Stage Groups or product areas. We recommend always start with the assumption that a feature request will have an impact into another Group. Loop in the most relevant PM and Product Designer from that Group to provide strategic support to help align the Group's broader plan and vision, as well as to avoid UX and technical debt. https://about.gitlab.com/handbook/product/#cross-stage-features -->
### Links / references
/label ~feature
import flash from '~/flash';
import $ from 'jquery';
import { sprintf, __ } from '../../locale';
import { __, sprintf } from '~/locale';
import { once } from 'lodash';
// Renders diagrams and flowcharts from text using Mermaid in any element with the
// `js-render-mermaid` class.
......@@ -18,14 +19,10 @@ import { sprintf, __ } from '../../locale';
// This is an arbitrary number; Can be iterated upon when suitable.
const MAX_CHAR_LIMIT = 5000;
let mermaidModule = {};
function renderMermaids($els) {
if (!$els.length) return;
// A diagram may have been truncated in search results which will cause errors, so abort the render.
if (document.querySelector('body').dataset.page === 'search:show') return;
import(/* webpackChunkName: 'mermaid' */ 'mermaid')
function importMermaidModule() {
return import(/* webpackChunkName: 'mermaid' */ 'mermaid')
.then(mermaid => {
mermaid.initialize({
// mermaid core options
......@@ -41,63 +38,127 @@ function renderMermaids($els) {
securityLevel: 'strict',
});
mermaidModule = mermaid;
return mermaid;
})
.catch(err => {
flash(sprintf(__("Can't load mermaid module: %{err}"), { err }));
// eslint-disable-next-line no-console
console.error(err);
});
}
function fixElementSource(el) {
// Mermaid doesn't like `<br />` tags, so collapse all like tags into `<br>`, which is parsed correctly.
const source = el.textContent.replace(/<br\s*\/>/g, '<br>');
// Remove any extra spans added by the backend syntax highlighting.
Object.assign(el, { textContent: source });
return { source };
}
function renderMermaidEl(el) {
mermaidModule.init(undefined, el, id => {
const source = el.textContent;
const svg = document.getElementById(id);
// As of https://github.com/knsv/mermaid/commit/57b780a0d,
// Mermaid will make two init callbacks:one to initialize the
// flow charts, and another to initialize the Gannt charts.
// Guard against an error caused by double initialization.
if (svg.classList.contains('mermaid')) {
return;
}
svg.classList.add('mermaid');
// pre > code > svg
svg.closest('pre').replaceWith(svg);
// We need to add the original source into the DOM to allow Copy-as-GFM
// to access it.
const sourceEl = document.createElement('text');
sourceEl.classList.add('source');
sourceEl.setAttribute('display', 'none');
sourceEl.textContent = source;
svg.appendChild(sourceEl);
});
}
function renderMermaids($els) {
if (!$els.length) return;
// A diagram may have been truncated in search results which will cause errors, so abort the render.
if (document.querySelector('body').dataset.page === 'search:show') return;
importMermaidModule()
.then(() => {
let renderedChars = 0;
$els.each((i, el) => {
// Mermaid doesn't like `<br />` tags, so collapse all like tags into `<br>`, which is parsed correctly.
const source = el.textContent.replace(/<br\s*\/>/g, '<br>');
const { source } = fixElementSource(el);
/**
* Restrict the rendering to a certain amount of character to
* prevent mermaidjs from hanging up the entire thread and
* causing a DoS.
*/
if ((source && source.length > MAX_CHAR_LIMIT) || renderedChars > MAX_CHAR_LIMIT) {
el.textContent = sprintf(
__(
'Cannot render the image. Maximum character count (%{charLimit}) has been exceeded.',
),
{ charLimit: MAX_CHAR_LIMIT },
);
const html = `
<div class="alert gl-alert gl-alert-warning alert-dismissible lazy-render-mermaid-container js-lazy-render-mermaid-container fade show" role="alert">
<div>
<div class="display-flex">
<div>${__(
'Warning: Displaying this diagram might cause performance issues on this page.',
)}</div>
<div class="gl-alert-actions">
<button class="js-lazy-render-mermaid btn gl-alert-action btn-warning btn-md new-gl-button">Display</button>
</div>
</div>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
</div>
`;
const $parent = $(el).parent();
if (!$parent.hasClass('lazy-alert-shown')) {
$parent.after(html);
$parent.addClass('lazy-alert-shown');
}
return;
}
renderedChars += source.length;
// Remove any extra spans added by the backend syntax highlighting.
Object.assign(el, { textContent: source });
mermaid.init(undefined, el, id => {
const svg = document.getElementById(id);
// As of https://github.com/knsv/mermaid/commit/57b780a0d,
// Mermaid will make two init callbacks:one to initialize the
// flow charts, and another to initialize the Gannt charts.
// Guard against an error caused by double initialization.
if (svg.classList.contains('mermaid')) {
return;
}
svg.classList.add('mermaid');
// pre > code > svg
svg.closest('pre').replaceWith(svg);
// We need to add the original source into the DOM to allow Copy-as-GFM
// to access it.
const sourceEl = document.createElement('text');
sourceEl.classList.add('source');
sourceEl.setAttribute('display', 'none');
sourceEl.textContent = source;
svg.appendChild(sourceEl);
});
renderMermaidEl(el);
});
})
.catch(err => {
flash(`Can't load mermaid module: ${err}`);
flash(sprintf(__('Encountered an error while rendering: %{err}'), { err }));
// eslint-disable-next-line no-console
console.error(err);
});
}
const hookLazyRenderMermaidEvent = once(() => {
$(document.body).on('click', '.js-lazy-render-mermaid', function eventHandler() {
const parent = $(this).closest('.js-lazy-render-mermaid-container');
const pre = parent.prev();
const el = pre.find('.js-render-mermaid');
parent.remove();
renderMermaidEl(el);
});
});
export default function renderMermaid($els) {
if (!$els.length) return;
......@@ -112,4 +173,6 @@ export default function renderMermaid($els) {
renderMermaids($(this).find('.js-render-mermaid'));
}
});
hookLazyRenderMermaidEvent();
}
......@@ -308,6 +308,7 @@ export default {
'is-added': file.tempFile,
}"
class="multi-file-editor-holder"
data-qa-selector="editor_container"
@focusout="triggerFilesChange"
></div>
<content-viewer
......
......@@ -39,6 +39,7 @@ const populateUserInfo = user => {
location: userData.location,
bio: userData.bio,
organization: userData.organization,
jobTitle: userData.job_title,
loaded: true,
});
}
......
......@@ -121,6 +121,7 @@ export default {
data-placement="bottom"
tabindex="0"
role="button"
data-qa-selector="open_in_web_ide_button"
>
{{ s__('mrWidget|Open in Web IDE') }}
</a>
......
<script>
import { GlPopover, GlSkeletonLoading } from '@gitlab/ui';
import { GlPopover, GlSkeletonLoading, GlSprintf } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarImage from '../user_avatar/user_avatar_image.vue';
import { glEmojiTag } from '../../../emoji';
import { s__ } from '~/locale';
import { isString } from 'lodash';
export default {
name: 'UserPopover',
......@@ -10,6 +12,7 @@ export default {
Icon,
GlPopover,
GlSkeletonLoading,
GlSprintf,
UserAvatarImage,
},
props: {
......@@ -45,8 +48,27 @@ export default {
nameIsLoading() {
return !this.user.name;
},
jobInfoIsLoading() {
return !this.user.loaded && this.user.organization === null;
workInformationIsLoading() {
return !this.user.loaded && this.workInformation === null;
},
workInformation() {
const { jobTitle, organization } = this.user;
if (organization && jobTitle) {
return {
message: s__('Profile|%{job_title} at %{organization}'),
placeholders: { job_title: jobTitle, organization },
};
} else if (organization) {
return organization;
} else if (jobTitle) {
return jobTitle;
}
return null;
},
workInformationShouldUseSprintf() {
return !isString(this.workInformation);
},
locationIsLoading() {
return !this.user.loaded && this.user.location === null;
......@@ -72,16 +94,30 @@ export default {
<gl-skeleton-loading v-else :lines="1" class="animation-container-small mb-1" />
</div>
<div class="text-secondary">
<div v-if="user.bio" class="js-bio d-flex mb-1">
<div v-if="user.bio" class="d-flex mb-1">
<icon name="profile" class="category-icon flex-shrink-0" />
<span class="ml-1">{{ user.bio }}</span>
<span ref="bio" class="ml-1">{{ user.bio }}</span>
</div>
<div v-if="user.organization" class="js-organization d-flex mb-1">
<icon v-show="!jobInfoIsLoading" name="work" class="category-icon flex-shrink-0" />
<span class="ml-1">{{ user.organization }}</span>
<div v-if="workInformation" class="d-flex mb-1">
<icon
v-show="!workInformationIsLoading"
name="work"
class="category-icon flex-shrink-0"
/>
<span ref="workInformation" class="ml-1">
<gl-sprintf v-if="workInformationShouldUseSprintf" :message="workInformation.message">
<template
v-for="(placeholder, slotName) in workInformation.placeholders"
v-slot:[slotName]
>
<span :key="slotName">{{ placeholder }}</span>
</template>
</gl-sprintf>
<span v-else>{{ workInformation }}</span>
</span>
</div>
<gl-skeleton-loading
v-if="jobInfoIsLoading"
v-if="workInformationIsLoading"
:lines="1"
class="animation-container-small mb-1"
/>
......
......@@ -161,13 +161,17 @@
}
.cover-controls {
position: absolute;
top: 10px;
right: 10px;
@include media-breakpoint-up(sm) {
position: absolute;
top: 1rem;
right: 1.25rem;
}
&.left {
left: 10px;
right: auto;
@include media-breakpoint-up(sm) {
left: 1.25rem;
right: auto;
}
}
}
......
......@@ -401,3 +401,21 @@
line-height: 16px;
text-align: center;
}
@mixin middle-dot-divider {
&::after {
// Duplicate `content` property used as a fallback
// scss-lint:disable DuplicateProperty
content: '\00B7'; // middle dot fallback if browser does not support alternative content
content: '\00B7' / ''; // tell screen readers to ignore the content https://www.w3.org/TR/css-content-3/#accessibility
padding: 0 0.375rem;
font-weight: $gl-font-weight-bold;
}
&:last-child {
&::after {
content: '';
padding: 0;
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment