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
8c5f2b7f
Commit
8c5f2b7f
authored
Apr 13, 2021
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab master
parents
8c79ba4e
288c7965
Changes
56
Hide whitespace changes
Inline
Side-by-side
Showing
56 changed files
with
824 additions
and
130 deletions
+824
-130
.rubocop.yml
.rubocop.yml
+13
-0
.rubocop_manual_todo.yml
.rubocop_manual_todo.yml
+57
-0
.rubocop_todo.yml
.rubocop_todo.yml
+0
-7
app/assets/javascripts/members/components/action_buttons/approve_access_request_button.vue
...mponents/action_buttons/approve_access_request_button.vue
+6
-1
app/assets/javascripts/members/components/action_buttons/remove_group_link_button.vue
...rs/components/action_buttons/remove_group_link_button.vue
+6
-1
app/assets/javascripts/members/components/action_buttons/remove_member_button.vue
...embers/components/action_buttons/remove_member_button.vue
+6
-1
app/assets/javascripts/members/components/action_buttons/resend_invite_button.vue
...embers/components/action_buttons/resend_invite_button.vue
+6
-1
app/assets/javascripts/members/components/app.vue
app/assets/javascripts/members/components/app.vue
+12
-2
app/assets/javascripts/members/components/filter_sort/filter_sort_container.vue
.../members/components/filter_sort/filter_sort_container.vue
+9
-1
app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue
...rs/components/filter_sort/members_filtered_search_bar.vue
+6
-2
app/assets/javascripts/members/components/filter_sort/sort_dropdown.vue
...ascripts/members/components/filter_sort/sort_dropdown.vue
+9
-1
app/assets/javascripts/members/components/modals/leave_modal.vue
...ets/javascripts/members/components/modals/leave_modal.vue
+6
-1
app/assets/javascripts/members/components/modals/remove_group_link_modal.vue
...pts/members/components/modals/remove_group_link_modal.vue
+17
-2
app/assets/javascripts/members/components/table/expiration_datepicker.vue
...cripts/members/components/table/expiration_datepicker.vue
+6
-1
app/assets/javascripts/members/components/table/members_table.vue
...ts/javascripts/members/components/table/members_table.vue
+12
-2
app/assets/javascripts/members/components/table/role_dropdown.vue
...ts/javascripts/members/components/table/role_dropdown.vue
+6
-1
app/assets/javascripts/members/index.js
app/assets/javascripts/members/index.js
+14
-10
app/assets/javascripts/members/store/index.js
app/assets/javascripts/members/store/index.js
+1
-0
app/assets/javascripts/pages/groups/group_members/index.js
app/assets/javascripts/pages/groups/group_members/index.js
+5
-0
app/assets/javascripts/pages/projects/project_members/index.js
...ssets/javascripts/pages/projects/project_members/index.js
+5
-0
app/assets/javascripts/pipelines/components/graph/constants.js
...ssets/javascripts/pipelines/components/graph/constants.js
+3
-0
app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
...scripts/pipelines/components/graph/job_group_dropdown.vue
+7
-2
app/assets/javascripts/pipelines/components/graph/job_item.vue
...ssets/javascripts/pipelines/components/graph/job_item.vue
+21
-2
app/views/projects/show.html.haml
app/views/projects/show.html.haml
+1
-1
app/views/projects/tree/show.html.haml
app/views/projects/tree/show.html.haml
+1
-1
changelogs/unreleased/322043-insert-plan-trial.yml
changelogs/unreleased/322043-insert-plan-trial.yml
+5
-0
db/post_migrate/20210329102724_add_new_trail_plans.rb
db/post_migrate/20210329102724_add_new_trail_plans.rb
+41
-0
db/schema_migrations/20210329102724
db/schema_migrations/20210329102724
+1
-0
ee/app/assets/javascripts/members/components/ldap/ldap_dropdown_item.vue
...avascripts/members/components/ldap/ldap_dropdown_item.vue
+6
-1
ee/app/assets/javascripts/members/components/ldap/ldap_override_button.vue
...ascripts/members/components/ldap/ldap_override_button.vue
+6
-1
ee/app/assets/javascripts/members/components/ldap/ldap_override_confirmation_modal.vue
...bers/components/ldap/ldap_override_confirmation_modal.vue
+17
-2
ee/spec/frontend/members/components/action_buttons/user_action_buttons_spec.js
...ers/components/action_buttons/user_action_buttons_spec.js
+4
-0
ee/spec/frontend/members/components/ldap/ldap_dropdown_item_spec.js
...ontend/members/components/ldap/ldap_dropdown_item_spec.js
+12
-1
ee/spec/frontend/members/components/ldap/ldap_override_button_spec.js
...tend/members/components/ldap/ldap_override_button_spec.js
+12
-1
ee/spec/frontend/members/components/ldap/ldap_override_confirmation_modal_spec.js
.../components/ldap/ldap_override_confirmation_modal_spec.js
+14
-5
ee/spec/frontend/members/components/table/expiration_datepicker_spec.js
...nd/members/components/table/expiration_datepicker_spec.js
+4
-0
ee/spec/frontend/members/components/table/members_table_spec.js
...c/frontend/members/components/table/members_table_spec.js
+14
-7
ee/spec/frontend/members/components/table/role_dropdown_spec.js
...c/frontend/members/components/table/role_dropdown_spec.js
+4
-0
ee/spec/frontend/members/index_spec.js
ee/spec/frontend/members/index_spec.js
+5
-2
rubocop/cop/style/regexp_literal_mixed_preserve.rb
rubocop/cop/style/regexp_literal_mixed_preserve.rb
+33
-0
spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js
...ents/action_buttons/approve_access_request_button_spec.js
+12
-3
spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js
...omponents/action_buttons/remove_group_link_button_spec.js
+10
-1
spec/frontend/members/components/action_buttons/remove_member_button_spec.js
...rs/components/action_buttons/remove_member_button_spec.js
+12
-3
spec/frontend/members/components/action_buttons/resend_invite_button_spec.js
...rs/components/action_buttons/resend_invite_button_spec.js
+12
-3
spec/frontend/members/components/app_spec.js
spec/frontend/members/components/app_spec.js
+18
-7
spec/frontend/members/components/filter_sort/filter_sort_container_spec.js
...bers/components/filter_sort/filter_sort_container_spec.js
+18
-9
spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js
...omponents/filter_sort/members_filtered_search_bar_spec.js
+15
-8
spec/frontend/members/components/filter_sort/sort_dropdown_spec.js
...tend/members/components/filter_sort/sort_dropdown_spec.js
+16
-9
spec/frontend/members/components/modals/leave_modal_spec.js
spec/frontend/members/components/modals/leave_modal_spec.js
+12
-4
spec/frontend/members/components/modals/remove_group_link_modal_spec.js
...members/components/modals/remove_group_link_modal_spec.js
+15
-7
spec/frontend/members/components/table/expiration_datepicker_spec.js
...nd/members/components/table/expiration_datepicker_spec.js
+9
-1
spec/frontend/members/components/table/members_table_spec.js
spec/frontend/members/components/table/members_table_spec.js
+14
-7
spec/frontend/members/components/table/role_dropdown_spec.js
spec/frontend/members/components/table/role_dropdown_spec.js
+9
-1
spec/frontend/members/index_spec.js
spec/frontend/members/index_spec.js
+13
-7
spec/migrations/add_new_trail_plans_spec.rb
spec/migrations/add_new_trail_plans_spec.rb
+95
-0
spec/rubocop/cop/style/regexp_literal_mixed_preserve_spec.rb
spec/rubocop/cop/style/regexp_literal_mixed_preserve_spec.rb
+131
-0
No files found.
.rubocop.yml
View file @
8c5f2b7f
...
...
@@ -644,3 +644,16 @@ Cop/UserAdmin:
Performance/OpenStruct
:
Exclude
:
-
'
ee/spec/**/*.rb'
# See https://gitlab.com/gitlab-org/gitlab/-/issues/327495
Style/RegexpLiteral
:
Enabled
:
false
Style/RegexpLiteralMixedPreserve
:
Enabled
:
true
SupportedStyles
:
-
slashes
-
percent_r
-
mixed
-
mixed_preserve
EnforcedStyle
:
mixed_preserve
.rubocop_manual_todo.yml
View file @
8c5f2b7f
...
...
@@ -3330,3 +3330,60 @@ Gitlab/FeatureAvailableUsage:
-
'
ee/spec/models/project_spec.rb'
-
'
lib/api/helpers/related_resources_helpers.rb'
-
'
spec/models/concerns/featurable_spec.rb'
# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/327490
Style/RegexpLiteralMixedPreserve
:
Exclude
:
-
'
app/controllers/projects/repositories_controller.rb'
-
'
app/helpers/ci/variables_helper.rb'
-
'
app/models/alert_management/alert.rb'
-
'
app/models/application_setting.rb'
-
'
app/models/blob_viewer/go_mod.rb'
-
'
app/models/concerns/ci/maskable.rb'
-
'
app/models/operations/feature_flag.rb'
-
'
app/models/packages/go/module.rb'
-
'
app/models/project_services/chat_message/base_message.rb'
-
'
app/services/packages/conan/search_service.rb'
-
'
app/services/projects/update_remote_mirror_service.rb'
-
'
config/initializers/rspec_profiling.rb'
-
'
ee/app/models/status_page/project_setting.rb'
-
'
ee/app/presenters/vulnerability_presenter.rb'
-
'
ee/lib/api/geo_nodes.rb'
-
'
ee/lib/gitlab/vulnerabilities/standard_vulnerability.rb'
-
'
ee/spec/controllers/concerns/ee/routable_actions/sso_enforcement_redirect_spec.rb'
-
'
ee/spec/controllers/concerns/routable_actions_spec.rb'
-
'
ee/spec/controllers/groups/groups_controller_spec.rb'
-
'
ee/spec/features/groups/saml_enforcement_spec.rb'
-
'
ee/spec/features/markdown/metrics_spec.rb'
-
'
ee/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb'
-
'
ee/spec/models/project_services/jira_service_spec.rb'
-
'
ee/spec/services/jira/requests/issues/list_service_spec.rb'
-
'
lib/api/invitations.rb'
-
'
lib/gitlab/ci/pipeline/expression/lexeme/pattern.rb'
-
'
lib/gitlab/metrics/requests_rack_middleware.rb'
-
'
lib/gitlab/metrics/subscribers/active_record.rb'
-
'
lib/gitlab/regex.rb'
-
'
lib/gitlab/utils.rb'
-
'
lib/product_analytics/tracker.rb'
-
'
qa/qa/page/project/settings/advanced.rb'
-
'
qa/spec/service/docker_run/gitlab_runner_spec.rb'
-
'
rubocop/cop/gitlab/duplicate_spec_location.rb'
-
'
spec/features/clusters/cluster_health_dashboard_spec.rb'
-
'
spec/features/markdown/metrics_spec.rb'
-
'
spec/features/search/user_searches_for_code_spec.rb'
-
'
spec/features/snippets/embedded_snippet_spec.rb'
-
'
spec/helpers/diff_helper_spec.rb'
-
'
spec/helpers/releases_helper_spec.rb'
-
'
spec/lib/gitlab/ci/reports/test_case_spec.rb'
-
'
spec/lib/gitlab/consul/internal_spec.rb'
-
'
spec/lib/gitlab/import_export/shared_spec.rb'
-
'
spec/lib/gitlab/utils/usage_data_spec.rb'
-
'
spec/presenters/ci/build_runner_presenter_spec.rb'
-
'
spec/requests/api/projects_spec.rb'
-
'
spec/services/jira/requests/projects/list_service_spec.rb'
-
'
spec/support/capybara.rb'
-
'
spec/support/helpers/grafana_api_helpers.rb'
-
'
spec/support/helpers/query_recorder.rb'
-
'
spec/support/helpers/require_migration.rb'
-
'
spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb'
-
'
spec/views/layouts/_head.html.haml_spec.rb'
.rubocop_todo.yml
View file @
8c5f2b7f
...
...
@@ -922,13 +922,6 @@ Style/RedundantRegexpEscape:
Style/RedundantSelf
:
Enabled
:
false
# Offense count: 213
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral
:
Enabled
:
false
# Offense count: 53
# Cop supports --auto-correct.
Style/RescueModifier
:
...
...
app/assets/javascripts/members/components/action_buttons/approve_access_request_button.vue
View file @
8c5f2b7f
...
...
@@ -12,6 +12,7 @@ export default {
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
inject
:
[
'
namespace
'
],
props
:
{
memberId
:
{
type
:
Number
,
...
...
@@ -19,7 +20,11 @@ export default {
},
},
computed
:
{
...
mapState
([
'
memberPath
'
]),
...
mapState
({
memberPath
(
state
)
{
return
state
[
this
.
namespace
].
memberPath
;
},
}),
approvePath
()
{
return
this
.
memberPath
.
replace
(
/:id$/
,
`
${
this
.
memberId
}
/approve_access_request`
);
},
...
...
app/assets/javascripts/members/components/action_buttons/remove_group_link_button.vue
View file @
8c5f2b7f
...
...
@@ -12,6 +12,7 @@ export default {
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
inject
:
[
'
namespace
'
],
props
:
{
groupLink
:
{
type
:
Object
,
...
...
@@ -19,7 +20,11 @@ export default {
},
},
methods
:
{
...
mapActions
([
'
showRemoveGroupLinkModal
'
]),
...
mapActions
({
showRemoveGroupLinkModal
(
dispatch
,
payload
)
{
return
dispatch
(
`
${
this
.
namespace
}
/showRemoveGroupLinkModal`
,
payload
);
},
}),
},
};
</
script
>
...
...
app/assets/javascripts/members/components/action_buttons/remove_member_button.vue
View file @
8c5f2b7f
...
...
@@ -8,6 +8,7 @@ export default {
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
inject
:
[
'
namespace
'
],
props
:
{
memberId
:
{
type
:
Number
,
...
...
@@ -43,7 +44,11 @@ export default {
},
},
computed
:
{
...
mapState
([
'
memberPath
'
]),
...
mapState
({
memberPath
(
state
)
{
return
state
[
this
.
namespace
].
memberPath
;
},
}),
computedMemberPath
()
{
return
this
.
memberPath
.
replace
(
'
:id
'
,
this
.
memberId
);
},
...
...
app/assets/javascripts/members/components/action_buttons/resend_invite_button.vue
View file @
8c5f2b7f
...
...
@@ -12,6 +12,7 @@ export default {
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
inject
:
[
'
namespace
'
],
props
:
{
memberId
:
{
type
:
Number
,
...
...
@@ -19,7 +20,11 @@ export default {
},
},
computed
:
{
...
mapState
([
'
memberPath
'
]),
...
mapState
({
memberPath
(
state
)
{
return
state
[
this
.
namespace
].
memberPath
;
},
}),
resendPath
()
{
return
this
.
memberPath
.
replace
(
/:id$/
,
`
${
this
.
memberId
}
/resend_invite`
);
},
...
...
app/assets/javascripts/members/components/app.vue
View file @
8c5f2b7f
...
...
@@ -9,8 +9,16 @@ import MembersTable from './table/members_table.vue';
export
default
{
name
:
'
MembersApp
'
,
components
:
{
MembersTable
,
FilterSortContainer
,
GlAlert
},
inject
:
[
'
namespace
'
],
computed
:
{
...
mapState
([
'
showError
'
,
'
errorMessage
'
]),
...
mapState
({
showError
(
state
)
{
return
state
[
this
.
namespace
].
showError
;
},
errorMessage
(
state
)
{
return
state
[
this
.
namespace
].
errorMessage
;
},
}),
},
watch
:
{
showError
(
value
)
{
...
...
@@ -23,7 +31,9 @@ export default {
},
methods
:
{
...
mapMutations
({
hideError
:
HIDE_ERROR
,
hideError
(
commit
)
{
return
commit
(
`
${
this
.
namespace
}
/
${
HIDE_ERROR
}
`
);
},
}),
},
};
...
...
app/assets/javascripts/members/components/filter_sort/filter_sort_container.vue
View file @
8c5f2b7f
...
...
@@ -6,8 +6,16 @@ import SortDropdown from './sort_dropdown.vue';
export
default
{
name
:
'
FilterSortContainer
'
,
components
:
{
MembersFilteredSearchBar
,
SortDropdown
},
inject
:
[
'
namespace
'
],
computed
:
{
...
mapState
([
'
filteredSearchBar
'
,
'
tableSortableFields
'
]),
...
mapState
({
filteredSearchBar
(
state
)
{
return
state
[
this
.
namespace
].
filteredSearchBar
;
},
tableSortableFields
(
state
)
{
return
state
[
this
.
namespace
].
tableSortableFields
;
},
}),
showContainer
()
{
return
this
.
filteredSearchBar
.
show
||
this
.
showSortDropdown
;
},
...
...
app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue
View file @
8c5f2b7f
...
...
@@ -37,14 +37,18 @@ export default {
],
},
],
inject
:
[
'
sourceId
'
,
'
canManageMembers
'
],
inject
:
[
'
namespace
'
,
'
sourceId
'
,
'
canManageMembers
'
],
data
()
{
return
{
initialFilterValue
:
[],
};
},
computed
:
{
...
mapState
([
'
filteredSearchBar
'
]),
...
mapState
({
filteredSearchBar
(
state
)
{
return
state
[
this
.
namespace
].
filteredSearchBar
;
},
}),
tokens
()
{
return
this
.
$options
.
availableTokens
.
filter
((
token
)
=>
{
if
(
...
...
app/assets/javascripts/members/components/filter_sort/sort_dropdown.vue
View file @
8c5f2b7f
...
...
@@ -8,8 +8,16 @@ import { parseSortParam, buildSortHref } from '~/members/utils';
export
default
{
name
:
'
SortDropdown
'
,
components
:
{
GlSorting
,
GlSortingItem
},
inject
:
[
'
namespace
'
],
computed
:
{
...
mapState
([
'
tableSortableFields
'
,
'
filteredSearchBar
'
]),
...
mapState
({
tableSortableFields
(
state
)
{
return
state
[
this
.
namespace
].
tableSortableFields
;
},
filteredSearchBar
(
state
)
{
return
state
[
this
.
namespace
].
filteredSearchBar
;
},
}),
sort
()
{
return
parseSortParam
(
this
.
tableSortableFields
);
},
...
...
app/assets/javascripts/members/components/modals/leave_modal.vue
View file @
8c5f2b7f
...
...
@@ -23,6 +23,7 @@ export default {
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
inject
:
[
'
namespace
'
],
props
:
{
member
:
{
type
:
Object
,
...
...
@@ -30,7 +31,11 @@ export default {
},
},
computed
:
{
...
mapState
([
'
memberPath
'
]),
...
mapState
({
memberPath
(
state
)
{
return
state
[
this
.
namespace
].
memberPath
;
},
}),
leavePath
()
{
return
this
.
memberPath
.
replace
(
/:id$/
,
'
leave
'
);
},
...
...
app/assets/javascripts/members/components/modals/remove_group_link_modal.vue
View file @
8c5f2b7f
...
...
@@ -22,8 +22,19 @@ export default {
},
modalId
:
REMOVE_GROUP_LINK_MODAL_ID
,
components
:
{
GlModal
,
GlSprintf
,
GlForm
},
inject
:
[
'
namespace
'
],
computed
:
{
...
mapState
([
'
memberPath
'
,
'
groupLinkToRemove
'
,
'
removeGroupLinkModalVisible
'
]),
...
mapState
({
memberPath
(
state
)
{
return
state
[
this
.
namespace
].
memberPath
;
},
groupLinkToRemove
(
state
)
{
return
state
[
this
.
namespace
].
groupLinkToRemove
;
},
removeGroupLinkModalVisible
(
state
)
{
return
state
[
this
.
namespace
].
removeGroupLinkModalVisible
;
},
}),
groupLinkPath
()
{
return
this
.
memberPath
.
replace
(
/:id$/
,
this
.
groupLinkToRemove
?.
id
);
},
...
...
@@ -35,7 +46,11 @@ export default {
},
},
methods
:
{
...
mapActions
([
'
hideRemoveGroupLinkModal
'
]),
...
mapActions
({
hideRemoveGroupLinkModal
(
dispatch
)
{
return
dispatch
(
`
${
this
.
namespace
}
/hideRemoveGroupLinkModal`
);
},
}),
handlePrimary
()
{
this
.
$refs
.
form
.
$el
.
submit
();
},
...
...
app/assets/javascripts/members/components/table/expiration_datepicker.vue
View file @
8c5f2b7f
...
...
@@ -7,6 +7,7 @@ import { s__ } from '~/locale';
export
default
{
name
:
'
ExpirationDatepicker
'
,
components
:
{
GlDatepicker
},
inject
:
[
'
namespace
'
],
props
:
{
member
:
{
type
:
Object
,
...
...
@@ -46,7 +47,11 @@ export default {
}
},
methods
:
{
...
mapActions
([
'
updateMemberExpiration
'
]),
...
mapActions
({
updateMemberExpiration
(
dispatch
,
payload
)
{
return
dispatch
(
`
${
this
.
namespace
}
/updateMemberExpiration`
,
payload
);
},
}),
handleInput
(
date
)
{
this
.
busy
=
true
;
this
.
updateMemberExpiration
({
...
...
app/assets/javascripts/members/components/table/members_table.vue
View file @
8c5f2b7f
...
...
@@ -31,9 +31,19 @@ export default {
LdapOverrideConfirmationModal
:
()
=>
import
(
'
ee_component/members/components/ldap/ldap_override_confirmation_modal.vue
'
),
},
inject
:
[
'
currentUserId
'
],
inject
:
[
'
namespace
'
,
'
currentUserId
'
],
computed
:
{
...
mapState
([
'
members
'
,
'
tableFields
'
,
'
tableAttrs
'
]),
...
mapState
({
members
(
state
)
{
return
state
[
this
.
namespace
].
members
;
},
tableFields
(
state
)
{
return
state
[
this
.
namespace
].
tableFields
;
},
tableAttrs
(
state
)
{
return
state
[
this
.
namespace
].
tableAttrs
;
},
}),
filteredFields
()
{
return
FIELDS
.
filter
(
(
field
)
=>
this
.
tableFields
.
includes
(
field
.
key
)
&&
this
.
showField
(
field
),
...
...
app/assets/javascripts/members/components/table/role_dropdown.vue
View file @
8c5f2b7f
...
...
@@ -11,6 +11,7 @@ export default {
GlDropdownItem
,
LdapDropdownItem
:
()
=>
import
(
'
ee_component/members/components/ldap/ldap_dropdown_item.vue
'
),
},
inject
:
[
'
namespace
'
],
props
:
{
member
:
{
type
:
Object
,
...
...
@@ -44,7 +45,11 @@ export default {
}
},
methods
:
{
...
mapActions
([
'
updateMemberRole
'
]),
...
mapActions
({
updateMemberRole
(
dispatch
,
payload
)
{
return
dispatch
(
`
${
this
.
namespace
}
/updateMemberRole`
,
payload
);
},
}),
handleSelect
(
value
,
name
)
{
if
(
value
===
this
.
member
.
accessLevel
.
integerValue
)
{
return
;
...
...
app/assets/javascripts/members/index.js
View file @
8c5f2b7f
...
...
@@ -8,6 +8,7 @@ import membersStore from './store';
export
const
initMembersApp
=
(
el
,
{
namespace
,
tableFields
=
[],
tableAttrs
=
{},
tableSortableFields
=
[],
...
...
@@ -24,22 +25,25 @@ export const initMembersApp = (
const
{
sourceId
,
canManageMembers
,
...
vuexStoreAttributes
}
=
parseDataAttributes
(
el
);
const
store
=
new
Vuex
.
Store
(
membersStore
({
...
vuexStoreAttributes
,
tableFields
,
tableAttrs
,
tableSortableFields
,
requestFormatter
,
filteredSearchBar
,
}),
);
const
store
=
new
Vuex
.
Store
({
modules
:
{
[
namespace
]:
membersStore
({
...
vuexStoreAttributes
,
tableFields
,
tableAttrs
,
tableSortableFields
,
requestFormatter
,
filteredSearchBar
,
}),
},
});
return
new
Vue
({
el
,
components
:
{
App
},
store
,
provide
:
{
namespace
,
currentUserId
:
gon
.
current_user_id
||
null
,
sourceId
,
canManageMembers
,
...
...
app/assets/javascripts/members/store/index.js
View file @
8c5f2b7f
...
...
@@ -3,6 +3,7 @@ import mutations from 'ee_else_ce/members/store/mutations';
import
createState
from
'
ee_else_ce/members/store/state
'
;
export
default
(
initialState
)
=>
({
namespaced
:
true
,
state
:
createState
(
initialState
),
actions
,
mutations
,
...
...
app/assets/javascripts/pages/groups/group_members/index.js
View file @
8c5f2b7f
...
...
@@ -8,6 +8,7 @@ import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigg
import
{
s__
}
from
'
~/locale
'
;
import
memberExpirationDate
from
'
~/member_expiration_date
'
;
import
{
initMembersApp
}
from
'
~/members
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
groupLinkRequestFormatter
}
from
'
~/members/utils
'
;
import
UsersSelect
from
'
~/users_select
'
;
import
RemoveMemberModal
from
'
~/vue_shared/components/remove_member_modal.vue
'
;
...
...
@@ -29,6 +30,7 @@ function mountRemoveMemberModal() {
const
SHARED_FIELDS
=
[
'
account
'
,
'
expires
'
,
'
maxRole
'
,
'
expiration
'
,
'
actions
'
];
initMembersApp
(
document
.
querySelector
(
'
.js-group-members-list
'
),
{
namespace
:
MEMBER_TYPES
.
user
,
tableFields
:
SHARED_FIELDS
.
concat
([
'
source
'
,
'
granted
'
]),
tableAttrs
:
{
tr
:
{
'
data-qa-selector
'
:
'
member_row
'
}
},
tableSortableFields
:
[
'
account
'
,
'
granted
'
,
'
maxRole
'
,
'
lastSignIn
'
],
...
...
@@ -43,6 +45,7 @@ initMembersApp(document.querySelector('.js-group-members-list'), {
});
initMembersApp
(
document
.
querySelector
(
'
.js-group-group-links-list
'
),
{
namespace
:
MEMBER_TYPES
.
group
,
tableFields
:
SHARED_FIELDS
.
concat
(
'
granted
'
),
tableAttrs
:
{
table
:
{
'
data-qa-selector
'
:
'
groups_list
'
},
...
...
@@ -51,6 +54,7 @@ initMembersApp(document.querySelector('.js-group-group-links-list'), {
requestFormatter
:
groupLinkRequestFormatter
,
});
initMembersApp
(
document
.
querySelector
(
'
.js-group-invited-members-list
'
),
{
namespace
:
MEMBER_TYPES
.
invite
,
tableFields
:
SHARED_FIELDS
.
concat
(
'
invited
'
),
requestFormatter
:
groupMemberRequestFormatter
,
filteredSearchBar
:
{
...
...
@@ -62,6 +66,7 @@ initMembersApp(document.querySelector('.js-group-invited-members-list'), {
},
});
initMembersApp
(
document
.
querySelector
(
'
.js-group-access-requests-list
'
),
{
namespace
:
MEMBER_TYPES
.
accessRequest
,
tableFields
:
SHARED_FIELDS
.
concat
(
'
requested
'
),
requestFormatter
:
groupMemberRequestFormatter
,
});
...
...
app/assets/javascripts/pages/projects/project_members/index.js
View file @
8c5f2b7f
...
...
@@ -7,6 +7,7 @@ import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigg
import
{
s__
}
from
'
~/locale
'
;
import
memberExpirationDate
from
'
~/member_expiration_date
'
;
import
{
initMembersApp
}
from
'
~/members
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
groupLinkRequestFormatter
}
from
'
~/members/utils
'
;
import
{
projectMemberRequestFormatter
}
from
'
~/projects/members/utils
'
;
import
UsersSelect
from
'
~/users_select
'
;
...
...
@@ -42,6 +43,7 @@ new UsersSelect(); // eslint-disable-line no-new
const
SHARED_FIELDS
=
[
'
account
'
,
'
expires
'
,
'
maxRole
'
,
'
expiration
'
,
'
actions
'
];
initMembersApp
(
document
.
querySelector
(
'
.js-project-members-list
'
),
{
namespace
:
MEMBER_TYPES
.
user
,
tableFields
:
SHARED_FIELDS
.
concat
([
'
source
'
,
'
granted
'
]),
tableAttrs
:
{
tr
:
{
'
data-qa-selector
'
:
'
member_row
'
}
},
tableSortableFields
:
[
'
account
'
,
'
granted
'
,
'
maxRole
'
,
'
lastSignIn
'
],
...
...
@@ -56,6 +58,7 @@ initMembersApp(document.querySelector('.js-project-members-list'), {
});
initMembersApp
(
document
.
querySelector
(
'
.js-project-group-links-list
'
),
{
namespace
:
MEMBER_TYPES
.
group
,
tableFields
:
SHARED_FIELDS
.
concat
(
'
granted
'
),
tableAttrs
:
{
table
:
{
'
data-qa-selector
'
:
'
groups_list
'
},
...
...
@@ -72,11 +75,13 @@ initMembersApp(document.querySelector('.js-project-group-links-list'), {
});
initMembersApp
(
document
.
querySelector
(
'
.js-project-invited-members-list
'
),
{
namespace
:
MEMBER_TYPES
.
invite
,
tableFields
:
SHARED_FIELDS
.
concat
(
'
invited
'
),
requestFormatter
:
projectMemberRequestFormatter
,
});
initMembersApp
(
document
.
querySelector
(
'
.js-project-access-requests-list
'
),
{
namespace
:
MEMBER_TYPES
.
accessRequest
,
tableFields
:
SHARED_FIELDS
.
concat
(
'
requested
'
),
requestFormatter
:
projectMemberRequestFormatter
,
});
app/assets/javascripts/pipelines/components/graph/constants.js
View file @
8c5f2b7f
...
...
@@ -15,4 +15,7 @@ export const STAGE_VIEW = 'stage';
export
const
LAYER_VIEW
=
'
layer
'
;
export
const
VIEW_TYPE_KEY
=
'
pipeline_graph_view_type
'
;
export
const
SINGLE_JOB
=
'
single_job
'
;
export
const
JOB_DROPDOWN
=
'
job_dropdown
'
;
export
const
IID_FAILURE
=
'
missing_iid
'
;
app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
View file @
8c5f2b7f
<
script
>
import
{
reportToSentry
}
from
'
../../utils
'
;
import
{
JOB_DROPDOWN
,
SINGLE_JOB
}
from
'
./constants
'
;
import
JobItem
from
'
./job_item.vue
'
;
/**
...
...
@@ -28,6 +29,10 @@ export default {
default
:
''
,
},
},
jobItemTypes
:
{
jobDropdown
:
JOB_DROPDOWN
,
singleJob
:
SINGLE_JOB
,
},
computed
:
{
computedJobId
()
{
return
this
.
pipelineId
>
-
1
?
`
${
this
.
group
.
name
}
-
${
this
.
pipelineId
}
`
:
''
;
...
...
@@ -57,11 +62,10 @@ export default {
>
<div
class=
"gl-display-flex gl-align-items-center gl-justify-content-space-between"
>
<job-item
:
dropdown-length=
"group.size
"
:
type=
"$options.jobItemTypes.jobDropdown
"
:group-tooltip=
"tooltipText"
:job=
"group"
:stage-name=
"stageName"
@
pipelineActionRequestComplete=
"pipelineActionRequestComplete"
/>
<div
class=
"gl-font-weight-100 gl-font-size-lg gl-ml-n4"
>
{{
group
.
size
}}
</div>
...
...
@@ -75,6 +79,7 @@ export default {
<job-item
:dropdown-length=
"group.size"
:job=
"job"
:type=
"$options.jobItemTypes.singleJob"
css-class-job-name=
"mini-pipeline-graph-dropdown-item"
@
pipelineActionRequestComplete=
"pipelineActionRequestComplete"
/>
...
...
app/assets/javascripts/pipelines/components/graph/job_item.vue
View file @
8c5f2b7f
...
...
@@ -8,7 +8,7 @@ import { reportToSentry } from '../../utils';
import
ActionComponent
from
'
../jobs_shared/action_component.vue
'
;
import
JobNameComponent
from
'
../jobs_shared/job_name_component.vue
'
;
import
{
accessValue
}
from
'
./accessors
'
;
import
{
REST
}
from
'
./constants
'
;
import
{
REST
,
SINGLE_JOB
}
from
'
./constants
'
;
/**
* Renders the badge for the pipeline graph and the job's dropdown.
...
...
@@ -97,6 +97,11 @@ export default {
required
:
false
,
default
:
''
,
},
type
:
{
type
:
String
,
required
:
false
,
default
:
SINGLE_JOB
,
},
},
computed
:
{
boundary
()
{
...
...
@@ -111,6 +116,9 @@ export default {
hasDetails
()
{
return
accessValue
(
this
.
dataMethod
,
'
hasDetails
'
,
this
.
status
);
},
isSingleItem
()
{
return
this
.
type
===
SINGLE_JOB
;
},
nameComponent
()
{
return
this
.
hasDetails
?
'
gl-link
'
:
'
div
'
;
},
...
...
@@ -177,6 +185,17 @@ export default {
hideTooltips
()
{
this
.
$root
.
$emit
(
BV_HIDE_TOOLTIP
);
},
jobItemClick
(
evt
)
{
if
(
this
.
isSingleItem
)
{
/*
This is so the jobDropdown still toggles. Issue to refactor:
https://gitlab.com/gitlab-org/gitlab/-/issues/267117
*/
evt
.
stopPropagation
();
}
this
.
hideTooltips
();
},
pipelineActionRequestComplete
()
{
this
.
$emit
(
'
pipelineActionRequestComplete
'
);
},
...
...
@@ -201,7 +220,7 @@ export default {
:href="detailsPath"
class="js-pipeline-graph-job-link qa-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none gl-focus-text-decoration-none gl-hover-text-decoration-none gl-w-full"
:data-testid="testId"
@click
.stop="hideTooltips
"
@click
="jobItemClick
"
@mouseout="hideTooltips"
>
<div
class=
"ci-job-name-component gl-display-flex gl-align-items-center"
>
...
...
app/views/projects/show.html.haml
View file @
8c5f2b7f
-
current_route_path
=
request
.
fullpath
.
match
(
/-\/tree\/[^\/]+\/(.+$)/
).
to_a
[
1
]
-
current_route_path
=
request
.
fullpath
.
match
(
%r{-/tree/[^/]+/(.+$)}
).
to_a
[
1
]
-
add_page_startup_graphql_call
(
'repository/path_last_commit'
,
{
projectPath:
@project
.
full_path
,
ref:
current_ref
,
path:
current_route_path
||
""
})
-
@content_class
=
"limit-container-width"
unless
fluid_layout
-
@skip_current_level_breadcrumb
=
true
...
...
app/views/projects/tree/show.html.haml
View file @
8c5f2b7f
-
current_route_path
=
request
.
fullpath
.
match
(
/-\/tree\/[^\/]+\/(.+$)/
).
to_a
[
1
]
-
current_route_path
=
request
.
fullpath
.
match
(
%r{-/tree/[^/]+/(.+$)}
).
to_a
[
1
]
-
add_page_startup_graphql_call
(
'repository/path_last_commit'
,
{
projectPath:
@project
.
full_path
,
ref:
current_ref
,
path:
current_route_path
||
""
})
-
add_page_startup_graphql_call
(
'repository/permissions'
,
{
projectPath:
@project
.
full_path
})
-
add_page_startup_graphql_call
(
'repository/files'
,
{
nextPageCursor:
""
,
pageSize:
100
,
projectPath:
@project
.
full_path
,
ref:
current_ref
,
path:
current_route_path
||
"/"
})
...
...
changelogs/unreleased/322043-insert-plan-trial.yml
0 → 100644
View file @
8c5f2b7f
---
title
:
Add a migration to insert trail plans within SAAS for Ultimate and Premium plans
merge_request
:
57814
author
:
type
:
added
db/post_migrate/20210329102724_add_new_trail_plans.rb
0 → 100644
View file @
8c5f2b7f
# frozen_string_literal: true
class
AddNewTrailPlans
<
ActiveRecord
::
Migration
[
6.0
]
class
Plan
<
ActiveRecord
::
Base
self
.
inheritance_column
=
:_type_disabled
has_one
:limits
,
class_name:
'PlanLimits'
def
actual_limits
self
.
limits
||
self
.
build_limits
end
end
class
PlanLimits
<
ActiveRecord
::
Base
self
.
inheritance_column
=
:_type_disabled
belongs_to
:plan
end
def
create_plan_limits
(
plan_limit_name
,
plan
)
plan_limit
=
Plan
.
find_or_initialize_by
(
name:
plan_limit_name
).
actual_limits
.
dup
plan_limit
.
plan
=
plan
plan_limit
.
save!
end
def
up
return
unless
Gitlab
.
dev_env_or_com?
ultimate_trial
=
Plan
.
create!
(
name:
'ultimate_trial'
,
title:
'Ultimate Trial'
)
premium_trial
=
Plan
.
create!
(
name:
'premium_trial'
,
title:
'Premium Trial'
)
create_plan_limits
(
'gold'
,
ultimate_trial
)
create_plan_limits
(
'silver'
,
premium_trial
)
end
def
down
return
unless
Gitlab
.
dev_env_or_com?
Plan
.
where
(
name:
%w(ultimate_trial premium_trial)
).
delete_all
end
end
db/schema_migrations/20210329102724
0 → 100644
View file @
8c5f2b7f
b40c702ea6b2120da6fe11b213064a7a124dbc86bfb2d6785bfd2274c44f1e22
\ No newline at end of file
ee/app/assets/javascripts/members/components/ldap/ldap_dropdown_item.vue
View file @
8c5f2b7f
...
...
@@ -6,6 +6,7 @@ import { s__ } from '~/locale';
export
default
{
name
:
'
LdapDropdownItem
'
,
components
:
{
GlDropdownItem
,
GlDropdownDivider
},
inject
:
[
'
namespace
'
],
props
:
{
memberId
:
{
type
:
Number
,
...
...
@@ -13,7 +14,11 @@ export default {
},
},
methods
:
{
...
mapActions
([
'
updateLdapOverride
'
]),
...
mapActions
({
updateLdapOverride
(
dispatch
,
payload
)
{
return
dispatch
(
`
${
this
.
namespace
}
/updateLdapOverride`
,
payload
);
},
}),
handleClick
()
{
this
.
updateLdapOverride
({
memberId
:
this
.
memberId
,
override
:
false
})
.
then
(()
=>
{
...
...
ee/app/assets/javascripts/members/components/ldap/ldap_override_button.vue
View file @
8c5f2b7f
...
...
@@ -12,6 +12,7 @@ export default {
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
inject
:
[
'
namespace
'
],
props
:
{
member
:
{
type
:
Object
,
...
...
@@ -19,7 +20,11 @@ export default {
},
},
methods
:
{
...
mapActions
([
'
showLdapOverrideConfirmationModal
'
]),
...
mapActions
({
showLdapOverrideConfirmationModal
(
dispatch
,
payload
)
{
return
dispatch
(
`
${
this
.
namespace
}
/showLdapOverrideConfirmationModal`
,
payload
);
},
}),
},
};
</
script
>
...
...
ee/app/assets/javascripts/members/components/ldap/ldap_override_confirmation_modal.vue
View file @
8c5f2b7f
...
...
@@ -18,13 +18,21 @@ export default {
},
modalId
:
LDAP_OVERRIDE_CONFIRMATION_MODAL_ID
,
components
:
{
GlModal
,
GlSprintf
},
inject
:
[
'
namespace
'
],
data
()
{
return
{
busy
:
false
,
};
},
computed
:
{
...
mapState
([
'
memberToOverride
'
,
'
ldapOverrideConfirmationModalVisible
'
]),
...
mapState
({
memberToOverride
(
state
)
{
return
state
[
this
.
namespace
].
memberToOverride
;
},
ldapOverrideConfirmationModalVisible
(
state
)
{
return
state
[
this
.
namespace
].
ldapOverrideConfirmationModalVisible
;
},
}),
actionPrimary
()
{
return
{
text
:
this
.
$options
.
i18n
.
editPermissions
,
...
...
@@ -36,7 +44,14 @@ export default {
},
},
methods
:
{
...
mapActions
([
'
updateLdapOverride
'
,
'
hideLdapOverrideConfirmationModal
'
]),
...
mapActions
({
updateLdapOverride
(
dispatch
,
payload
)
{
return
dispatch
(
`
${
this
.
namespace
}
/updateLdapOverride`
,
payload
);
},
hideLdapOverrideConfirmationModal
(
dispatch
)
{
return
dispatch
(
`
${
this
.
namespace
}
/hideLdapOverrideConfirmationModal`
);
},
}),
handlePrimary
()
{
this
.
busy
=
true
;
...
...
ee/spec/frontend/members/components/action_buttons/user_action_buttons_spec.js
View file @
8c5f2b7f
...
...
@@ -3,12 +3,16 @@ import LdapOverrideButton from 'ee/members/components/ldap/ldap_override_button.
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
member
}
from
'
jest/members/mock_data
'
;
import
UserActionButtons
from
'
~/members/components/action_buttons/user_action_buttons.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
describe
(
'
UserActionButtons
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
(
propsData
=
{})
=>
{
wrapper
=
shallowMount
(
UserActionButtons
,
{
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
propsData
:
{
member
,
isCurrentUser
:
false
,
...
...
ee/spec/frontend/members/components/ldap/ldap_dropdown_item_spec.js
View file @
8c5f2b7f
...
...
@@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils';
import
Vuex
from
'
vuex
'
;
import
LdapDropdownItem
from
'
ee/members/components/ldap/ldap_dropdown_item.vue
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
...
...
@@ -19,7 +20,14 @@ describe('LdapDropdownItem', () => {
updateLdapOverride
:
jest
.
fn
(()
=>
Promise
.
resolve
()),
};
return
new
Vuex
.
Store
({
actions
});
return
new
Vuex
.
Store
({
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
actions
,
},
},
});
};
const
createComponent
=
(
propsData
=
{})
=>
{
...
...
@@ -30,6 +38,9 @@ describe('LdapDropdownItem', () => {
},
localVue
,
store
:
createStore
(),
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
mocks
:
{
$toast
,
},
...
...
ee/spec/frontend/members/components/ldap/ldap_override_button_spec.js
View file @
8c5f2b7f
...
...
@@ -4,6 +4,7 @@ import Vuex from 'vuex';
import
LdapOverrideButton
from
'
ee/members/components/ldap/ldap_override_button.vue
'
;
import
{
createMockDirective
,
getBinding
}
from
'
helpers/vue_mock_directive
'
;
import
{
member
}
from
'
jest/members/mock_data
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
...
...
@@ -17,7 +18,14 @@ describe('LdapOverrideButton', () => {
showLdapOverrideConfirmationModal
:
jest
.
fn
(),
};
return
new
Vuex
.
Store
({
actions
});
return
new
Vuex
.
Store
({
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
actions
,
},
},
});
};
const
createComponent
=
(
propsData
=
{})
=>
{
...
...
@@ -28,6 +36,9 @@ describe('LdapOverrideButton', () => {
...
propsData
,
},
store
:
createStore
(),
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
directives
:
{
GlTooltip
:
createMockDirective
(),
},
...
...
ee/spec/frontend/members/components/ldap/ldap_override_confirmation_modal_spec.js
View file @
8c5f2b7f
...
...
@@ -7,6 +7,7 @@ import LdapOverrideConfirmationModal from 'ee/members/components/ldap/ldap_overr
import
{
LDAP_OVERRIDE_CONFIRMATION_MODAL_ID
}
from
'
ee/members/constants
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
member
}
from
'
jest/members/mock_data
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
...
...
@@ -31,12 +32,17 @@ describe('LdapOverrideConfirmationModal', () => {
};
return
new
Vuex
.
Store
({
state
:
{
memberToOverride
:
member
,
ldapOverrideConfirmationModalVisible
:
true
,
...
state
,
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
memberToOverride
:
member
,
ldapOverrideConfirmationModalVisible
:
true
,
...
state
,
},
actions
,
},
},
actions
,
});
};
...
...
@@ -44,6 +50,9 @@ describe('LdapOverrideConfirmationModal', () => {
wrapper
=
mount
(
LdapOverrideConfirmationModal
,
{
localVue
,
store
:
createStore
(
state
),
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
attrs
:
{
static
:
true
,
},
...
...
ee/spec/frontend/members/components/table/expiration_datepicker_spec.js
View file @
8c5f2b7f
...
...
@@ -2,12 +2,16 @@ import { GlDatepicker } from '@gitlab/ui';
import
{
mount
}
from
'
@vue/test-utils
'
;
import
{
member
}
from
'
jest/members/mock_data
'
;
import
ExpirationDatepicker
from
'
~/members/components/table/expiration_datepicker.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
describe
(
'
ExpirationDatepicker
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
(
propsData
=
{})
=>
{
wrapper
=
mount
(
ExpirationDatepicker
,
{
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
propsData
,
});
};
...
...
ee/spec/frontend/members/components/table/members_table_spec.js
View file @
8c5f2b7f
...
...
@@ -3,6 +3,7 @@ import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
import
Vuex
from
'
vuex
'
;
import
{
member
as
memberMock
,
directMember
,
members
}
from
'
jest/members/mock_data
'
;
import
MembersTable
from
'
~/members/components/table/members_table.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
...
...
@@ -12,14 +13,19 @@ describe('MemberList', () => {
const
createStore
=
(
state
=
{})
=>
{
return
new
Vuex
.
Store
({
state
:
{
members
:
[],
tableFields
:
[],
tableAttrs
:
{
table
:
{
'
data-qa-selector
'
:
'
members_list
'
},
tr
:
{
'
data-qa-selector
'
:
'
member_row
'
},
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
members
:
[],
tableFields
:
[],
tableAttrs
:
{
table
:
{
'
data-qa-selector
'
:
'
members_list
'
},
tr
:
{
'
data-qa-selector
'
:
'
member_row
'
},
},
...
state
,
},
},
...
state
,
},
});
};
...
...
@@ -31,6 +37,7 @@ describe('MemberList', () => {
provide
:
{
sourceId
:
1
,
currentUserId
:
1
,
namespace
:
MEMBER_TYPES
.
user
,
},
stubs
:
[
'
member-avatar
'
,
...
...
ee/spec/frontend/members/components/table/role_dropdown_spec.js
View file @
8c5f2b7f
...
...
@@ -4,12 +4,16 @@ import LdapDropdownItem from 'ee/members/components/ldap/ldap_dropdown_item.vue'
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
member
}
from
'
jest/members/mock_data
'
;
import
RoleDropdown
from
'
~/members/components/table/role_dropdown.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
describe
(
'
RoleDropdown
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
(
propsData
=
{})
=>
{
wrapper
=
shallowMount
(
RoleDropdown
,
{
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
propsData
:
{
member
,
permissions
:
{},
...
...
ee/spec/frontend/members/index_spec.js
View file @
8c5f2b7f
import
{
membersJsonString
}
from
'
jest/members/mock_data
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
initMembersApp
}
from
'
~/members/index
'
;
describe
(
'
initMembersApp
'
,
()
=>
{
...
...
@@ -6,7 +7,9 @@ describe('initMembersApp', () => {
let
vm
;
const
createVm
=
()
=>
{
vm
=
initMembersApp
(
el
,
{});
vm
=
initMembersApp
(
el
,
{
namespace
:
MEMBER_TYPES
.
user
,
});
};
beforeEach
(()
=>
{
...
...
@@ -24,7 +27,7 @@ describe('initMembersApp', () => {
it
(
'
sets `ldapOverridePath` in Vuex store
'
,
()
=>
{
createVm
();
expect
(
vm
.
$store
.
state
.
ldapOverridePath
).
toBe
(
expect
(
vm
.
$store
.
state
[
MEMBER_TYPES
.
user
]
.
ldapOverridePath
).
toBe
(
'
/groups/ldap-group/-/group_members/:id/override
'
,
);
});
...
...
rubocop/cop/style/regexp_literal_mixed_preserve.rb
0 → 100644
View file @
8c5f2b7f
# frozen_string_literal: true
module
RuboCop
module
Cop
module
Style
# This cop is based on `Style/RegexpLiteral` but adds a new
# `EnforcedStyle` option `mixed_preserve`.
#
# This cop will be removed once the upstream PR is merged and RuboCop upgraded.
#
# See https://github.com/rubocop/rubocop/pull/9688
class
RegexpLiteralMixedPreserve
<
RuboCop
::
Cop
::
Style
::
RegexpLiteral
module
Patch
private
def
allowed_slash_literal?
(
node
)
super
||
allowed_mixed_preserve?
(
node
)
end
def
allowed_percent_r_literal?
(
node
)
super
||
allowed_mixed_preserve?
(
node
)
end
def
allowed_mixed_preserve?
(
node
)
style
==
:mixed_preserve
&&
!
contains_disallowed_slash?
(
node
)
end
end
prepend
Patch
end
end
end
end
spec/frontend/members/components/action_buttons/approve_access_request_button_spec.js
View file @
8c5f2b7f
...
...
@@ -3,6 +3,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import
Vuex
from
'
vuex
'
;
import
{
createMockDirective
,
getBinding
}
from
'
helpers/vue_mock_directive
'
;
import
ApproveAccessRequestButton
from
'
~/members/components/action_buttons/approve_access_request_button.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
jest
.
mock
(
'
~/lib/utils/csrf
'
,
()
=>
({
token
:
'
mock-csrf-token
'
}));
...
...
@@ -14,9 +15,14 @@ describe('ApproveAccessRequestButton', () => {
const
createStore
=
(
state
=
{})
=>
{
return
new
Vuex
.
Store
({
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_members/:id
'
,
...
state
,
modules
:
{
[
MEMBER_TYPES
.
accessRequest
]:
{
namespaced
:
true
,
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_members/:id
'
,
...
state
,
},
},
},
});
};
...
...
@@ -25,6 +31,9 @@ describe('ApproveAccessRequestButton', () => {
wrapper
=
shallowMount
(
ApproveAccessRequestButton
,
{
localVue
,
store
:
createStore
(
state
),
provide
:
{
namespace
:
MEMBER_TYPES
.
accessRequest
,
},
propsData
:
{
memberId
:
1
,
...
propsData
,
...
...
spec/frontend/members/components/action_buttons/remove_group_link_button_spec.js
View file @
8c5f2b7f
...
...
@@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils';
import
Vuex
from
'
vuex
'
;
import
{
createMockDirective
,
getBinding
}
from
'
helpers/vue_mock_directive
'
;
import
RemoveGroupLinkButton
from
'
~/members/components/action_buttons/remove_group_link_button.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
group
}
from
'
../../mock_data
'
;
const
localVue
=
createLocalVue
();
...
...
@@ -17,7 +18,12 @@ describe('RemoveGroupLinkButton', () => {
const
createStore
=
()
=>
{
return
new
Vuex
.
Store
({
actions
,
modules
:
{
[
MEMBER_TYPES
.
group
]:
{
namespaced
:
true
,
actions
,
},
},
});
};
...
...
@@ -25,6 +31,9 @@ describe('RemoveGroupLinkButton', () => {
wrapper
=
mount
(
RemoveGroupLinkButton
,
{
localVue
,
store
:
createStore
(),
provide
:
{
namespace
:
MEMBER_TYPES
.
group
,
},
propsData
:
{
groupLink
:
group
,
},
...
...
spec/frontend/members/components/action_buttons/remove_member_button_spec.js
View file @
8c5f2b7f
...
...
@@ -2,6 +2,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import
Vuex
from
'
vuex
'
;
import
{
createMockDirective
,
getBinding
}
from
'
helpers/vue_mock_directive
'
;
import
RemoveMemberButton
from
'
~/members/components/action_buttons/remove_member_button.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
...
...
@@ -11,9 +12,14 @@ describe('RemoveMemberButton', () => {
const
createStore
=
(
state
=
{})
=>
{
return
new
Vuex
.
Store
({
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_members/:id
'
,
...
state
,
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_members/:id
'
,
...
state
,
},
},
},
});
};
...
...
@@ -22,6 +28,9 @@ describe('RemoveMemberButton', () => {
wrapper
=
shallowMount
(
RemoveMemberButton
,
{
localVue
,
store
:
createStore
(
state
),
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
propsData
:
{
memberId
:
1
,
memberType
:
'
GroupMember
'
,
...
...
spec/frontend/members/components/action_buttons/resend_invite_button_spec.js
View file @
8c5f2b7f
...
...
@@ -3,6 +3,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import
Vuex
from
'
vuex
'
;
import
{
createMockDirective
,
getBinding
}
from
'
helpers/vue_mock_directive
'
;
import
ResendInviteButton
from
'
~/members/components/action_buttons/resend_invite_button.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
jest
.
mock
(
'
~/lib/utils/csrf
'
,
()
=>
({
token
:
'
mock-csrf-token
'
}));
...
...
@@ -14,9 +15,14 @@ describe('ResendInviteButton', () => {
const
createStore
=
(
state
=
{})
=>
{
return
new
Vuex
.
Store
({
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_members/:id
'
,
...
state
,
modules
:
{
[
MEMBER_TYPES
.
invite
]:
{
namespaced
:
true
,
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_members/:id
'
,
...
state
,
},
},
},
});
};
...
...
@@ -25,6 +31,9 @@ describe('ResendInviteButton', () => {
wrapper
=
shallowMount
(
ResendInviteButton
,
{
localVue
,
store
:
createStore
(
state
),
provide
:
{
namespace
:
MEMBER_TYPES
.
invite
,
},
propsData
:
{
memberId
:
1
,
...
propsData
,
...
...
spec/frontend/members/components/app_spec.js
View file @
8c5f2b7f
...
...
@@ -5,6 +5,7 @@ import Vuex from 'vuex';
import
*
as
commonUtils
from
'
~/lib/utils/common_utils
'
;
import
MembersApp
from
'
~/members/components/app.vue
'
;
import
FilterSortContainer
from
'
~/members/components/filter_sort/filter_sort_container.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
RECEIVE_MEMBER_ROLE_ERROR
,
HIDE_ERROR
}
from
'
~/members/store/mutation_types
'
;
import
mutations
from
'
~/members/store/mutations
'
;
...
...
@@ -17,16 +18,24 @@ describe('MembersApp', () => {
const
createComponent
=
(
state
=
{},
options
=
{})
=>
{
store
=
new
Vuex
.
Store
({
state
:
{
showError
:
true
,
errorMessage
:
'
Something went wrong, please try again.
'
,
...
state
,
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
showError
:
true
,
errorMessage
:
'
Something went wrong, please try again.
'
,
...
state
,
},
mutations
,
},
},
mutations
,
});
wrapper
=
shallowMount
(
MembersApp
,
{
localVue
,
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
store
,
...
options
,
});
...
...
@@ -48,7 +57,9 @@ describe('MembersApp', () => {
it
(
'
renders and scrolls to error alert
'
,
async
()
=>
{
createComponent
({
showError
:
false
,
errorMessage
:
''
});
store
.
commit
(
RECEIVE_MEMBER_ROLE_ERROR
,
{
error
:
new
Error
(
'
Network Error
'
)
});
store
.
commit
(
`
${
MEMBER_TYPES
.
user
}
/
${
RECEIVE_MEMBER_ROLE_ERROR
}
`
,
{
error
:
new
Error
(
'
Network Error
'
),
});
await
nextTick
();
...
...
@@ -66,7 +77,7 @@ describe('MembersApp', () => {
it
(
'
does not render and scroll to error alert
'
,
async
()
=>
{
createComponent
();
store
.
commit
(
HIDE_ERROR
);
store
.
commit
(
`
${
MEMBER_TYPES
.
user
}
/
${
HIDE_ERROR
}
`
);
await
nextTick
();
...
...
spec/frontend/members/components/filter_sort/filter_sort_container_spec.js
View file @
8c5f2b7f
...
...
@@ -3,6 +3,7 @@ import Vuex from 'vuex';
import
FilterSortContainer
from
'
~/members/components/filter_sort/filter_sort_container.vue
'
;
import
MembersFilteredSearchBar
from
'
~/members/components/filter_sort/members_filtered_search_bar.vue
'
;
import
SortDropdown
from
'
~/members/components/filter_sort/sort_dropdown.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
...
...
@@ -12,22 +13,30 @@ describe('FilterSortContainer', () => {
const
createComponent
=
(
state
)
=>
{
const
store
=
new
Vuex
.
Store
({
state
:
{
filteredSearchBar
:
{
show
:
true
,
tokens
:
[
'
two_factor
'
],
searchParam
:
'
search
'
,
placeholder
:
'
Filter members
'
,
recentSearchesStorageKey
:
'
group_members
'
,
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
filteredSearchBar
:
{
show
:
true
,
tokens
:
[
'
two_factor
'
],
searchParam
:
'
search
'
,
placeholder
:
'
Filter members
'
,
recentSearchesStorageKey
:
'
group_members
'
,
},
tableSortableFields
:
[
'
account
'
],
...
state
,
},
},
tableSortableFields
:
[
'
account
'
],
...
state
,
},
});
wrapper
=
shallowMount
(
FilterSortContainer
,
{
localVue
,
store
,
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
});
};
...
...
spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js
View file @
8c5f2b7f
...
...
@@ -2,6 +2,7 @@ import { GlFilteredSearchToken } from '@gitlab/ui';
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
MembersFilteredSearchBar
from
'
~/members/components/filter_sort/members_filtered_search_bar.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
FilteredSearchBar
from
'
~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
'
;
const
localVue
=
createLocalVue
();
...
...
@@ -12,15 +13,20 @@ describe('MembersFilteredSearchBar', () => {
const
createComponent
=
({
state
=
{},
provide
=
{}
}
=
{})
=>
{
const
store
=
new
Vuex
.
Store
({
state
:
{
filteredSearchBar
:
{
show
:
true
,
tokens
:
[
'
two_factor
'
],
searchParam
:
'
search
'
,
placeholder
:
'
Filter members
'
,
recentSearchesStorageKey
:
'
group_members
'
,
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
filteredSearchBar
:
{
show
:
true
,
tokens
:
[
'
two_factor
'
],
searchParam
:
'
search
'
,
placeholder
:
'
Filter members
'
,
recentSearchesStorageKey
:
'
group_members
'
,
},
...
state
,
},
},
...
state
,
},
});
...
...
@@ -29,6 +35,7 @@ describe('MembersFilteredSearchBar', () => {
provide
:
{
sourceId
:
1
,
canManageMembers
:
true
,
namespace
:
MEMBER_TYPES
.
user
,
...
provide
,
},
store
,
...
...
spec/frontend/members/components/filter_sort/sort_dropdown_spec.js
View file @
8c5f2b7f
...
...
@@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils';
import
Vuex
from
'
vuex
'
;
import
*
as
urlUtilities
from
'
~/lib/utils/url_utility
'
;
import
SortDropdown
from
'
~/members/components/filter_sort/sort_dropdown.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
...
...
@@ -14,16 +15,21 @@ describe('SortDropdown', () => {
const
createComponent
=
(
state
)
=>
{
const
store
=
new
Vuex
.
Store
({
state
:
{
tableSortableFields
:
[
'
account
'
,
'
granted
'
,
'
expires
'
,
'
maxRole
'
,
'
lastSignIn
'
],
filteredSearchBar
:
{
show
:
true
,
tokens
:
[
'
two_factor
'
],
searchParam
:
'
search
'
,
placeholder
:
'
Filter members
'
,
recentSearchesStorageKey
:
'
group_members
'
,
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
tableSortableFields
:
[
'
account
'
,
'
granted
'
,
'
expires
'
,
'
maxRole
'
,
'
lastSignIn
'
],
filteredSearchBar
:
{
show
:
true
,
tokens
:
[
'
two_factor
'
],
searchParam
:
'
search
'
,
placeholder
:
'
Filter members
'
,
recentSearchesStorageKey
:
'
group_members
'
,
},
...
state
,
},
},
...
state
,
},
});
...
...
@@ -31,6 +37,7 @@ describe('SortDropdown', () => {
localVue
,
provide
:
{
sourceId
:
1
,
namespace
:
MEMBER_TYPES
.
user
,
},
store
,
});
...
...
spec/frontend/members/components/modals/leave_modal_spec.js
View file @
8c5f2b7f
...
...
@@ -4,7 +4,7 @@ import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
import
{
nextTick
}
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
LeaveModal
from
'
~/members/components/modals/leave_modal.vue
'
;
import
{
LEAVE_MODAL_ID
}
from
'
~/members/constants
'
;
import
{
LEAVE_MODAL_ID
,
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
member
}
from
'
../../mock_data
'
;
jest
.
mock
(
'
~/lib/utils/csrf
'
,
()
=>
({
token
:
'
mock-csrf-token
'
}));
...
...
@@ -17,9 +17,14 @@ describe('LeaveModal', () => {
const
createStore
=
(
state
=
{})
=>
{
return
new
Vuex
.
Store
({
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_members/:id
'
,
...
state
,
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_members/:id
'
,
...
state
,
},
},
},
});
};
...
...
@@ -28,6 +33,9 @@ describe('LeaveModal', () => {
wrapper
=
mount
(
LeaveModal
,
{
localVue
,
store
:
createStore
(
state
),
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
propsData
:
{
member
,
...
propsData
,
...
...
spec/frontend/members/components/modals/remove_group_link_modal_spec.js
View file @
8c5f2b7f
...
...
@@ -4,7 +4,7 @@ import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
import
{
nextTick
}
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
RemoveGroupLinkModal
from
'
~/members/components/modals/remove_group_link_modal.vue
'
;
import
{
REMOVE_GROUP_LINK_MODAL_ID
}
from
'
~/members/constants
'
;
import
{
REMOVE_GROUP_LINK_MODAL_ID
,
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
group
}
from
'
../../mock_data
'
;
jest
.
mock
(
'
~/lib/utils/csrf
'
,
()
=>
({
token
:
'
mock-csrf-token
'
}));
...
...
@@ -21,13 +21,18 @@ describe('RemoveGroupLinkModal', () => {
const
createStore
=
(
state
=
{})
=>
{
return
new
Vuex
.
Store
({
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_links/:id
'
,
groupLinkToRemove
:
group
,
removeGroupLinkModalVisible
:
true
,
...
state
,
modules
:
{
[
MEMBER_TYPES
.
group
]:
{
namespaced
:
true
,
state
:
{
memberPath
:
'
/groups/foo-bar/-/group_links/:id
'
,
groupLinkToRemove
:
group
,
removeGroupLinkModalVisible
:
true
,
...
state
,
},
actions
,
},
},
actions
,
});
};
...
...
@@ -35,6 +40,9 @@ describe('RemoveGroupLinkModal', () => {
wrapper
=
mount
(
RemoveGroupLinkModal
,
{
localVue
,
store
:
createStore
(
state
),
provide
:
{
namespace
:
MEMBER_TYPES
.
group
,
},
attrs
:
{
static
:
true
,
},
...
...
spec/frontend/members/components/table/expiration_datepicker_spec.js
View file @
8c5f2b7f
...
...
@@ -5,6 +5,7 @@ import Vuex from 'vuex';
import
{
useFakeDate
}
from
'
helpers/fake_date
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
ExpirationDatepicker
from
'
~/members/components/table/expiration_datepicker.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
member
}
from
'
../../mock_data
'
;
const
localVue
=
createLocalVue
();
...
...
@@ -31,7 +32,11 @@ describe('ExpirationDatepicker', () => {
),
};
return
new
Vuex
.
Store
({
actions
});
return
new
Vuex
.
Store
({
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
actions
},
},
});
};
const
createComponent
=
(
propsData
=
{})
=>
{
...
...
@@ -41,6 +46,9 @@ describe('ExpirationDatepicker', () => {
permissions
:
{
canUpdate
:
true
},
...
propsData
,
},
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
localVue
,
store
:
createStore
(),
mocks
:
{
...
...
spec/frontend/members/components/table/members_table_spec.js
View file @
8c5f2b7f
...
...
@@ -14,6 +14,7 @@ import MemberAvatar from '~/members/components/table/member_avatar.vue';
import
MemberSource
from
'
~/members/components/table/member_source.vue
'
;
import
MembersTable
from
'
~/members/components/table/members_table.vue
'
;
import
RoleDropdown
from
'
~/members/components/table/role_dropdown.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
*
as
initUserPopovers
from
'
~/user_popovers
'
;
import
{
member
as
memberMock
,
directMember
,
invite
,
accessRequest
}
from
'
../../mock_data
'
;
...
...
@@ -25,14 +26,19 @@ describe('MembersTable', () => {
const
createStore
=
(
state
=
{})
=>
{
return
new
Vuex
.
Store
({
state
:
{
members
:
[],
tableFields
:
[],
tableAttrs
:
{
table
:
{
'
data-qa-selector
'
:
'
members_list
'
},
tr
:
{
'
data-qa-selector
'
:
'
member_row
'
},
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
state
:
{
members
:
[],
tableFields
:
[],
tableAttrs
:
{
table
:
{
'
data-qa-selector
'
:
'
members_list
'
},
tr
:
{
'
data-qa-selector
'
:
'
member_row
'
},
},
...
state
,
},
},
...
state
,
},
});
};
...
...
@@ -44,6 +50,7 @@ describe('MembersTable', () => {
provide
:
{
sourceId
:
1
,
currentUserId
:
1
,
namespace
:
MEMBER_TYPES
.
user
,
...
provide
,
},
stubs
:
[
...
...
spec/frontend/members/components/table/role_dropdown_spec.js
View file @
8c5f2b7f
...
...
@@ -7,6 +7,7 @@ import Vuex from 'vuex';
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
BV_DROPDOWN_SHOW
}
from
'
~/lib/utils/constants
'
;
import
RoleDropdown
from
'
~/members/components/table/role_dropdown.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
member
}
from
'
../../mock_data
'
;
const
localVue
=
createLocalVue
();
...
...
@@ -24,11 +25,18 @@ describe('RoleDropdown', () => {
updateMemberRole
:
jest
.
fn
(()
=>
Promise
.
resolve
()),
};
return
new
Vuex
.
Store
({
actions
});
return
new
Vuex
.
Store
({
modules
:
{
[
MEMBER_TYPES
.
user
]:
{
namespaced
:
true
,
actions
},
},
});
};
const
createComponent
=
(
propsData
=
{})
=>
{
wrapper
=
mount
(
RoleDropdown
,
{
provide
:
{
namespace
:
MEMBER_TYPES
.
user
,
},
propsData
:
{
member
,
permissions
:
{},
...
...
spec/frontend/members/index_spec.js
View file @
8c5f2b7f
import
{
createWrapper
}
from
'
@vue/test-utils
'
;
import
MembersApp
from
'
~/members/components/app.vue
'
;
import
{
MEMBER_TYPES
}
from
'
~/members/constants
'
;
import
{
initMembersApp
}
from
'
~/members/index
'
;
import
{
membersJsonString
,
members
}
from
'
./mock_data
'
;
...
...
@@ -10,6 +11,7 @@ describe('initMembersApp', () => {
const
setup
=
()
=>
{
vm
=
initMembersApp
(
el
,
{
namespace
:
MEMBER_TYPES
.
user
,
tableFields
:
[
'
account
'
],
tableAttrs
:
{
table
:
{
'
data-qa-selector
'
:
'
members_list
'
}
},
tableSortableFields
:
[
'
account
'
],
...
...
@@ -45,42 +47,46 @@ describe('initMembersApp', () => {
it
(
'
parses and sets `members` in Vuex store
'
,
()
=>
{
setup
();
expect
(
vm
.
$store
.
state
.
members
).
toEqual
(
members
);
expect
(
vm
.
$store
.
state
[
MEMBER_TYPES
.
user
]
.
members
).
toEqual
(
members
);
});
it
(
'
sets `tableFields` in Vuex store
'
,
()
=>
{
setup
();
expect
(
vm
.
$store
.
state
.
tableFields
).
toEqual
([
'
account
'
]);
expect
(
vm
.
$store
.
state
[
MEMBER_TYPES
.
user
]
.
tableFields
).
toEqual
([
'
account
'
]);
});
it
(
'
sets `tableAttrs` in Vuex store
'
,
()
=>
{
setup
();
expect
(
vm
.
$store
.
state
.
tableAttrs
).
toEqual
({
table
:
{
'
data-qa-selector
'
:
'
members_list
'
}
});
expect
(
vm
.
$store
.
state
[
MEMBER_TYPES
.
user
].
tableAttrs
).
toEqual
({
table
:
{
'
data-qa-selector
'
:
'
members_list
'
},
});
});
it
(
'
sets `tableSortableFields` in Vuex store
'
,
()
=>
{
setup
();
expect
(
vm
.
$store
.
state
.
tableSortableFields
).
toEqual
([
'
account
'
]);
expect
(
vm
.
$store
.
state
[
MEMBER_TYPES
.
user
]
.
tableSortableFields
).
toEqual
([
'
account
'
]);
});
it
(
'
sets `requestFormatter` in Vuex store
'
,
()
=>
{
setup
();
expect
(
vm
.
$store
.
state
.
requestFormatter
()).
toEqual
({});
expect
(
vm
.
$store
.
state
[
MEMBER_TYPES
.
user
]
.
requestFormatter
()).
toEqual
({});
});
it
(
'
sets `filteredSearchBar` in Vuex store
'
,
()
=>
{
setup
();
expect
(
vm
.
$store
.
state
.
filteredSearchBar
).
toEqual
({
show
:
false
});
expect
(
vm
.
$store
.
state
[
MEMBER_TYPES
.
user
]
.
filteredSearchBar
).
toEqual
({
show
:
false
});
});
it
(
'
sets `memberPath` in Vuex store
'
,
()
=>
{
setup
();
expect
(
vm
.
$store
.
state
.
memberPath
).
toBe
(
'
/groups/foo-bar/-/group_members/:id
'
);
expect
(
vm
.
$store
.
state
[
MEMBER_TYPES
.
user
].
memberPath
).
toBe
(
'
/groups/foo-bar/-/group_members/:id
'
,
);
});
});
spec/migrations/add_new_trail_plans_spec.rb
0 → 100644
View file @
8c5f2b7f
# frozen_string_literal: true
require
'spec_helper'
require_migration!
RSpec
.
describe
AddNewTrailPlans
,
:migration
do
describe
'#up'
do
before
do
allow
(
Gitlab
).
to
receive
(
:dev_env_or_com?
).
and_return
true
end
it
'creates 2 entries within the plans table'
do
expect
{
migrate!
}.
to
change
{
AddNewTrailPlans
::
Plan
.
count
}.
by
2
expect
(
AddNewTrailPlans
::
Plan
.
last
(
2
).
pluck
(
:name
)).
to
match_array
(
%w(ultimate_trial premium_trial)
)
end
it
'creates 2 entries for plan limits'
do
expect
{
migrate!
}.
to
change
{
AddNewTrailPlans
::
PlanLimits
.
count
}.
by
2
end
context
'when the plan limits for gold and silver exists'
do
before
do
table
(
:plans
).
create!
(
id:
1
,
name:
'gold'
,
title:
'Gold'
)
table
(
:plan_limits
).
create!
(
id:
1
,
plan_id:
1
,
storage_size_limit:
2000
)
table
(
:plans
).
create!
(
id:
2
,
name:
'silver'
,
title:
'Silver'
)
table
(
:plan_limits
).
create!
(
id:
2
,
plan_id:
2
,
storage_size_limit:
1000
)
end
it
'duplicates the gold and silvers plan limits entries'
do
migrate!
ultimate_plan_limits
=
AddNewTrailPlans
::
Plan
.
find_by
(
name:
'ultimate_trial'
).
limits
expect
(
ultimate_plan_limits
.
storage_size_limit
).
to
be
2000
premium_plan_limits
=
AddNewTrailPlans
::
Plan
.
find_by
(
name:
'premium_trial'
).
limits
expect
(
premium_plan_limits
.
storage_size_limit
).
to
be
1000
end
end
context
'when the instance is not SaaS'
do
before
do
allow
(
Gitlab
).
to
receive
(
:dev_env_or_com?
).
and_return
false
end
it
'does not create plans and plan limits and returns'
do
expect
{
migrate!
}.
not_to
change
{
AddNewTrailPlans
::
Plan
.
count
}
expect
{
migrate!
}.
not_to
change
{
AddNewTrailPlans
::
Plan
.
count
}
end
end
end
describe
'#down'
do
before
do
table
(
:plans
).
create!
(
id:
3
,
name:
'other'
)
table
(
:plan_limits
).
create!
(
plan_id:
3
)
end
context
'when the instance is SaaS'
do
before
do
allow
(
Gitlab
).
to
receive
(
:dev_env_or_com?
).
and_return
true
end
it
'removes the newly added ultimate and premium trial entries'
do
migrate!
expect
{
described_class
.
new
.
down
}.
to
change
{
AddNewTrailPlans
::
Plan
.
count
}.
by
(
-
2
)
expect
(
AddNewTrailPlans
::
Plan
.
find_by
(
name:
'premium_trial'
)).
to
be_nil
expect
(
AddNewTrailPlans
::
Plan
.
find_by
(
name:
'ultimate_trial'
)).
to
be_nil
other_plan
=
AddNewTrailPlans
::
Plan
.
find_by
(
name:
'other'
)
expect
(
other_plan
).
to
be_persisted
expect
(
AddNewTrailPlans
::
PlanLimits
.
count
).
to
eq
(
1
)
expect
(
AddNewTrailPlans
::
PlanLimits
.
first
.
plan_id
).
to
eq
(
other_plan
.
id
)
end
end
context
'when the instance is not SaaS'
do
before
do
allow
(
Gitlab
).
to
receive
(
:dev_env_or_com?
).
and_return
false
table
(
:plans
).
create!
(
id:
1
,
name:
'ultimate_trial'
,
title:
'Ultimate Trial'
)
table
(
:plans
).
create!
(
id:
2
,
name:
'premium_trial'
,
title:
'Premium Trial'
)
table
(
:plan_limits
).
create!
(
id:
1
,
plan_id:
1
)
table
(
:plan_limits
).
create!
(
id:
2
,
plan_id:
2
)
end
it
'does not delete plans and plan limits and returns'
do
migrate!
expect
{
described_class
.
new
.
down
}.
not_to
change
{
AddNewTrailPlans
::
Plan
.
count
}
expect
(
AddNewTrailPlans
::
PlanLimits
.
count
).
to
eq
(
3
)
end
end
end
end
spec/rubocop/cop/style/regexp_literal_mixed_preserve_spec.rb
0 → 100644
View file @
8c5f2b7f
# frozen_string_literal: true
require
'fast_spec_helper'
require_relative
'../../../../rubocop/cop/style/regexp_literal_mixed_preserve'
# This spec contains only relevant examples.
#
# See also https://github.com/rubocop/rubocop/pull/9688
RSpec
.
describe
RuboCop
::
Cop
::
Style
::
RegexpLiteralMixedPreserve
,
:config
do
let
(
:config
)
do
supported_styles
=
{
'SupportedStyles'
=>
%w[slashes percent_r mixed mixed_preserve]
}
RuboCop
::
Config
.
new
(
'Style/PercentLiteralDelimiters'
=>
percent_literal_delimiters_config
,
'Style/RegexpLiteralMixedPreserve'
=>
cop_config
.
merge
(
supported_styles
))
end
let
(
:percent_literal_delimiters_config
)
{
{
'PreferredDelimiters'
=>
{
'%r'
=>
'{}'
}
}
}
context
'when EnforcedStyle is set to mixed_preserve'
do
let
(
:cop_config
)
{
{
'EnforcedStyle'
=>
'mixed_preserve'
}
}
describe
'a single-line `//` regex without slashes'
do
it
'is accepted'
do
expect_no_offenses
(
'foo = /a/'
)
end
end
describe
'a single-line `//` regex with slashes'
do
it
'registers an offense and corrects'
do
expect_offense
(
<<~
'RUBY'
)
foo = /home
\/
/
^^^^^^^^ Use `%r` around regular expression.
RUBY
expect_correction
(
<<~
'RUBY'
)
foo = %r{home/}
RUBY
end
describe
'when configured to allow inner slashes'
do
before
do
cop_config
[
'AllowInnerSlashes'
]
=
true
end
it
'is accepted'
do
expect_no_offenses
(
'foo = /home\\//'
)
end
end
end
describe
'a multi-line `//` regex without slashes'
do
it
'is accepted'
do
expect_no_offenses
(
<<~
'RUBY'
)
foo = /
foo
bar
/x
RUBY
end
end
describe
'a multi-line `//` regex with slashes'
do
it
'registers an offense and corrects'
do
expect_offense
(
<<~
'RUBY'
)
foo = /
^ Use `%r` around regular expression.
https?:
\/\/
example
\.
com
/x
RUBY
expect_correction
(
<<~
'RUBY'
)
foo = %r{
https?://
example
\.
com
}x
RUBY
end
end
describe
'a single-line %r regex without slashes'
do
it
'is accepted'
do
expect_no_offenses
(
<<~
RUBY
)
foo = %r{a}
RUBY
end
end
describe
'a single-line %r regex with slashes'
do
it
'is accepted'
do
expect_no_offenses
(
'foo = %r{home/}'
)
end
describe
'when configured to allow inner slashes'
do
before
do
cop_config
[
'AllowInnerSlashes'
]
=
true
end
it
'is accepted'
do
expect_no_offenses
(
<<~
RUBY
)
foo = %r{home/}
RUBY
end
end
end
describe
'a multi-line %r regex without slashes'
do
it
'is accepted'
do
expect_no_offenses
(
<<~
RUBY
)
foo = %r{
foo
bar
}x
RUBY
end
end
describe
'a multi-line %r regex with slashes'
do
it
'is accepted'
do
expect_no_offenses
(
<<~
RUBY
)
foo = %r{
https?://
example
\.
com
}x
RUBY
end
end
end
end
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