Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
3e3a5382
Commit
3e3a5382
authored
Jul 28, 2020
by
James Fargher
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'list-removable-projects' into 'master'
List removable projects See merge request gitlab-org/gitlab!37014
parents
3d5d66b0
5fabac0a
Changes
24
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
301 additions
and
17 deletions
+301
-17
app/controllers/dashboard/projects_controller.rb
app/controllers/dashboard/projects_controller.rb
+1
-1
app/views/dashboard/_projects_head.html.haml
app/views/dashboard/_projects_head.html.haml
+1
-0
app/views/dashboard/projects/shared/_common.html.haml
app/views/dashboard/projects/shared/_common.html.haml
+13
-0
app/views/dashboard/projects/starred.html.haml
app/views/dashboard/projects/starred.html.haml
+1
-14
app/views/shared/projects/_project.html.haml
app/views/shared/projects/_project.html.haml
+2
-0
db/migrate/20200721230558_add_index_to_projects_aimed_for_deletion.rb
...0200721230558_add_index_to_projects_aimed_for_deletion.rb
+27
-0
db/schema_migrations/20200721230558
db/schema_migrations/20200721230558
+1
-0
db/structure.sql
db/structure.sql
+2
-2
ee/app/controllers/ee/dashboard/projects_controller.rb
ee/app/controllers/ee/dashboard/projects_controller.rb
+30
-0
ee/app/controllers/ee/explore/projects_controller.rb
ee/app/controllers/ee/explore/projects_controller.rb
+7
-0
ee/app/finders/ee/projects_finder.rb
ee/app/finders/ee/projects_finder.rb
+9
-0
ee/app/helpers/ee/projects_helper.rb
ee/app/helpers/ee/projects_helper.rb
+4
-0
ee/app/policies/ee/global_policy.rb
ee/app/policies/ee/global_policy.rb
+8
-0
ee/app/views/dashboard/_removed_projects_tab.html.haml
ee/app/views/dashboard/_removed_projects_tab.html.haml
+5
-0
ee/app/views/dashboard/projects/_removed_empty_state.html.haml
...p/views/dashboard/projects/_removed_empty_state.html.haml
+9
-0
ee/app/views/dashboard/projects/removed.html.haml
ee/app/views/dashboard/projects/removed.html.haml
+1
-0
ee/app/views/shared/projects/_removed.html.haml
ee/app/views/shared/projects/_removed.html.haml
+14
-0
ee/changelogs/unreleased/deletion-delay-with-restoration.yml
ee/changelogs/unreleased/deletion-delay-with-restoration.yml
+5
-0
ee/config/routes/dashboard.rb
ee/config/routes/dashboard.rb
+11
-0
ee/spec/controllers/ee/dashboard/projects_controller_spec.rb
ee/spec/controllers/ee/dashboard/projects_controller_spec.rb
+67
-0
ee/spec/finders/ee/projects_finder_spec.rb
ee/spec/finders/ee/projects_finder_spec.rb
+8
-0
ee/spec/helpers/projects_helper_spec.rb
ee/spec/helpers/projects_helper_spec.rb
+12
-0
ee/spec/policies/global_policy_spec.rb
ee/spec/policies/global_policy_spec.rb
+42
-0
locale/gitlab.pot
locale/gitlab.pot
+21
-0
No files found.
app/controllers/dashboard/projects_controller.rb
View file @
3e3a5382
...
...
@@ -9,7 +9,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
include
FiltersEvents
prepend_before_action
(
only:
[
:index
])
{
authenticate_sessionless_user!
(
:rss
)
}
before_action
:set_non_archived_param
before_action
:set_non_archived_param
,
only:
[
:index
,
:starred
]
before_action
:set_sorting
before_action
:projects
,
only:
[
:index
]
skip_cross_project_access_check
:index
,
:starred
...
...
app/views/dashboard/_projects_head.html.haml
View file @
3e3a5382
...
...
@@ -26,6 +26,7 @@
=
nav_link
(
page:
[
explore_root_path
,
trending_explore_projects_path
,
starred_explore_projects_path
,
explore_projects_path
])
do
=
link_to
explore_root_path
,
data:
{
placement:
'right'
}
do
=
_
(
"Explore projects"
)
=
render_if_exists
"dashboard/removed_projects_tab"
,
removed_projects_count:
@removed_projects_count
-
unless
feature_project_list_filter_bar
.nav-controls
=
render
'shared/projects/search_form'
...
...
app/views/dashboard/projects/shared/_common.html.haml
0 → 100644
View file @
3e3a5382
-
@hide_top_links
=
true
-
breadcrumb_title
_
(
"Projects"
)
-
header_title
_
(
"Projects"
),
dashboard_projects_path
=
render_dashboard_gold_trial
(
current_user
)
=
render
"projects/last_push"
=
render
'dashboard/projects_head'
,
project_tab_filter: :starred
-
if
params
[
:filter_projects
]
||
any_projects?
(
@projects
)
=
render
'projects'
-
else
=
render
empty_page
app/views/dashboard/projects/starred.html.haml
View file @
3e3a5382
-
@hide_top_links
=
true
-
breadcrumb_title
_
(
"Projects"
)
-
page_title
_
(
"Starred Projects"
)
-
header_title
_
(
"Projects"
),
dashboard_projects_path
=
render_dashboard_gold_trial
(
current_user
)
=
render
"projects/last_push"
=
render
'dashboard/projects_head'
,
project_tab_filter: :starred
-
if
params
[
:filter_projects
]
||
any_projects?
(
@projects
)
=
render
'projects'
-
else
=
render
'starred_empty_state'
=
render
partial:
'dashboard/projects/shared/common'
,
locals:
{
page_title:
_
(
'Starred Projects'
),
empty_page:
'starred_empty_state'
}
app/views/shared/projects/_project.html.haml
View file @
3e3a5382
...
...
@@ -64,6 +64,8 @@
.description.d-none.d-sm-block.gl-mr-3
=
markdown_field
(
project
,
:description
)
=
render_if_exists
'shared/projects/removed'
,
project:
project
.controls.d-flex.flex-sm-column.align-items-center.align-items-sm-end.flex-wrap.flex-shrink-0.text-secondary
{
class:
css_controls_class
.
join
(
" "
)
}
.icon-container.d-flex.align-items-center
-
if
show_pipeline_status_icon
...
...
db/migrate/20200721230558_add_index_to_projects_aimed_for_deletion.rb
0 → 100644
View file @
3e3a5382
# frozen_string_literal: true
class
AddIndexToProjectsAimedForDeletion
<
ActiveRecord
::
Migration
[
6.0
]
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
PROJECTS_AIMED_FOR_DELETION_INDEX_NAME
=
"index_projects_aimed_for_deletion"
MARKED_FOR_DELETION_PROJECTS_INDEX_NAME
=
"index_projects_on_marked_for_deletion_at"
disable_ddl_transaction!
def
up
add_concurrent_index
:projects
,
:marked_for_deletion_at
,
where:
"marked_for_deletion_at IS NOT NULL AND pending_delete = false"
,
name:
PROJECTS_AIMED_FOR_DELETION_INDEX_NAME
remove_concurrent_index_by_name
:projects
,
MARKED_FOR_DELETION_PROJECTS_INDEX_NAME
end
def
down
remove_concurrent_index_by_name
:projects
,
PROJECTS_AIMED_FOR_DELETION_INDEX_NAME
add_concurrent_index
:projects
,
:marked_for_deletion_at
,
where:
'marked_for_deletion_at IS NOT NULL'
end
end
db/schema_migrations/20200721230558
0 → 100644
View file @
3e3a5382
7409688836e7375423b45d69e6c7b82c6a946c0306435ec341bf216e3f97190f
\ No newline at end of file
db/structure.sql
View file @
3e3a5382
...
...
@@ -20245,6 +20245,8 @@ CREATE INDEX index_project_statistics_on_wiki_size_and_project_id ON public.proj
CREATE
UNIQUE
INDEX
index_project_tracing_settings_on_project_id
ON
public
.
project_tracing_settings
USING
btree
(
project_id
);
CREATE
INDEX
index_projects_aimed_for_deletion
ON
public
.
projects
USING
btree
(
marked_for_deletion_at
)
WHERE
((
marked_for_deletion_at
IS
NOT
NULL
)
AND
(
pending_delete
=
false
));
CREATE
INDEX
index_projects_api_created_at_id_desc
ON
public
.
projects
USING
btree
(
created_at
,
id
DESC
);
CREATE
INDEX
index_projects_api_created_at_id_for_archived
ON
public
.
projects
USING
btree
(
created_at
,
id
)
WHERE
((
archived
=
true
)
AND
(
pending_delete
=
false
));
...
...
@@ -20295,8 +20297,6 @@ CREATE INDEX index_projects_on_last_repository_updated_at ON public.projects USI
CREATE
INDEX
index_projects_on_lower_name
ON
public
.
projects
USING
btree
(
lower
((
name
)::
text
));
CREATE
INDEX
index_projects_on_marked_for_deletion_at
ON
public
.
projects
USING
btree
(
marked_for_deletion_at
)
WHERE
(
marked_for_deletion_at
IS
NOT
NULL
);
CREATE
INDEX
index_projects_on_marked_for_deletion_by_user_id
ON
public
.
projects
USING
btree
(
marked_for_deletion_by_user_id
)
WHERE
(
marked_for_deletion_by_user_id
IS
NOT
NULL
);
CREATE
INDEX
index_projects_on_mirror_creator_id_created_at
ON
public
.
projects
USING
btree
(
creator_id
,
created_at
)
WHERE
((
mirror
=
true
)
AND
(
mirror_trigger_builds
=
true
));
...
...
ee/app/controllers/ee/dashboard/projects_controller.rb
View file @
3e3a5382
...
...
@@ -6,6 +6,25 @@ module EE
extend
ActiveSupport
::
Concern
extend
::
Gitlab
::
Utils
::
Override
prepended
do
before_action
:check_adjourned_deletion_listing_availability
,
only:
[
:removed
]
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def
removed
@projects
=
load_projects
(
params
.
merge
(
aimed_for_deletion:
true
))
respond_to
do
|
format
|
format
.
html
format
.
json
do
render
json:
{
html:
view_to_html_string
(
"dashboard/projects/_projects"
,
projects:
@projects
)
}
end
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
private
override
:preload_associations
...
...
@@ -13,6 +32,17 @@ module EE
super
.
with_compliance_framework_settings
.
with_group_saml_provider
end
override
:load_projects
def
load_projects
(
finder_params
)
@removed_projects_count
=
::
ProjectsFinder
.
new
(
params:
{
aimed_for_deletion:
true
},
current_user:
current_user
).
execute
# rubocop:disable Gitlab/ModuleWithInstanceVariables
super
end
def
check_adjourned_deletion_listing_availability
return
render_404
unless
can?
(
current_user
,
:list_removable_projects
)
end
end
end
end
ee/app/controllers/ee/explore/projects_controller.rb
View file @
3e3a5382
...
...
@@ -11,6 +11,13 @@ module EE
def
preload_associations
(
projects
)
super
.
with_compliance_framework_settings
end
override
:load_project_counts
def
load_project_counts
@removed_projects_count
=
::
ProjectsFinder
.
new
(
params:
{
aimed_for_deletion:
true
},
current_user:
current_user
).
execute
# rubocop:disable Gitlab/ModuleWithInstanceVariables
super
end
end
end
end
ee/app/finders/ee/projects_finder.rb
View file @
3e3a5382
...
...
@@ -17,6 +17,7 @@ module EE
def
filter_projects
(
collection
)
collection
=
super
(
collection
)
collection
=
by_plans
(
collection
)
collection
=
by_aimed_for_deletion
(
collection
)
collection
end
...
...
@@ -27,5 +28,13 @@ module EE
collection
end
end
def
by_aimed_for_deletion
(
items
)
if
::
Gitlab
::
Utils
.
to_boolean
(
params
[
:aimed_for_deletion
])
items
.
aimed_for_deletion
(
Date
.
current
)
else
items
end
end
end
end
ee/app/helpers/ee/projects_helper.rb
View file @
3e3a5382
...
...
@@ -246,6 +246,10 @@ module EE
project
&
.
compliance_framework_setting
&
.
present?
end
def
scheduled_for_deletion?
(
project
)
project
.
marked_for_deletion_at
.
present?
end
private
def
get_project_security_nav_tabs
(
project
,
current_user
)
...
...
ee/app/policies/ee/global_policy.rb
View file @
3e3a5382
...
...
@@ -13,6 +13,10 @@ module EE
License
.
feature_available?
(
:pages_size_limit
)
end
condition
(
:adjourned_project_deletion_available
)
do
License
.
feature_available?
(
:adjourned_deletion_for_projects_and_groups
)
end
rule
{
~
anonymous
&
operations_dashboard_available
}.
enable
:read_operations_dashboard
rule
{
admin
}.
policy
do
...
...
@@ -30,6 +34,10 @@ module EE
rule
{
~
(
admin
|
allow_to_manage_default_branch_protection
)
}.
policy
do
prevent
:create_group_with_default_branch_protection
end
rule
{
admin
&
adjourned_project_deletion_available
}.
policy
do
enable
:list_removable_projects
end
end
end
end
ee/app/views/dashboard/_removed_projects_tab.html.haml
0 → 100644
View file @
3e3a5382
-
if
can?
(
current_user
,
:list_removable_projects
)
=
nav_link
(
page:
removed_dashboard_projects_path
)
do
=
link_to
removed_dashboard_projects_path
,
data:
{
placement:
'right'
}
do
=
_
(
"Removed projects"
)
%span
.badge.badge-pill
=
limited_counter_with_delimiter
(
removed_projects_count
)
ee/app/views/dashboard/projects/_removed_empty_state.html.haml
0 → 100644
View file @
3e3a5382
.row.empty-state
.col-12
.svg-content.svg-250
=
image_tag
'illustrations/erased-log_empty.svg'
.text-content
%h4
.gl-text-center
=
s_
(
"RemovedProjects|You haven’t removed any projects."
)
%p
.gl-text-gray-700
=
s_
(
"RemovedProjects|Projects which are removed and are yet to be permanently removed are visible here."
)
ee/app/views/dashboard/projects/removed.html.haml
0 → 100644
View file @
3e3a5382
=
render
partial:
'dashboard/projects/shared/common'
,
locals:
{
page_title:
_
(
'Removed Projects'
),
empty_page:
'removed_empty_state'
}
ee/app/views/shared/projects/_removed.html.haml
0 → 100644
View file @
3e3a5382
-
if
current_user
&
.
admin?
&&
scheduled_for_deletion?
(
project
)
.gl-display-flex.gl-align-items-center.gl-flex-wrap.project-title
%span
.small
=
_
(
"Marked For Deletion At - %{deletion_time}"
)
%
{
deletion_time:
project
.
marked_for_deletion_at
.
strftime
(
Date
::
DATE_FORMATS
[
:medium
])
}
.gl-display-flex.gl-align-items-center.gl-flex-wrap.project-title
%p
.small
=
_
(
"Scheduled Deletion At - %{permanent_deletion_time}"
)
%
{
permanent_deletion_time:
DateTime
.
parse
(
permanent_deletion_date
(
project
.
marked_for_deletion_at
)).
strftime
(
Date
::
DATE_FORMATS
[
:medium
])
}
.gl-display-flex.gl-align-items-center.gl-flex-wrap.project-title
%span
.small
=
link_to
project_restore_path
(
project
),
class:
"gl-display-flex gl-align-items-center icon-wrapper stars has-tooltip"
,
title:
_
(
'Restore'
),
data:
{
container:
'body'
,
placement:
'top'
},
method: :post
do
=
_
(
"Restore"
)
ee/changelogs/unreleased/deletion-delay-with-restoration.yml
0 → 100644
View file @
3e3a5382
---
title
:
Removed Projects Page in Admin UI with restoration button
merge_request
:
37014
author
:
Ashesh Vidyut
type
:
added
ee/config/routes/dashboard.rb
0 → 100644
View file @
3e3a5382
# frozen_string_literal: true
resource
:dashboard
,
controller:
'dashboard'
,
only:
[]
do
scope
module: :dashboard
do
resources
:projects
,
only:
[
:index
]
do
collection
do
get
:removed
end
end
end
end
ee/spec/controllers/ee/dashboard/projects_controller_spec.rb
0 → 100644
View file @
3e3a5382
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Dashboard
::
ProjectsController
do
let_it_be
(
:user
)
{
create
(
:user
)
}
describe
'#removed'
do
render_views
subject
{
get
:removed
,
format: :json
}
before
do
sign_in
(
user
)
allow
(
Kaminari
.
config
).
to
receive
(
:default_per_page
).
and_return
(
1
)
end
shared_examples
'returns not found'
do
it
do
subject
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
context
'when licensed'
do
before
do
stub_licensed_features
(
adjourned_deletion_for_projects_and_groups:
true
)
end
context
'for admin users'
,
:enable_admin_mode
do
let_it_be
(
:user
)
{
create
(
:admin
)
}
let_it_be
(
:projects
)
{
create_list
(
:project
,
2
,
:archived
,
creator:
user
,
marked_for_deletion_at:
3
.
days
.
ago
)
}
it
'returns success'
do
subject
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
end
it
'paginates the records'
do
subject
expect
(
assigns
(
:projects
).
count
).
to
eq
(
1
)
end
it
'accounts total removable projects'
do
subject
expect
(
assigns
(
:removed_projects_count
).
count
).
to
eq
(
2
)
end
end
context
'for non-admin users'
do
it_behaves_like
'returns not found'
end
end
context
'when not licensed'
do
before
do
stub_licensed_features
(
adjourned_deletion_for_projects_and_groups:
false
)
end
it_behaves_like
'returns not found'
end
end
end
ee/spec/finders/ee/projects_finder_spec.rb
View file @
3e3a5382
...
...
@@ -48,6 +48,14 @@ RSpec.describe ProjectsFinder do
it
{
is_expected
.
to
contain_exactly
(
gold_project
,
gold_project2
,
silver_project
,
no_plan_project
)
}
end
context
'filter by aimed for deletion'
do
let_it_be
(
:params
)
{
{
aimed_for_deletion:
true
}
}
let_it_be
(
:aimed_for_deletion_project
)
{
create
(
:project
,
:public
,
marked_for_deletion_at:
2
.
days
.
ago
,
pending_delete:
false
)
}
let_it_be
(
:deleted_project
)
{
create
(
:project
,
:public
,
marked_for_deletion_at:
1
.
month
.
ago
,
pending_delete:
true
)
}
it
{
is_expected
.
to
contain_exactly
(
aimed_for_deletion_project
)
}
end
private
def
create_project
(
plan
)
...
...
ee/spec/helpers/projects_helper_spec.rb
View file @
3e3a5382
...
...
@@ -263,4 +263,16 @@ RSpec.describe ProjectsHelper do
end
end
end
describe
'#scheduled_for_deletion?'
do
context
'when project is NOT scheduled for deletion'
do
it
{
expect
(
helper
.
scheduled_for_deletion?
(
project
)).
to
be
false
}
end
context
'when project is scheduled for deletion'
do
let_it_be
(
:archived_project
)
{
create
(
:project
,
:archived
,
marked_for_deletion_at:
10
.
minutes
.
ago
)
}
it
{
expect
(
helper
.
scheduled_for_deletion?
(
archived_project
)).
to
be
true
}
end
end
end
ee/spec/policies/global_policy_spec.rb
View file @
3e3a5382
...
...
@@ -195,4 +195,46 @@ RSpec.describe GlobalPolicy do
end
end
end
describe
'list_removable_projects'
do
context
'when user is an admin'
,
:enable_admin_mode
do
let_it_be
(
:current_user
)
{
admin
}
before
do
stub_licensed_features
(
adjourned_deletion_for_projects_and_groups:
licensed?
)
end
context
'when licensed feature is enabled'
do
let
(
:licensed?
)
{
true
}
it
{
is_expected
.
to
be_allowed
(
:list_removable_projects
)
}
end
context
'when licensed feature is enabled'
do
let
(
:licensed?
)
{
false
}
it
{
is_expected
.
to
be_disallowed
(
:list_removable_projects
)
}
end
end
context
'when user is a normal user'
do
let_it_be
(
:current_user
)
{
create
(
:user
)
}
before
do
stub_licensed_features
(
adjourned_deletion_for_projects_and_groups:
licensed?
)
end
context
'when licensed feature is enabled'
do
let
(
:licensed?
)
{
true
}
it
{
is_expected
.
to
be_disallowed
(
:list_removable_projects
)
}
end
context
'when licensed feature is enabled'
do
let
(
:licensed?
)
{
false
}
it
{
is_expected
.
to
be_disallowed
(
:list_removable_projects
)
}
end
end
end
end
locale/gitlab.pot
View file @
3e3a5382
...
...
@@ -14444,6 +14444,9 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
msgid "Marked To Do as done."
msgstr ""
...
...
@@ -19856,6 +19859,9 @@ msgstr ""
msgid "Removed %{type} with id %{id}"
msgstr ""
msgid "Removed Projects"
msgstr ""
msgid "Removed all labels."
msgstr ""
...
...
@@ -19868,6 +19874,9 @@ msgstr ""
msgid "Removed parent epic %{epic_ref}."
msgstr ""
msgid "Removed projects"
msgstr ""
msgid "Removed projects cannot be restored!"
msgstr ""
...
...
@@ -19880,6 +19889,12 @@ msgstr ""
msgid "Removed time estimate."
msgstr ""
msgid "RemovedProjects|Projects which are removed and are yet to be permanently removed are visible here."
msgstr ""
msgid "RemovedProjects|You haven’t removed any projects."
msgstr ""
msgid "Removes %{assignee_text} %{assignee_references}."
msgstr ""
...
...
@@ -20360,6 +20375,9 @@ msgstr ""
msgid "Restart Terminal"
msgstr ""
msgid "Restore"
msgstr ""
msgid "Restore group"
msgstr ""
...
...
@@ -20659,6 +20677,9 @@ msgstr ""
msgid "Scheduled"
msgstr ""
msgid "Scheduled Deletion At - %{permanent_deletion_time}"
msgstr ""
msgid "Scheduled to merge this merge request (%{strategy})."
msgstr ""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment