diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 5dd2f9ec06b..fe160c8eb4b 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -13.25.1 +13.25.2 diff --git a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js index 6922ec9c5a5..3b9f6011c6d 100644 --- a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js +++ b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js @@ -53,9 +53,6 @@ function fixElementSource(el) { // Mermaid doesn't like `
` tags, so collapse all like tags into `
`, which is parsed correctly. const source = el.textContent?.replace(//g, '
'); - // Remove any extra spans added by the backend syntax highlighting. - Object.assign(el, { textContent: source }); - return { source }; } @@ -78,17 +75,13 @@ function renderMermaidEl(el, source) { width: '100%', }); - // Add the original source into the DOM - // to allow Copy-as-GFM to access it. - const sourceEl = document.createElement('text'); - sourceEl.textContent = source; - sourceEl.classList.add('gl-display-none'); - const wrapper = document.createElement('div'); wrapper.appendChild(iframeEl); - wrapper.appendChild(sourceEl); - el.closest('pre').replaceWith(wrapper); + // Hide the markdown but keep it "visible enough" to allow Copy-as-GFM + // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83202 + el.closest('pre').classList.add('gl-sr-only'); + el.closest('pre').parentNode.appendChild(wrapper); // Event Listeners iframeEl.addEventListener('load', () => { diff --git a/app/graphql/types/design_management/design_fields.rb b/app/graphql/types/design_management/design_fields.rb index 364f72a519f..c3a35cfe1ad 100644 --- a/app/graphql/types/design_management/design_fields.rb +++ b/app/graphql/types/design_management/design_fields.rb @@ -43,13 +43,12 @@ module Types end def image_v432x230(parent:) - version = cached_stateful_version(parent) - action = design.actions.up_to_version(version).most_recent.first + Gitlab::Graphql::Lazy.with_value(lazy_action(parent)) do |action| + # A `nil` return value indicates that the image has not been processed + next unless action&.image_v432x230&.file - # A `nil` return value indicates that the image has not been processed - return unless action.image_v432x230.file - - Gitlab::UrlBuilder.build(design, ref: version.sha, size: :v432x230) + Gitlab::UrlBuilder.build(action.design, ref: action.version.sha, size: :v432x230) + end end def event(parent:) @@ -73,6 +72,25 @@ module Types def issue ::Gitlab::Graphql::Loaders::BatchModelLoader.new(::Issue, design.issue_id).find end + + private + + def lazy_action(parent) + version = cached_stateful_version(parent) + + BatchLoader::GraphQL.for([version, design]).batch do |ids, loader| + by_version = ids.group_by(&:first).transform_values { _1.map(&:second) } + designs_by_id = ids.map(&:second).index_by(&:id) + + by_version.each do |v, designs| + actions = ::DesignManagement::Action.most_recent.up_to_version(v).by_design(designs).with_version + actions.each do |action| + action.design = designs_by_id[action.design_id] # eliminate duplicate load + loader.call([v, action.design], action) + end + end + end + end end end end diff --git a/app/models/design_management/action.rb b/app/models/design_management/action.rb index b9df2873a73..5f407a5867d 100644 --- a/app/models/design_management/action.rb +++ b/app/models/design_management/action.rb @@ -19,6 +19,7 @@ module DesignManagement scope :ordered, -> { order(version_id: :asc) } scope :by_design, -> (design) { where(design: design) } scope :by_event, -> (event) { where(event: event) } + scope :with_version, -> { preload(:version) } # For each design, only select the most recent action scope :most_recent, -> do diff --git a/config/feature_flags/development/enforce_security_report_validation.yml b/config/feature_flags/development/enforce_security_report_validation.yml index 0478033c55b..2a8d3e32ec4 100644 --- a/config/feature_flags/development/enforce_security_report_validation.yml +++ b/config/feature_flags/development/enforce_security_report_validation.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351000 milestone: '14.9' type: development group: group::threat insights -default_enabled: false +default_enabled: true diff --git a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb index cef029bd749..0accf1be970 100644 --- a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb +++ b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb @@ -110,7 +110,7 @@ module Gitlab log_warnings(problem_type: 'schema_validation_fails') unless schema_validation_errors.empty? - if Feature.enabled?(:enforce_security_report_validation, @project) + if Feature.enabled?(:enforce_security_report_validation, @project, default_enabled: :yaml) @errors += schema_validation_errors else @warnings += schema_validation_errors @@ -147,7 +147,7 @@ module Gitlab def add_unsupported_report_version_message log_warnings(problem_type: 'using_unsupported_schema_version') - if Feature.enabled?(:enforce_security_report_validation, @project) + if Feature.enabled?(:enforce_security_report_validation, @project, default_enabled: :yaml) handle_unsupported_report_version(treat_as: :error) else handle_unsupported_report_version(treat_as: :warning) diff --git a/package.json b/package.json index 2c5ccd018f8..2db4491b519 100644 --- a/package.json +++ b/package.json @@ -161,7 +161,7 @@ "prosemirror-model": "^1.16.1", "prosemirror-state": "^1.3.4", "prosemirror-tables": "^1.1.1", - "prosemirror-view": "^1.23.10", + "prosemirror-view": "^1.23.12", "raphael": "^2.2.7", "raw-loader": "^4.0.2", "rehype-raw": "^6.1.1", @@ -249,7 +249,7 @@ "prettier": "2.2.1", "prosemirror-schema-basic": "^1.1.2", "prosemirror-schema-list": "^1.1.6", - "prosemirror-test-builder": "^1.0.5", + "prosemirror-test-builder": "^1.0.6", "purgecss": "^4.0.3", "purgecss-from-html": "^4.0.3", "sass": "^1.32.12", diff --git a/spec/features/markdown/mermaid_spec.rb b/spec/features/markdown/mermaid_spec.rb index 6a91d4e03c1..4b5031892c1 100644 --- a/spec/features/markdown/mermaid_spec.rb +++ b/spec/features/markdown/mermaid_spec.rb @@ -5,6 +5,9 @@ require 'spec_helper' RSpec.describe 'Mermaid rendering', :js do let_it_be(:project) { create(:project, :public) } + let(:is_mac) { page.evaluate_script('navigator.platform').include?('Mac') } + let(:modifier_key) { is_mac ? :command : :control } + before do stub_feature_flags(sandboxed_mermaid: false) end @@ -300,6 +303,40 @@ RSpec.describe 'Mermaid rendering', :js do expect(page).not_to have_xpath("//iframe") end end + + it 'correctly copies and pastes to/from the clipboard' do + stub_feature_flags(sandboxed_mermaid: true) + + description = <<~MERMAID + ```mermaid + graph TD; + A-->B; + A-->C; + ``` + MERMAID + + issue = create(:issue, project: project, description: description) + + user = create(:user) + sign_in(user) + visit project_issue_path(project, issue) + + wait_for_requests + wait_for_mermaid + + find('pre.language-mermaid').hover + find('copy-code button').click + + sleep 2 + + find('#note-body').send_keys [modifier_key, 'v'] + + wait_for_requests + + # The codefences do actually get included, but we can't get spec to pass + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83202#note_880621264 + expect(find('#note-body').value.strip).to eq("graph TD;\n A-->B;\n A-->C;") + end end def wait_for_mermaid diff --git a/spec/frontend/behaviors/markdown/render_sandboxed_mermaid_spec.js b/spec/frontend/behaviors/markdown/render_sandboxed_mermaid_spec.js new file mode 100644 index 00000000000..b4844ebc765 --- /dev/null +++ b/spec/frontend/behaviors/markdown/render_sandboxed_mermaid_spec.js @@ -0,0 +1,31 @@ +import $ from 'jquery'; +import renderMermaid from '~/behaviors/markdown/render_sandboxed_mermaid'; + +describe('Render mermaid diagrams for Gitlab Flavoured Markdown', () => { + it('Does something', () => { + document.body.dataset.page = ''; + setFixtures(` +
+
+          
+            graph TD;
+            A-->B
+            A-->C
+            B-->D
+            C-->D
+          
+        
+ + + +
`); + const els = $('pre.js-syntax-highlight').find('.js-render-mermaid'); + + renderMermaid(els); + + jest.runAllTimers(); + expect(document.querySelector('pre.js-syntax-highlight').classList).toContain('gl-sr-only'); + }); +}); diff --git a/spec/models/design_management/action_spec.rb b/spec/models/design_management/action_spec.rb index 0a8bbc8d26e..f2b8fcaa256 100644 --- a/spec/models/design_management/action_spec.rb +++ b/spec/models/design_management/action_spec.rb @@ -49,6 +49,15 @@ RSpec.describe DesignManagement::Action do end end + describe '.with_version' do + it 'preloads the version' do + actions = described_class.with_version + + expect { actions.map(&:version) }.not_to exceed_query_limit(2) + expect(actions.count).to be > 2 + end + end + describe '.by_event' do it 'returns the actions by event type' do expect(described_class.by_event(:deletion)).to match_array([action_a_2, action_c]) diff --git a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb index f0205319983..459a30508eb 100644 --- a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb +++ b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb @@ -273,8 +273,10 @@ RSpec.describe 'Getting designs related to an issue' do end it 'returns the correct v432x230-sized design images' do + v0 = design.actions.most_recent.first.version + expect(design_nodes).to contain_exactly( - a_hash_including('imageV432x230' => design_image_url(design, ref: version.sha, size: :v432x230)), + a_hash_including('imageV432x230' => design_image_url(design, ref: v0.sha, size: :v432x230)), a_hash_including('imageV432x230' => design_image_url(second_design, ref: version.sha, size: :v432x230)) ) end @@ -323,8 +325,10 @@ RSpec.describe 'Getting designs related to an issue' do end it 'returns the correct v432x230-sized design images' do + v0 = design.actions.most_recent.first.version + expect(design_nodes).to contain_exactly( - a_hash_including('imageV432x230' => design_image_url(design, ref: version.sha, size: :v432x230)), + a_hash_including('imageV432x230' => design_image_url(design, ref: v0.sha, size: :v432x230)), a_hash_including('imageV432x230' => design_image_url(second_design, ref: version.sha, size: :v432x230)) ) end diff --git a/yarn.lock b/yarn.lock index 9196e34cf15..092596c8aa4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10121,10 +10121,10 @@ prosemirror-tables@^1.1.1: prosemirror-transform "^1.2.1" prosemirror-view "^1.13.3" -prosemirror-test-builder@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/prosemirror-test-builder/-/prosemirror-test-builder-1.0.5.tgz#d05e8f77484aef192d705c46fe648d0319d69000" - integrity sha512-mymXkqJlhcB4JtQpM5buHvfn7SawJ2vRwYzuIUMkky00ILBOPUnwUCAbjA7L8o4hsaQeyHljRCNdpjXKK8KsOw== +prosemirror-test-builder@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/prosemirror-test-builder/-/prosemirror-test-builder-1.0.6.tgz#5b3df044beee6050791e96abc80fb48e66be30ea" + integrity sha512-71pbSJqaqUJfbLwGett1yhMRQ/TV7QcOPfHvj6X9U/u/nQeZQNnsHsaVBpUeLgICADtusQSVPvyeGC0LGknwgA== dependencies: prosemirror-model "^1.0.0" prosemirror-schema-basic "^1.0.0" @@ -10137,10 +10137,10 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor dependencies: prosemirror-model "^1.0.0" -prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.23.10, prosemirror-view@^1.23.6: - version "1.23.10" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.23.10.tgz#a3fb6a7c780c8cd84488fdd451c23becab9dbefb" - integrity sha512-/p8Orb1VeJEbf7Z/BltU9GMWADZRqKlna6TlQGK1snJ6fTdLRC4f4yF2MgNK4OMQjmAwJISUtEp5+Vu5CSbR1w== +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.23.12, prosemirror-view@^1.23.6: + version "1.23.12" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.23.12.tgz#196436a964abbd25a7d8efad879575e80d286ba6" + integrity sha512-uvw9ZVz5dNDD9w1bzHkU2r4NWFlpFz85v9rCD8NAhQBau6LYhwM/crjry+C4JgeR8gy6pMXS5eJ1zhNLcK4ctQ== dependencies: prosemirror-model "^1.16.0" prosemirror-state "^1.0.0"