diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-15 00:08:06 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-15 00:08:06 +0000 |
commit | aebabf8f5a4b5b4ef68221aeb73729f91f11f98f (patch) | |
tree | 6cc4117df89eec3be7ea8cbb199515aef4622aca /app | |
parent | 67cd2904c9ebd7ba346cc92a37ac953747a3f0e5 (diff) | |
download | gitlab-ce-aebabf8f5a4b5b4ef68221aeb73729f91f11f98f.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
11 files changed, 119 insertions, 46 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_metrics.js b/app/assets/javascripts/behaviors/markdown/render_metrics.js index 9260a89bd52..37cbce46b6f 100644 --- a/app/assets/javascripts/behaviors/markdown/render_metrics.js +++ b/app/assets/javascripts/behaviors/markdown/render_metrics.js @@ -1,15 +1,12 @@ import Vue from 'vue'; -import EmbedGroup from '~/monitoring/components/embeds/embed_group.vue'; import { createStore } from '~/monitoring/stores/embed_group/'; // TODO: Handle copy-pasting - https://gitlab.com/gitlab-org/gitlab-foss/issues/64369. export default function renderMetrics(elements) { if (!elements.length) { - return; + return Promise.resolve(); } - const EmbedGroupComponent = Vue.extend(EmbedGroup); - const wrapperList = []; elements.forEach(element => { @@ -31,14 +28,20 @@ export default function renderMetrics(elements) { element.parentNode.removeChild(element); }); - wrapperList.forEach(wrapper => { - // eslint-disable-next-line no-new - new EmbedGroupComponent({ - el: wrapper, - store: createStore(), - propsData: { - urls: wrapper.urls, - }, + return import( + /* webpackChunkName: 'gfm_metrics' */ '~/monitoring/components/embeds/embed_group.vue' + ).then(({ default: EmbedGroup }) => { + const EmbedGroupComponent = Vue.extend(EmbedGroup); + + wrapperList.forEach(wrapper => { + // eslint-disable-next-line no-new + new EmbedGroupComponent({ + el: wrapper, + store: createStore(), + propsData: { + urls: wrapper.urls, + }, + }); }); }); } diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index a0305a8f52f..c72a8b2b0d0 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -13,6 +13,7 @@ import { import Editor from '../lib/editor'; import FileTemplatesBar from './file_templates/bar.vue'; import { __ } from '~/locale'; +import { extractMarkdownImagesFromEntries } from '../stores/utils'; export default { components: { @@ -26,6 +27,12 @@ export default { required: true, }, }, + data() { + return { + content: '', + images: {}, + }; + }, computed: { ...mapState('rightPane', { rightPaneIsOpen: 'isOpen', @@ -36,6 +43,7 @@ export default { 'currentActivityView', 'renderWhitespaceInCode', 'editorTheme', + 'entries', ]), ...mapGetters([ 'currentMergeRequest', @@ -136,6 +144,18 @@ export default { this.$nextTick(() => this.refreshEditorDimensions()); } }, + showContentViewer(val) { + if (!val) return; + + if (this.fileType === 'markdown') { + const { content, images } = extractMarkdownImagesFromEntries(this.file, this.entries); + this.content = content; + this.images = images; + } else { + this.content = this.file.content || this.file.raw; + this.images = {}; + } + }, }, beforeDestroy() { this.editor.dispose(); @@ -310,7 +330,8 @@ export default { ></div> <content-viewer v-if="showContentViewer" - :content="file.content || file.raw" + :content="content" + :images="images" :path="file.rawPath || file.path" :file-path="file.path" :file-size="file.size" diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js index 4e5b01596d8..56671142bd4 100644 --- a/app/assets/javascripts/ide/stores/utils.js +++ b/app/assets/javascripts/ide/stores/utils.js @@ -1,4 +1,5 @@ import { commitActionTypes, FILE_VIEW_MODE_EDITOR } from '../constants'; +import { relativePathToAbsolute, isAbsolute, isRootRelative } from '~/lib/utils/url_utility'; export const dataStructure = () => ({ id: '', @@ -274,3 +275,45 @@ export const pathsAreEqual = (a, b) => { // if the contents of a file dont end with a newline, this function adds a newline export const addFinalNewlineIfNeeded = content => content.charAt(content.length - 1) !== '\n' ? `${content}\n` : content; + +export function extractMarkdownImagesFromEntries(mdFile, entries) { + /** + * Regex to identify an image tag in markdown, like: + * + * ![img alt goes here](/img.png) + * ![img alt](../img 1/img.png "my image title") + * ![img alt](https://gitlab.com/assets/logo.svg "title here") + * + */ + const reMdImage = /!\[([^\]]*)\]\((.*?)(?:(?="|\))"([^"]*)")?\)/gi; + const prefix = 'gl_md_img_'; + const images = {}; + + let content = mdFile.content || mdFile.raw; + let i = 0; + + content = content.replace(reMdImage, (_, alt, path, title) => { + const imagePath = (isRootRelative(path) ? path : relativePathToAbsolute(path, mdFile.path)) + .substr(1) + .trim(); + + const imageContent = entries[imagePath]?.content || entries[imagePath]?.raw; + + if (!isAbsolute(path) && imageContent) { + const ext = path.includes('.') + ? path + .split('.') + .pop() + .trim() + : 'jpeg'; + const src = `data:image/${ext};base64,${imageContent}`; + i += 1; + const key = `{{${prefix}${i}}}`; + images[key] = { alt, src, title }; + return key; + } + return title ? `![${alt}](${path}"${title}")` : `![${alt}](${path})`; + }); + + return { content, images }; +} diff --git a/app/assets/javascripts/reports/accessibility_report/store/getters.js b/app/assets/javascripts/reports/accessibility_report/store/getters.js index 83e97a48e3b..9aff427e644 100644 --- a/app/assets/javascripts/reports/accessibility_report/store/getters.js +++ b/app/assets/javascripts/reports/accessibility_report/store/getters.js @@ -37,23 +37,12 @@ export const summaryStatus = state => { export const shouldRenderIssuesList = state => Object.values(state.report).some(x => Array.isArray(x) && x.length > 0); -export const unresolvedIssues = state => [ - ...state.report.existing_errors, - ...state.report.existing_warnings, - ...state.report.existing_notes, -]; - -export const resolvedIssues = state => [ - ...state.report.resolved_errors, - ...state.report.resolved_warnings, - ...state.report.resolved_notes, -]; - -export const newIssues = state => [ - ...state.report.new_errors, - ...state.report.new_warnings, - ...state.report.new_notes, -]; +// We could just map state, but we're going to iterate in the future +// to add notes and warnings to these issue lists, so I'm going to +// keep these as getters +export const unresolvedIssues = state => state.report.existing_errors; +export const resolvedIssues = state => state.report.resolved_errors; +export const newIssues = state => state.report.new_errors; // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index d0251c29fba..265ff81f39f 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -40,7 +40,6 @@ import TerraformPlan from './components/mr_widget_terraform_plan.vue'; import GroupedTestReportsApp from '../reports/components/grouped_test_reports_app.vue'; import { setFaviconOverlay } from '../lib/utils/common_utils'; import GroupedAccessibilityReportsApp from '../reports/accessibility_report/grouped_accessibility_reports_app.vue'; -import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; export default { el: '#js-vue-mr-widget', @@ -80,7 +79,6 @@ export default { TerraformPlan, GroupedAccessibilityReportsApp, }, - mixins: [glFeatureFlagsMixin()], props: { mrData: { type: Object, @@ -146,7 +144,7 @@ export default { }); }, shouldShowAccessibilityReport() { - return this.mr.accessibilityReportPath && this.glFeatures.accessibilityMergeRequestWidget; + return this.mr.accessibilityReportPath; }, }, watch: { diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue index 3f8b8cea256..fe488ab6cfa 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue @@ -39,6 +39,11 @@ export default { required: false, default: '', }, + images: { + type: Object, + required: false, + default: () => ({}), + }, }, computed: { viewer() { @@ -67,6 +72,7 @@ export default { :file-size="fileSize" :project-path="projectPath" :content="content" + :images="images" :commit-sha="commitSha" /> </div> diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue index bfd13a4b10f..1344c766e0e 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue @@ -5,6 +5,7 @@ import '~/behaviors/markdown/render_gfm'; import { GlSkeletonLoading } from '@gitlab/ui'; import axios from '~/lib/utils/axios_utils'; import { __ } from '~/locale'; +import { forEach, escape } from 'lodash'; const { CancelToken } = axios; let axiosSource; @@ -32,6 +33,11 @@ export default { type: String, required: true, }, + images: { + type: Object, + required: false, + default: () => ({}), + }, }, data() { return { @@ -76,7 +82,15 @@ export default { postOptions, ) .then(({ data }) => { - this.previewContent = data.body; + let previewContent = data.body; + forEach(this.images, ({ src, title = '', alt }, key) => { + previewContent = previewContent.replace( + key, + `<img src="${escape(src)}" title="${escape(title)}" alt="${escape(alt)}">`, + ); + }); + + this.previewContent = previewContent; this.isLoading = false; this.$nextTick(() => { diff --git a/app/controllers/projects/alert_management_controller.rb b/app/controllers/projects/alert_management_controller.rb index 086aca3f6a3..bcaaeb3c017 100644 --- a/app/controllers/projects/alert_management_controller.rb +++ b/app/controllers/projects/alert_management_controller.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class Projects::AlertManagementController < Projects::ApplicationController - before_action :ensure_list_feature_enabled, only: :index before_action :ensure_detail_feature_enabled, only: :details before_action :authorize_read_alert_management_alert! before_action do @@ -18,10 +17,6 @@ class Projects::AlertManagementController < Projects::ApplicationController private - def ensure_list_feature_enabled - render_404 unless Feature.enabled?(:alert_management_minimal, project) - end - def ensure_detail_feature_enabled render_404 unless Feature.enabled?(:alert_management_detail, project) end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 87b69291559..5613b5b9589 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -32,7 +32,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:code_navigation, @project) push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true) push_frontend_feature_flag(:merge_ref_head_comments, @project) - push_frontend_feature_flag(:accessibility_merge_request_widget, @project) push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true) end diff --git a/app/serializers/merge_request_poll_widget_entity.rb b/app/serializers/merge_request_poll_widget_entity.rb index 08255db5cbf..aad607f358a 100644 --- a/app/serializers/merge_request_poll_widget_entity.rb +++ b/app/serializers/merge_request_poll_widget_entity.rb @@ -71,6 +71,12 @@ class MergeRequestPollWidgetEntity < Grape::Entity end end + expose :accessibility_report_path do |merge_request| + if merge_request.has_accessibility_reports? + accessibility_reports_project_merge_request_path(merge_request.project, merge_request, format: :json) + end + end + expose :terraform_reports_path do |merge_request| if merge_request.has_terraform_reports? terraform_reports_project_merge_request_path(merge_request.project, merge_request, format: :json) diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index 2f33cb22502..f0e68423424 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -222,12 +222,11 @@ %span = _('Metrics') - - if Feature.enabled?(:alert_management_minimal, @project) - - if project_nav_tab?(:alert_management) - = nav_link(controller: :alert_management) do - = link_to project_alert_management_index_path(@project), title: _('Alerts'), class: 'shortcuts-tracking qa-operations-tracking-link' do - %span - = _('Alerts') + - if project_nav_tab?(:alert_management) + = nav_link(controller: :alert_management) do + = link_to project_alert_management_index_path(@project), title: _('Alerts'), class: 'shortcuts-tracking qa-operations-tracking-link' do + %span + = _('Alerts') - if project_nav_tab? :environments = render_if_exists "layouts/nav/sidebar/tracing_link" |