Commit 9536d26e authored by Toon Claes's avatar Toon Claes Committed by Stan Hu

Implement Geo Admin Uploads controller

Add the controller and the views to show the list of upload
registries.
parent 8987e143
......@@ -178,13 +178,9 @@
}
.geo-admin-projects,
.geo-admin-uploads,
.admin-projects {
.card-header {
.header-text-primary,
.header-text-secondary {
color: $blue-600;
}
.header-text-primary {
line-height: 28px;
text-overflow: ellipsis;
......@@ -213,12 +209,13 @@
}
.card-body {
.project-container {
.project-container,
.upload-container {
margin-left: 0;
padding-left: 0;
}
.project-status-content {
.geo-status-content {
&.status-type-success {
color: $green-600;
}
......@@ -229,7 +226,8 @@
}
@include media-breakpoint-down(xs) {
.project-status-container + .project-status-container {
.project-status-container + .project-status-container,
.upload-status-container + .upload-status-container {
margin-top: 15px;
}
}
......
# frozen_string_literal: true
class Admin::Geo::UploadsController < Admin::Geo::ApplicationController
before_action :check_license!
before_action :registries, only: [:index]
def index
end
def destroy
if registry.upload
return redirect_admin_geo_uploads(alert: s_('Geo|Could not remove tracking entry for an existing upload.'))
end
registry.destroy
redirect_admin_geo_uploads(notice: s_('Geo|Tracking entry for upload (%{type}/%{id}) was successfully removed.') % { type: registry.file_type, id: registry.file_id })
end
private
def registries
@registries ||=
::Geo::UploadRegistry
.with_status(params[:sync_status])
.with_search(params[:name])
.fresh
.page(params[:page])
end
def registry
@registry ||= ::Geo::UploadRegistry.find_by_id(params[:id])
end
def redirect_admin_geo_uploads(options)
redirect_back_or_default(default: admin_geo_uploads_path, options: options)
end
end
......@@ -18,4 +18,8 @@ class Geo::UploadRegistry < Geo::FileRegistry
def file
upload&.path || s_('Removed %{type} with id %{id}') % { type: file_type, id: file_id }
end
def project
return upload.model if upload&.model.is_a?(Project)
end
end
.card.upload-card.prepend-top-15
.card-header{ id: "upload-#{upload_registry.id}-header" }
.d-flex
%strong.header-text-primary.flex-fill
= upload_registry.file
- unless upload_registry.success?
= link_to('sync_admin_geo_upload_path(upload_registry)', method: :post, class: 'btn btn-default btn-sm mr-2') do
= s_('Geo|Sync')
- unless upload_registry.upload
= link_to(admin_geo_upload_path(upload_registry), data: { confirm: s_('Geo|Tracking entry will be removed. Are you sure?')}, method: :delete, class: 'btn btn-inverted btn-remove btn-sm') do
= s_('Geo|Remove')
.card-body
.container.upload-container
.row
.col-sm.upload-status-container
.upload-status-title.text-muted
= s_('Geo|Status')
= geo_registry_status(upload_registry)
.col-sm.upload-status-container
.upload-status-title.text-muted
= s_('Geo|Synced at')
.upload-status-content
- if upload_registry.success?
= time_ago_with_tooltip(upload_registry.created_at, placement: 'bottom')
- else
= s_('Geo|Never')
- if upload_registry.project
.col-sm.upload-status-container
.upload-status-title.text-muted
= s_('Geo|Project')
.upload-status-content
= link_to(upload_registry.project.full_name, admin_namespace_project_path(upload_registry.project.namespace, upload_registry.project))
- page_title 'Geo Uploads'
- @content_class = "geo-admin-container geo-admin-uploads"
- params[:sync_status] ||= []
%div{ class: container_class }
.top-area.scrolling-tabs-container.inner-page-scroll-tabs
%ul.nav-links.nav.nav-tabs
- opts = params[:sync_status].present? ? {} : { page: admin_geo_uploads_path }
= nav_link(opts) do
= link_to admin_geo_uploads_path do
= s_('Geo|All')
= nav_link(html_options: { class: active_when(params[:sync_status] == 'synced') }) do
= link_to admin_geo_uploads_path(sync_status: 'synced') do
= s_('Geo|Synced')
= nav_link(html_options: { class: active_when(params[:sync_status] == 'failed') }) do
= link_to admin_geo_uploads_path(sync_status: 'failed') do
= s_('Geo|Failed')
= nav_link(html_options: { class: active_when(params[:sync_status] == 'never') }) do
= link_to admin_geo_uploads_path(sync_status: 'never') do
= s_('Geo|Never')
.nav-controls
= render(partial: 'shared/projects/search_form', autofocus: true)
- @registries.each do |upload_registry|
= render partial: 'registry', locals: { upload_registry: upload_registry }
= paginate @registries, theme: 'gitlab'
= nav_link(controller: %w(admin/geo/nodes admin/geo/projects)) do
= nav_link(controller: %w(admin/geo/nodes admin/geo/projects admin/geo/uploads)) do
= link_to admin_geo_nodes_path, class: "qa-link-geo-menu" do
.nav-icon-container
= sprite_icon('location-dot')
......@@ -19,3 +19,7 @@
= link_to admin_geo_projects_path, title: 'Projects' do
%span
= _('Projects')
= nav_link(path: 'admin/geo/uploads#index') do
= link_to admin_geo_uploads_path, title: 'Uploads' do
%span
= _('Uploads')
---
title: Geo admin panel for upload verification
merge_request: 9720
author:
type: added
......@@ -40,6 +40,8 @@ namespace :admin do
post :resync_all
end
end
resources :uploads, only: [:index, :destroy]
end
get '/dashboard/stats', to: 'dashboard#stats'
......
# frozen_string_literal: true
require 'spec_helper'
describe Admin::Geo::UploadsController, :geo do
include EE::GeoHelpers
set(:admin) { create(:admin) }
set(:secondary) { create(:geo_node) }
set(:synced_registry) { create(:geo_file_registry, :with_file, success: true) }
set(:failed_registry) { create(:geo_file_registry, :failed) }
set(:never_registry) { create(:geo_file_registry, :failed, retry_count: nil) }
def css_id(registry)
"#upload-#{registry.id}-header"
end
before do
sign_in(admin)
end
shared_examples 'license required' do
context 'without a valid license' do
it 'redirects to license page with a flash message' do
expect(subject).to redirect_to(admin_license_path)
expect(flash[:alert]).to include('You need a different license to use Geo replication')
end
end
end
describe '#index' do
subject { get :index }
it_behaves_like 'license required'
context 'with a valid license' do
render_views
before do
stub_licensed_features(geo: true)
stub_current_geo_node(secondary)
end
it 'renders the index template' do
expect(subject).to have_gitlab_http_status(200)
expect(subject).to render_template(:index)
end
context 'without sync_status specified' do
it 'renders all registries' do
expect(subject).to have_gitlab_http_status(200)
expect(response.body).to have_css(css_id(synced_registry))
expect(response.body).to have_css(css_id(failed_registry))
expect(response.body).to have_css(css_id(never_registry))
end
end
context 'with sync_status=synced' do
subject { get :index, params: { sync_status: 'synced' } }
it 'renders only synced registries' do
expect(subject).to have_gitlab_http_status(200)
expect(response.body).to have_css(css_id(synced_registry))
expect(response.body).not_to have_css(css_id(failed_registry))
expect(response.body).not_to have_css(css_id(never_registry))
end
end
context 'with sync_status=failed' do
subject { get :index, params: { sync_status: 'failed' } }
it 'renders only failed registries' do
expect(subject).to have_gitlab_http_status(200)
expect(response.body).not_to have_css(css_id(synced_registry))
expect(response.body).to have_css(css_id(failed_registry))
expect(response.body).not_to have_css(css_id(never_registry))
end
end
context 'with sync_status=never' do
subject { get :index, params: { sync_status: 'never' } }
it 'renders only never synced registries' do
expect(subject).to have_gitlab_http_status(200)
expect(response.body).not_to have_css(css_id(synced_registry))
expect(response.body).not_to have_css(css_id(failed_registry))
expect(response.body).to have_css(css_id(never_registry))
end
end
end
end
describe '#destroy' do
subject { delete :destroy, params: { id: upload_registry } }
it_behaves_like 'license required' do
let(:upload_registry) { create(:geo_file_registry) }
end
context 'with a valid license' do
before do
stub_licensed_features(geo: true)
end
context 'with an orphaned registry' do
let(:upload_registry) { create(:geo_file_registry, success: true) }
it 'removes the registry' do
upload_registry.update_column(:file_id, -1)
expect(subject).to redirect_to(admin_geo_uploads_path)
expect(flash[:notice]).to include('was successfully removed')
expect { Geo::UploadRegistry.find(upload_registry.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
end
context 'with a regular registry' do
let(:upload_registry) { create(:geo_file_registry, :avatar, :with_file, success: true) }
it 'does not delete the registry and gives an error' do
expect(subject).to redirect_to(admin_geo_uploads_path)
expect(flash[:alert]).to include('Could not remove tracking entry')
expect { Geo::UploadRegistry.find(upload_registry.id) }.not_to raise_error
end
end
end
end
end
......@@ -15,6 +15,11 @@ FactoryBot.define do
factory :geo_upload_registry, class: Geo::UploadRegistry
trait :failed do
success false
retry_count 1
end
trait :with_file do
after(:build, :stub) do |registry, _|
file =
......
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