...@@ -163,7 +163,7 @@ export default class FilteredSearchVisualTokens { ...@@ -163,7 +163,7 @@ export default class FilteredSearchVisualTokens {
const tokenValueElement = tokenValueContainer.querySelector('.value'); const tokenValueElement = tokenValueContainer.querySelector('.value');
tokenValueElement.innerText = tokenValue; tokenValueElement.innerText = tokenValue;
if (tokenValue === 'none' || tokenValue === 'any') { if (['none', 'any'].includes(tokenValue.toLowerCase())) {
return; return;
} }
... ...
......
...@@ -25,8 +25,6 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController ...@@ -25,8 +25,6 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController
private private
def group_milestones def group_milestones
groups = GroupsFinder.new(current_user, all_available: false).execute
DashboardGroupMilestone.build_collection(groups, params) DashboardGroupMilestone.build_collection(groups, params)
end end
...@@ -45,6 +43,6 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController ...@@ -45,6 +43,6 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController
end end
def groups def groups
@groups ||= GroupsFinder.new(current_user, state_all: true).execute @groups ||= GroupsFinder.new(current_user, all_available: false).execute
end end
end end
...@@ -21,6 +21,10 @@ class Board < ActiveRecord::Base ...@@ -21,6 +21,10 @@ class Board < ActiveRecord::Base
group_id.present? group_id.present?
end end
def project_board?
project_id.present?
end
def backlog_list def backlog_list
lists.merge(List.backlog).take lists.merge(List.backlog).take
end end
... ...
......
...@@ -4,10 +4,12 @@ class BoardPolicy < BasePolicy ...@@ -4,10 +4,12 @@ class BoardPolicy < BasePolicy
delegate { @subject.parent } delegate { @subject.parent }
condition(:is_group_board) { @subject.group_board? } condition(:is_group_board) { @subject.group_board? }
condition(:is_project_board) { @subject.project_board? }
rule { is_group_board ? can?(:read_group) : can?(:read_project) }.enable :read_parent rule { is_project_board & can?(:read_project) }.enable :read_parent
rule { is_group_board & can?(:read_group) }.policy do rule { is_group_board & can?(:read_group) }.policy do
enable :read_parent
enable :read_milestone enable :read_milestone
enable :read_issue enable :read_issue
end end
... ...
......
---
title: Fix counts in milestones dashboard
merge_request: 25230
author:
type: fixed
---
title: Fix 403 errors when adding an assignee list in project boards
merge_request: 25263
author:
type: fixed
...@@ -61,6 +61,7 @@ The following table depicts the various user permission levels in a project. ...@@ -61,6 +61,7 @@ The following table depicts the various user permission levels in a project.
| Manage related issues **[STARTER]** | | ✓ | ✓ | ✓ | ✓ | | Manage related issues **[STARTER]** | | ✓ | ✓ | ✓ | ✓ |
| Lock issue discussions | | ✓ | ✓ | ✓ | ✓ | | Lock issue discussions | | ✓ | ✓ | ✓ | ✓ |
| Create issue from vulnerability **[ULTIMATE]** | | ✓ | ✓ | ✓ | ✓ | | Create issue from vulnerability **[ULTIMATE]** | | ✓ | ✓ | ✓ | ✓ |
| View Error Tracking list | | ✓ | ✓ | ✓ | ✓ |
| Lock merge request discussions | | | ✓ | ✓ | ✓ | | Lock merge request discussions | | | ✓ | ✓ | ✓ |
| Create new environments | | | ✓ | ✓ | ✓ | | Create new environments | | | ✓ | ✓ | ✓ |
| Stop environments | | | ✓ | ✓ | ✓ | | Stop environments | | | ✓ | ✓ | ✓ |
...@@ -101,6 +102,7 @@ The following table depicts the various user permission levels in a project. ...@@ -101,6 +102,7 @@ The following table depicts the various user permission levels in a project.
| Manage clusters | | | | ✓ | ✓ | | Manage clusters | | | | ✓ | ✓ |
| Manage license policy **[ULTIMATE]** | | | | ✓ | ✓ | | Manage license policy **[ULTIMATE]** | | | | ✓ | ✓ |
| Edit comments (posted by any user) | | | | ✓ | ✓ | | Edit comments (posted by any user) | | | | ✓ | ✓ |
| Manage Error Tracking | | | | ✓ | ✓ |
| Switch visibility level | | | | | ✓ | | Switch visibility level | | | | | ✓ |
| Transfer project to another namespace | | | | | ✓ | | Transfer project to another namespace | | | | | ✓ |
| Remove project | | | | | ✓ | | Remove project | | | | | ✓ |
... ...
......
...@@ -14,10 +14,14 @@ You may sign up to the cloud hosted <https://sentry.io> or deploy your own [on-p ...@@ -14,10 +14,14 @@ You may sign up to the cloud hosted <https://sentry.io> or deploy your own [on-p
### Enabling Sentry ### Enabling Sentry
NOTE: **Note:**
You will need at least Maintainer [permissions](../../permissions.md) to enable the Sentry integration.
GitLab provides an easy way to connect Sentry to your project: GitLab provides an easy way to connect Sentry to your project:
1. Sign up to Sentry.io or [deploy your own](#deploying-sentry) Sentry instance. 1. Sign up to Sentry.io or [deploy your own](#deploying-sentry) Sentry instance.
1. [Find or generate](https://docs.sentry.io/api/auth/) a Sentry auth token for your Sentry project. 1. [Find or generate](https://docs.sentry.io/api/auth/) a Sentry auth token for your Sentry project.
Make sure to give the token at least the following scopes: `event:read` and `project:read`.
1. Navigate to your project’s **Settings > Operations** and provide the Sentry API URL and auth token. 1. Navigate to your project’s **Settings > Operations** and provide the Sentry API URL and auth token.
1. Ensure that the 'Active' checkbox is set. 1. Ensure that the 'Active' checkbox is set.
1. Click **Save changes** for the changes to take effect. 1. Click **Save changes** for the changes to take effect.
...@@ -25,6 +29,9 @@ GitLab provides an easy way to connect Sentry to your project: ...@@ -25,6 +29,9 @@ GitLab provides an easy way to connect Sentry to your project:
## Error Tracking List ## Error Tracking List
NOTE: **Note:**
You will need at least Reporter [permissions](../../permissions.md) to view the Error Tracking list.
The Error Tracking list may be found at **Operations > Error Tracking** in your project's sidebar. The Error Tracking list may be found at **Operations > Error Tracking** in your project's sidebar.
![Error Tracking list](img/error_tracking_list.png) ![Error Tracking list](img/error_tracking_list.png)
...@@ -3,11 +3,9 @@ require 'spec_helper' ...@@ -3,11 +3,9 @@ require 'spec_helper'
describe Dashboard::MilestonesController do describe Dashboard::MilestonesController do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:group) { create(:group) } let(:group) { create(:group) }
let(:public_group) { create(:group, :public) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project_milestone) { create(:milestone, project: project) } let(:project_milestone) { create(:milestone, project: project) }
let(:group_milestone) { create(:milestone, group: group) } let(:group_milestone) { create(:milestone, group: group) }
let!(:public_milestone) { create(:milestone, group: public_group) }
let(:milestone) do let(:milestone) do
DashboardMilestone.build( DashboardMilestone.build(
[project], [project],
...@@ -45,6 +43,9 @@ describe Dashboard::MilestonesController do ...@@ -45,6 +43,9 @@ describe Dashboard::MilestonesController do
end end
describe "#index" do describe "#index" do
let(:public_group) { create(:group, :public) }
let!(:public_milestone) { create(:milestone, group: public_group) }
render_views render_views
it 'returns group and project milestones to which the user belongs' do it 'returns group and project milestones to which the user belongs' do
...@@ -74,10 +75,10 @@ describe Dashboard::MilestonesController do ...@@ -74,10 +75,10 @@ describe Dashboard::MilestonesController do
expect(response.body).not_to include(project_milestone.title) expect(response.body).not_to include(project_milestone.title)
end end
it 'should contain group and project milestones to which the user belongs to' do it 'should show counts of group and project milestones to which the user belongs to' do
get :index get :index
expect(response.body).to include("Open\n<span class=\"badge badge-pill\">3</span>") expect(response.body).to include("Open\n<span class=\"badge badge-pill\">2</span>")
expect(response.body).to include("Closed\n<span class=\"badge badge-pill\">0</span>") expect(response.body).to include("Closed\n<span class=\"badge badge-pill\">0</span>")
end end
end end
... ...
......
...@@ -755,6 +755,17 @@ describe('Filtered Search Visual Tokens', () => { ...@@ -755,6 +755,17 @@ describe('Filtered Search Visual Tokens', () => {
expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0);
}); });
it('does not update user token appearance for `None` filter', () => {
const { tokenNameElement } = findElements(authorToken);
const tokenName = tokenNameElement.innerText;
const tokenValue = 'None';
subject.renderVisualTokenValue(authorToken, tokenName, tokenValue);
expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0);
});
it('does not update user token appearance for `none` filter', () => { it('does not update user token appearance for `none` filter', () => {
const { tokenNameElement } = findElements(authorToken); const { tokenNameElement } = findElements(authorToken);
... ...
......
# frozen_string_literal: true
require 'spec_helper'
describe BoardPolicy do
let(:user) { create(:user) }
let(:project) { create(:project, :private) }
let(:group) { create(:group, :private) }
let(:group_board) { create(:board, group: group) }
let(:project_board) { create(:board, project: project) }
let(:board_permissions) do
[
:read_parent,
:read_milestone,
:read_issue
]
end
def expect_allowed(*permissions)
permissions.each { |p| is_expected.to be_allowed(p) }
end
def expect_disallowed(*permissions)
permissions.each { |p| is_expected.not_to be_allowed(p) }
end
context 'group board' do
subject { described_class.new(user, group_board) }
context 'user has access' do
before do
group.add_developer(user)
end
it do
expect_allowed(*board_permissions)
end
end
context 'user does not have access' do
it do
expect_disallowed(*board_permissions)
end
end
end
context 'project board' do
subject { described_class.new(user, project_board) }
context 'user has access' do
before do
project.add_developer(user)
end
it do
expect_allowed(*board_permissions)
end
end
context 'user does not have access' do
it do
expect_disallowed(*board_permissions)
end
end
end
end