diff options
Diffstat (limited to 'app')
20 files changed, 146 insertions, 74 deletions
diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_export.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_export.vue deleted file mode 100644 index 4d13f25c4cb..00000000000 --- a/app/assets/javascripts/pages/shared/wikis/components/wiki_export.vue +++ /dev/null @@ -1,40 +0,0 @@ -<script> -import { GlDisclosureDropdown } from '@gitlab/ui'; -import { __ } from '~/locale'; -import printMarkdownDom from '~/lib/print_markdown_dom'; - -export default { - components: { - GlDisclosureDropdown, - }, - inject: ['target', 'title', 'stylesheet'], - computed: { - dropdownItems() { - return [ - { - text: __('Print as PDF'), - action: this.print, - }, - ]; - }, - }, - methods: { - print() { - printMarkdownDom({ - target: document.querySelector(this.target), - title: this.title, - stylesheet: this.stylesheet, - }); - }, - }, -}; -</script> -<template> - <gl-disclosure-dropdown - :items="dropdownItems" - icon="ellipsis_v" - category="tertiary" - placement="right" - no-caret - /> -</template> diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_more_dropdown.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_more_dropdown.vue new file mode 100644 index 00000000000..18b11d46bca --- /dev/null +++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_more_dropdown.vue @@ -0,0 +1,58 @@ +<script> +import { GlDisclosureDropdown } from '@gitlab/ui'; +import { s__, __ } from '~/locale'; +import printMarkdownDom from '~/lib/print_markdown_dom'; + +export default { + components: { + GlDisclosureDropdown, + }, + inject: ['print', 'history'], + computed: { + dropdownItems() { + const items = []; + + if (this.history) { + items.push({ + text: s__('Wiki|Page history'), + href: this.history, + extraAttrs: { + 'data-testid': 'page-history-button', + }, + }); + } + + if (this.print) { + items.push({ + text: __('Print as PDF'), + action: this.printPage, + extraAttrs: { + 'data-testid': 'page-print-button', + }, + }); + } + + return items; + }, + }, + methods: { + printPage() { + printMarkdownDom({ + target: document.querySelector(this.print.target), + title: this.print.title, + stylesheet: this.print.stylesheet, + }); + }, + }, +}; +</script> +<template> + <gl-disclosure-dropdown + :items="dropdownItems" + icon="ellipsis_v" + category="tertiary" + placement="right" + no-caret + data-testid="wiki-more-dropdown" + /> +</template> diff --git a/app/assets/javascripts/pages/shared/wikis/show.js b/app/assets/javascripts/pages/shared/wikis/show.js index 9bc399d07b3..89ed395f742 100644 --- a/app/assets/javascripts/pages/shared/wikis/show.js +++ b/app/assets/javascripts/pages/shared/wikis/show.js @@ -1,7 +1,7 @@ import Vue from 'vue'; import Wikis from './wikis'; import WikiContent from './components/wiki_content.vue'; -import WikiExport from './components/wiki_export.vue'; +import WikiMoreDropdown from './components/wiki_more_dropdown.vue'; const mountWikiContentApp = () => { const el = document.querySelector('.js-async-wiki-page-content'); @@ -25,17 +25,16 @@ const mountWikiExportApp = () => { const el = document.querySelector('#js-export-actions'); if (!el) return false; - const { target, title, stylesheet } = JSON.parse(el.dataset.options); + const { history, print } = JSON.parse(el.dataset.options); return new Vue({ el, provide: { - target, - title, - stylesheet, + history, + print, }, render(createElement) { - return createElement(WikiExport); + return createElement(WikiMoreDropdown); }, }); }; diff --git a/app/assets/stylesheets/page_bundles/wiki.scss b/app/assets/stylesheets/page_bundles/wiki.scss index 4572e71e751..ed2c7662a98 100644 --- a/app/assets/stylesheets/page_bundles/wiki.scss +++ b/app/assets/stylesheets/page_bundles/wiki.scss @@ -90,8 +90,6 @@ } a { - color: var(--gray-400, $gray-400); - &:hover, &.active { text-decoration: none; @@ -103,18 +101,16 @@ } .active > .wiki-list { - a, - .wiki-list-expand-button, - .wiki-list-collapse-button { - color: var(--gl-text-color, $gl-text-color); - } + background-color: $gray-50; } .wiki-list { - min-height: $gl-spacing-scale-8; + padding: $gl-spacing-scale-2 $gl-spacing-scale-3; + margin-bottom: $gl-spacing-scale-1; + @include gl-rounded-base; &:hover { - background: $gray-10; + background: $gray-50; .wiki-list-create-child-button { display: block; @@ -148,8 +144,7 @@ margin: 0; } - ul.wiki-pages ul, - ul.wiki-pages li:not(.wiki-directory){ + ul.wiki-pages ul { padding-left: 20px; } diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index fb73cb55ec0..8536f790b7d 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -184,6 +184,10 @@ module Ci scope :without_coverage, -> { where(coverage: nil) } scope :with_coverage_regex, -> { where.not(coverage_regex: nil) } + scope :in_merge_request, ->(merge_request) do + joins(:pipeline).where(Ci::Pipeline.arel_table[:merge_request_id].eq(merge_request)) + end + acts_as_taggable add_authentication_token_field :token, @@ -367,6 +371,10 @@ module Ci end end + def self.ids_in_merge_request(merge_request_ids) + in_merge_request(merge_request_ids).pluck(:id) + end + def build_matcher strong_memoize(:build_matcher) do Gitlab::Ci::Matching::BuildMatcher.new({ diff --git a/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb b/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb index dfcc905b3c3..618ea7d979c 100644 --- a/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb +++ b/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb @@ -111,7 +111,8 @@ module Analytics :author_id, :state_id, :start_event_timestamp, - :end_event_timestamp + :end_event_timestamp, + :duration_in_milliseconds ] end @@ -125,7 +126,8 @@ module Analytics :author_id, :state_id, :start_event_timestamp, - :end_event_timestamp + :end_event_timestamp, + :duration_in_milliseconds ] end diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb index 15ed517dc12..6bcfd23e69c 100644 --- a/app/models/container_repository.rb +++ b/app/models/container_repository.rb @@ -656,7 +656,7 @@ class ContainerRepository < ApplicationRecord tag.updated_at = raw_tag['updated_at'] tag.total_size = raw_tag['size_bytes'] tag.manifest_digest = raw_tag['digest'] - tag.revision = raw_tag['config_digest'].to_s.split(':')[1] + tag.revision = raw_tag['config_digest'].to_s.split(':')[1] || '' tag end end diff --git a/app/models/pages_deployment.rb b/app/models/pages_deployment.rb index 0d87a8f6cf6..e8b186234af 100644 --- a/app/models/pages_deployment.rb +++ b/app/models/pages_deployment.rb @@ -20,6 +20,7 @@ class PagesDeployment < ApplicationRecord scope :with_files_stored_locally, -> { where(file_store: ::ObjectStorage::Store::LOCAL) } scope :with_files_stored_remotely, -> { where(file_store: ::ObjectStorage::Store::REMOTE) } scope :project_id_in, ->(ids) { where(project_id: ids) } + scope :ci_build_id_in, ->(ids) { where(ci_build_id: ids) } scope :with_path_prefix, ->(prefix) { where("COALESCE(path_prefix, '') = ?", prefix.to_s) } # We have to mark the PagesDeployment upload as ready to ensure we only @@ -28,6 +29,7 @@ class PagesDeployment < ApplicationRecord scope :active, -> { upload_ready.where(deleted_at: nil).order(created_at: :desc) } scope :deactivated, -> { where('deleted_at < ?', Time.now.utc) } + scope :versioned, -> { where.not(path_prefix: [nil, '']) } validates :file, presence: true validates :file_store, presence: true, inclusion: { in: ObjectStorage::SUPPORTED_STORES } @@ -62,6 +64,10 @@ class PagesDeployment < ApplicationRecord .update_all(updated_at: now, deleted_at: time || now) end + def self.deactivate + update(deleted_at: Time.now.utc) + end + private def set_size diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index f36cad7139a..f5c5dceb611 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -119,6 +119,10 @@ module MergeRequests Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter end + def deactivate_pages_deployments(merge_request) + Pages::DeactivateMrDeploymentsWorker.perform_async(merge_request) + end + private def self.constructor_container_arg(value) diff --git a/app/services/merge_requests/close_service.rb b/app/services/merge_requests/close_service.rb index 62928e05a89..42f5a8fd7ba 100644 --- a/app/services/merge_requests/close_service.rb +++ b/app/services/merge_requests/close_service.rb @@ -22,6 +22,7 @@ module MergeRequests invalidate_cache_counts(merge_request, users: merge_request.assignees | merge_request.reviewers) merge_request.update_project_counter_caches cleanup_environments(merge_request) + deactivate_pages_deployments(merge_request) abort_auto_merge(merge_request, 'merge request was closed') cleanup_refs(merge_request) trigger_merge_request_merge_status_updated(merge_request) diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb index e32895a3cb6..d2bfadc2205 100644 --- a/app/services/merge_requests/post_merge_service.rb +++ b/app/services/merge_requests/post_merge_service.rb @@ -32,6 +32,7 @@ module MergeRequests cancel_review_app_jobs!(merge_request) cleanup_environments(merge_request) cleanup_refs(merge_request) + deactivate_pages_deployments(merge_request) execute_hooks(merge_request, 'merge') end diff --git a/app/views/shared/wikis/_main_links.html.haml b/app/views/shared/wikis/_main_links.html.haml index 9a76069e8f6..2b9a64d6d04 100644 --- a/app/views/shared/wikis/_main_links.html.haml +++ b/app/views/shared/wikis/_main_links.html.haml @@ -1,6 +1,4 @@ - if @page&.persisted? - = link_button_to wiki_page_path(@wiki, @page, action: :history), role: "button", data: { testid: 'page-history-button' } do - = s_("Wiki|Page history") - if can?(current_user, :create_wiki, @wiki.container) = link_button_to wiki_path(@wiki, action: :new), role: "button", data: { testid: 'new-page-button' }, variant: :confirm, category: :secondary do = s_("Wiki|New page") diff --git a/app/views/shared/wikis/_sidebar_wiki_page.html.haml b/app/views/shared/wikis/_sidebar_wiki_page.html.haml index 710ecf6196e..afb26cf1d67 100644 --- a/app/views/shared/wikis/_sidebar_wiki_page.html.haml +++ b/app/views/shared/wikis/_sidebar_wiki_page.html.haml @@ -2,6 +2,6 @@ %li{ class: active_when(params[:id] == wiki_page.slug) } .gl-relative.gl-display-flex.gl-align-items-center.js-wiki-list-toggle.wiki-list{ data: { testid: 'wiki-list' } } - = render Pajamas::ButtonComponent.new(icon: 'plus', href: "#{wiki_path}/{new_page_title}", button_options: { class: 'wiki-list-create-child-button gl-bg-transparent! gl-hover-bg-gray-50! gl-focus-bg-gray-50! gl-absolute gl-top-half gl-translate-y-n50 gl-cursor-pointer gl-right-3' }) + = render Pajamas::ButtonComponent.new(icon: 'plus', size: :small, href: "#{wiki_path}/{new_page_title}", button_options: { class: 'wiki-list-create-child-button gl-bg-transparent! gl-hover-bg-gray-50! gl-focus-bg-gray-50! gl-absolute gl-top-half gl-translate-y-n50 gl-cursor-pointer gl-right-2' }) = link_to wiki_path, data: { testid: 'wiki-page-link', qa_page_name: wiki_page.human_title } do = wiki_page.human_title diff --git a/app/views/shared/wikis/_wiki_directory.html.haml b/app/views/shared/wikis/_wiki_directory.html.haml index 8b0b6dbd8f7..d939208811a 100644 --- a/app/views/shared/wikis/_wiki_directory.html.haml +++ b/app/views/shared/wikis/_wiki_directory.html.haml @@ -1,10 +1,10 @@ - wiki_path = wiki_page_path(@wiki, wiki_directory) -%li{ class: ['wiki-directory', active_when(params[:id] == wiki_directory.slug)], data: { testid: 'wiki-directory-content' } } +%li{ data: { testid: 'wiki-directory-content' } } .gl-relative.gl-display-flex.gl-align-items-center.js-wiki-list-toggle.wiki-list{ data: { testid: 'wiki-list' } }< = sprite_icon('chevron-right', css_class: 'js-wiki-list-expand-button wiki-list-expand-button gl-mr-2 gl-cursor-pointer') = sprite_icon('chevron-down', css_class: 'js-wiki-list-collapse-button wiki-list-collapse-button gl-mr-2 gl-cursor-pointer') - = render Pajamas::ButtonComponent.new(icon: 'plus', href: "#{wiki_path}/{new_page_title}", button_options: { class: 'wiki-list-create-child-button gl-bg-transparent! gl-hover-bg-gray-50! gl-focus-bg-gray-50! gl-absolute gl-top-half gl-translate-y-n50 gl-cursor-pointer gl-right-3' }) + = render Pajamas::ButtonComponent.new(icon: 'plus', size: :small, href: "#{wiki_path}/{new_page_title}", button_options: { class: 'wiki-list-create-child-button gl-bg-transparent! gl-hover-bg-gray-50! gl-focus-bg-gray-50! gl-absolute gl-top-half gl-translate-y-n50 gl-cursor-pointer gl-right-2' }) = link_to wiki_path, data: { testid: 'wiki-dir-page-link', qa_page_name: wiki_directory.title } do = wiki_directory.title %ul.gl-pl-8 diff --git a/app/views/shared/wikis/diff.html.haml b/app/views/shared/wikis/diff.html.haml index 67772ec40c1..700d8a903a4 100644 --- a/app/views/shared/wikis/diff.html.haml +++ b/app/views/shared/wikis/diff.html.haml @@ -12,7 +12,7 @@ = _('Changes') .nav-controls.pb-md-3.pb-lg-0 - = link_button_to wiki_page_path(@wiki, @page, action: :history), role: 'button', data: { qa_selector: 'page_history_button' } do + = link_button_to wiki_page_path(@wiki, @page, action: :history), role: 'button', data: { testid: 'page-history-button' } do = s_('Wiki|Page history') .page-content-header diff --git a/app/views/shared/wikis/edit.html.haml b/app/views/shared/wikis/edit.html.haml index fc56a191cad..b95bce37a75 100644 --- a/app/views/shared/wikis/edit.html.haml +++ b/app/views/shared/wikis/edit.html.haml @@ -12,7 +12,7 @@ %h1.page-title.gl-font-size-h-display.gl-flex-grow-1 - if @page.persisted? = link_to_wiki_page @page - %span.light + %span.gl-text-secondary · = s_("Wiki|Edit Page") - else diff --git a/app/views/shared/wikis/history.html.haml b/app/views/shared/wikis/history.html.haml index 052bbb3b410..4560f374fdf 100644 --- a/app/views/shared/wikis/history.html.haml +++ b/app/views/shared/wikis/history.html.haml @@ -11,7 +11,7 @@ = _('History') .prepend-top-default.gl-mb-3 - .table-holder + .table-holder{ data: { testid: 'wiki-history-table' } } %table.table.wiki-history %thead %tr diff --git a/app/views/shared/wikis/show.html.haml b/app/views/shared/wikis/show.html.haml index 2cd03c20080..a896aa29f52 100644 --- a/app/views/shared/wikis/show.html.haml +++ b/app/views/shared/wikis/show.html.haml @@ -1,7 +1,8 @@ - wiki_page_title @page - add_page_specific_style 'page_bundles/wiki' +- page_history = @page&.persisted? ? wiki_page_path(@wiki, @page, action: :history) : '' -.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row +.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row.gl-border-b-0 = wiki_sidebar_toggle_button .nav-text.flex-fill @@ -11,8 +12,12 @@ = time_ago_with_tooltip(@page.last_version.authored_date) .nav-controls.pb-md-3.pb-lg-0 + - if can?(current_user, :create_wiki, @wiki.container) && @page.latest? && @valid_encoding + = render Pajamas::ButtonComponent.new(href: wiki_page_path(@wiki, @page, action: :edit), button_options: { class: 'js-wiki-edit', data: { testid: 'wiki-edit-button' }}) do + = _('Edit') = render 'shared/wikis/main_links' - #js-export-actions{ data: { options: { target: '.js-wiki-page-content', title: @page.human_title, stylesheet: [stylesheet_path('application')] }.to_json } } + + #js-export-actions{ data: { options: { history: page_history, print: { target: '.js-wiki-page-content', title: @page.human_title, stylesheet: [stylesheet_path('application')] } }.to_json } } - if @page.historical? = render Pajamas::AlertComponent.new(variant: :warning, @@ -26,12 +31,9 @@ = render Pajamas::ButtonComponent.new(href: wiki_page_path(@wiki, @page, action: :history)) do = s_('WikiHistoricalPage|Browse history') -.gl-mt-5.gl-mb-3 +.gl-mb-3 .gl-display-flex.gl-justify-content-space-between %h2.gl-mt-0.gl-mb-5{ data: { testid: 'wiki-page-title' } }= @page.human_title - %div - - if can?(current_user, :create_wiki, @wiki.container) && @page.latest? && @valid_encoding - = render Pajamas::ButtonComponent.new(href: wiki_page_path(@wiki, @page, action: :edit), icon: 'pencil', button_options: { class: 'js-wiki-edit', title: "Edit", data: { testid: 'wiki-edit-button' }}) .js-async-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki-page-content', tracking_context: wiki_page_tracking_context(@page).to_json, get_wiki_content_url: wiki_page_render_api_endpoint(@page) } } diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index d8e78e28b55..875bf028267 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -3468,6 +3468,15 @@ :weight: 1 :idempotent: false :tags: [] +- :name: pages_deactivate_mr_deployments + :worker_name: Pages::DeactivateMrDeploymentsWorker + :feature_category: :pages + :has_external_dependencies: false + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] - :name: pages_domain_ssl_renewal :worker_name: PagesDomainSslRenewalWorker :feature_category: :pages diff --git a/app/workers/pages/deactivate_mr_deployments_worker.rb b/app/workers/pages/deactivate_mr_deployments_worker.rb new file mode 100644 index 00000000000..88a38f7f89c --- /dev/null +++ b/app/workers/pages/deactivate_mr_deployments_worker.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Pages + class DeactivateMrDeploymentsWorker + include ApplicationWorker + + idempotent! + data_consistency :always # rubocop: disable SidekiqLoadBalancing/WorkerDataConsistency -- performing writes only + urgency :low + + feature_category :pages + + def perform(merge_request_id) + build_ids = Ci::Build.ids_in_merge_request(merge_request_id) + deactivate_deployments_with_build_ids(build_ids) + end + + private + + def deactivate_deployments_with_build_ids(build_ids) + PagesDeployment + .versioned + .ci_build_id_in(build_ids) + .each_batch do |batch| # rubocop: disable Style/SymbolProc -- deactivate does not accept the index argument + batch.deactivate + end + end + end +end |