Commit 8801bf26 authored by shampton's avatar shampton

Artifacts management page

Add a page for managing job artifacts so that the
user can save space and find older artifacts easily.

This contains only frontend changes.

The link to the page is behind a feature flag.
parent b7f790c5
......@@ -208,6 +208,8 @@ linters:
- 'app/views/projects/_md_preview.html.haml'
- 'app/views/projects/_new_project_fields.html.haml'
- 'app/views/projects/_readme.html.haml'
- 'app/views/projects/artifacts/_artifact.html.haml'
- 'app/views/projects/artifacts/_search_bar.html.haml'
- 'app/views/projects/artifacts/_tree_file.html.haml'
- 'app/views/projects/artifacts/browse.html.haml'
- 'app/views/projects/blame/_age_map_legend.html.haml'
......
......@@ -182,11 +182,17 @@
= _('Pipelines')
- if project_nav_tab? :builds
= nav_link(controller: [:jobs, :artifacts]) do
= nav_link(controller: :jobs) do
= link_to project_jobs_path(@project), title: _('Jobs'), class: 'shortcuts-builds' do
%span
= _('Jobs')
- if Feature.enabled?(:artifacts_management_page, @project)
= nav_link(controller: :artifacts, action: :index) do
= link_to project_artifacts_path(@project), title: _('Artifacts'), class: 'shortcuts-builds' do
%span
= _('Artifacts')
- if project_nav_tab? :pipelines
= nav_link(controller: :pipeline_schedules) do
= link_to pipeline_schedules_path(@project), title: _('Schedules'), class: 'shortcuts-builds' do
......
.gl-responsive-table-row.px-md-3
.table-section.section-25.section-wrap.commit
.table-mobile-header{ role: 'rowheader' }= _('Job')
.table-mobile-content
.branch-commit.cgray
- if can?(current_user, :read_build, @project)
= link_to project_job_path(@project, artifact.job) do
%span.build-link ##{artifact.job_id}
- else
%span.build-link ##{artifact.job_id}
- if artifact.job.ref
.icon-container{ "aria-label" => artifact.job.tag? ? _('Tag') : _('Branch') }
= artifact.job.tag? ? sprite_icon('tag', css_class: 'sprite') : sprite_icon('branch', css_class: 'sprite')
= link_to artifact.job.ref, project_ref_path(@project, artifact.job.ref), class: 'ref-name'
- else
.light= _('none')
.icon-container.commit-icon{ "aria-label" => _('Commit') }
= sprite_icon('commit')
- if artifact.job.sha
= link_to artifact.job.short_sha, project_commit_path(@project, artifact.job.sha), class: 'commit-sha mr-0'
.table-section.section-15.section-wrap
.table-mobile-header{ role: 'rowheader' }= _('Name')
.table-mobile-content
= artifact.job.name
.table-section.section-20
.table-mobile-header{ role: 'rowheader' }= _('Creation date')
.table-mobile-content
%p.finished-at
= icon("calendar")
%span= time_ago_with_tooltip(artifact.created_at)
.table-section.section-20
.table-mobile-header{ role: 'rowheader' }= _('Expiration date')
.table-mobile-content
- if artifact.expire_at
%p.finished-at
= icon("calendar")
%span= time_ago_with_tooltip(artifact.expire_at)
.table-section.section-10
.table-mobile-header{ role: 'rowheader' }= _('Size')
.table-mobile-content
= number_to_human_size(artifact.size, precision: 2)
.table-section.table-button-footer.section-10
.table-action-buttons
.btn-group
- if can?(current_user, :read_build, @project)
= link_to download_project_job_artifacts_path(@project, artifact.job), rel: 'nofollow', download: '', title: _('Download artifacts'), data: { placement: 'top', container: 'body' }, ref: 'tooltip', aria: { label: _('Download artifacts') }, class: 'btn btn-build has-tooltip ml-0' do
= sprite_icon('download')
= link_to browse_project_job_artifacts_path(@project, artifact.job), rel: 'nofollow', title: _('Browse artifacts'), data: { placement: 'top', container: 'body' }, ref: 'tooltip', aria: { label: _('Browse artifacts') }, class: 'btn btn-build has-tooltip' do
= sprite_icon('folder-open')
- if can?(current_user, :destroy_artifacts, @project)
= link_to project_artifact_path(@project, artifact), data: { placement: 'top', container: 'body', confirm: _('Are you sure you want to delete these artifacts?') }, method: :delete, title: _('Delete artifacts'), ref: 'tooltip', aria: { label: _('Delete artifacts') }, class: 'btn btn-remove has-tooltip' do
= sprite_icon('remove')
- if artifacts.blank?
.nothing-here-block= _('No jobs to show')
- else
.table-holder
.ci-table
.gl-responsive-table-row.table-row-header.px-md-3{ role: 'row' }
.table-section.section-25{ role: 'rowheader' }= _('Job')
.table-section.section-15{ role: 'rowheader' }= _('Name')
.table-section.section-20{ role: 'rowheader' }= _('Creation date')
.table-section.section-20{ role: 'rowheader' }= _('Expiration date')
.table-section.section-10{ role: 'rowheader' }= _('Size')
.table-section.section-10{ role: 'rowheader' }
= render partial: 'artifact', collection: artifacts, as: :artifact
= paginate artifacts, theme: "gitlab", total_pages: @total_pages
- @no_container = true
- page_title _('Artifacts')
%div{ class: container_class }
.top-area.py-3
.align-self-center
= _('Total artifacts size: %{total_size}') % { total_size: number_to_human_size(@total_size, precicion: 2) }
.content-list.builds-content-list
= render "table", artifacts: @artifacts, project: @project
......@@ -1782,6 +1782,9 @@ msgstr ""
msgid "Are you sure you want to cancel editing this comment?"
msgstr ""
msgid "Are you sure you want to delete these artifacts?"
msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
......@@ -2377,6 +2380,9 @@ msgstr ""
msgid "Boards|View scope"
msgstr ""
msgid "Branch"
msgstr ""
msgid "Branch %{branchName} was not found in this project's repository."
msgstr ""
......@@ -2539,6 +2545,9 @@ msgstr ""
msgid "Browse Files"
msgstr ""
msgid "Browse artifacts"
msgstr ""
msgid "Browse files"
msgstr ""
......@@ -4475,6 +4484,9 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
msgid "Creation date"
msgstr ""
msgid "Cron Timezone"
msgstr ""
......@@ -4758,6 +4770,9 @@ msgstr ""
msgid "Delete Snippet"
msgstr ""
msgid "Delete artifacts"
msgstr ""
msgid "Delete board"
msgstr ""
......@@ -10313,6 +10328,9 @@ msgstr ""
msgid "No job trace"
msgstr ""
msgid "No jobs to show"
msgstr ""
msgid "No labels with such name or description"
msgstr ""
......@@ -16425,6 +16443,9 @@ msgstr ""
msgid "Total Time"
msgstr ""
msgid "Total artifacts size: %{total_size}"
msgstr ""
msgid "Total test time for all commits/merges"
msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe "projects/artifacts/_artifact.html.haml" do
let(:project) { create(:project) }
describe 'delete button' do
before do
create(:ci_build, :artifacts, project: project)
allow(view).to receive(:current_user).and_return(user)
assign(:project, project)
end
context 'with admin' do
let(:user) { build(:admin) }
it 'has a delete button' do
render_partial
expect(rendered).to have_link('Delete artifacts', href: project_artifact_path(project, project.job_artifacts.first))
end
end
context 'with owner' do
let(:user) { create(:user) }
let(:project) { build(:project, namespace: user.namespace) }
it 'has a delete button' do
render_partial
expect(rendered).to have_link('Delete artifacts', href: project_artifact_path(project, project.job_artifacts.first))
end
end
context 'with master' do
let(:user) { create(:user) }
it 'has a delete button' do
allow_any_instance_of(ProjectTeam).to receive(:max_member_access).and_return(Gitlab::Access::MASTER)
render_partial
expect(rendered).to have_link('Delete artifacts', href: project_artifact_path(project, project.job_artifacts.first))
end
end
context 'with developer' do
let(:user) { build(:user) }
it 'has no delete button' do
project.add_developer(user)
render_partial
expect(rendered).not_to have_link('Delete artifacts')
end
end
context 'with reporter' do
let(:user) { build(:user) }
it 'has no delete button' do
project.add_reporter(user)
render_partial
expect(rendered).not_to have_link('Delete artifacts')
end
end
end
def render_partial
render partial: 'projects/artifacts/artifact', collection: project.job_artifacts, as: :artifact
end
end
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