Commit 8aafdd0d authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '238222-clean-up-boards-with-swimlanes-feature-flag' into 'master'

Remove boards_with_swimlanes feature flag [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!48306
parents b491ece0 16f9857b
......@@ -32,9 +32,9 @@ export default {
...mapState(['boardLists', 'error']),
...mapGetters(['isSwimlanesOn']),
boardListsToUse() {
const lists =
this.glFeatures.graphqlBoardLists || this.isSwimlanesOn ? this.boardLists : this.lists;
return sortBy([...Object.values(lists)], 'position');
return this.glFeatures.graphqlBoardLists || this.isSwimlanesOn
? sortBy([...Object.values(this.boardLists)], 'position')
: this.lists;
},
},
mounted() {
......@@ -53,11 +53,7 @@ export default {
<gl-alert v-if="error" variant="danger" :dismissible="false">
{{ error }}
</gl-alert>
<div
v-if="!isSwimlanesOn"
class="boards-list gl-w-full gl-py-5 gl-px-3 gl-white-space-nowrap"
data-qa-selector="boards_list"
>
<div v-if="!isSwimlanesOn" class="boards-list gl-w-full gl-py-5 gl-px-3 gl-white-space-nowrap">
<board-column
v-for="list in boardListsToUse"
:key="list.id"
......
......@@ -278,7 +278,7 @@ export default {
v-if="isSwimlanesHeader && !list.isExpanded"
ref="collapsedInfo"
aria-hidden="true"
class="board-header-collapsed-info-icon gl-mt-2 gl-cursor-pointer gl-text-gray-500"
class="board-header-collapsed-info-icon gl-cursor-pointer gl-text-gray-500"
>
<gl-icon name="information" />
</span>
......
import FilteredSearchBoards from '../../filtered_search_boards';
import FilteredSearchContainer from '../../../filtered_search/container';
import vuexstore from '~/boards/stores';
export default {
name: 'modal-filters',
......@@ -12,7 +13,7 @@ export default {
mounted() {
FilteredSearchContainer.container = this.$el;
this.filteredSearch = new FilteredSearchBoards(this.store);
this.filteredSearch = new FilteredSearchBoards(this.store, vuexstore);
this.filteredSearch.setup();
this.filteredSearch.removeTokens();
this.filteredSearch.handleInputPlaceholder();
......
......@@ -4,7 +4,7 @@ import FilteredSearchContainer from '../filtered_search/container';
import boardsStore from './stores/boards_store';
export default class FilteredSearchBoards extends FilteredSearchManager {
constructor(store, updateUrl = false, cantEdit = []) {
constructor(store, vuexstore, updateUrl = false, cantEdit = []) {
super({
page: 'boards',
isGroupDecendent: true,
......@@ -22,18 +22,18 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
this.isHandledAsync = true;
this.cantEdit = cantEdit.filter(i => typeof i === 'string');
this.cantEditWithValue = cantEdit.filter(i => typeof i === 'object');
this.vuexstore = vuexstore;
}
updateObject(path) {
const groupByParam = new URLSearchParams(window.location.search).get('group_by');
this.store.path = `${path.substr(1)}${groupByParam ? `&group_by=${groupByParam}` : ''}`;
if (gon.features.boardsWithSwimlanes || gon.features.graphqlBoardLists) {
if (this.vuexstore.getters.shouldUseGraphQL) {
boardsStore.updateFiltersUrl();
boardsStore.performSearch();
}
if (this.updateUrl) {
} else if (this.updateUrl) {
boardsStore.updateFiltersUrl();
}
}
......
import Vue from 'vue';
import { mapActions, mapGetters, mapState } from 'vuex';
import { mapActions, mapGetters } from 'vuex';
import 'ee_else_ce/boards/models/issue';
import 'ee_else_ce/boards/models/list';
......@@ -77,7 +77,6 @@ export default () => {
el: $boardApp,
components: {
BoardContent,
Board: () => import('ee_else_ce/boards/components/board_column.vue'),
BoardSidebar,
BoardAddIssuesModal,
BoardSettingsSidebar: () => import('~/boards/components/board_settings_sidebar.vue'),
......@@ -114,8 +113,7 @@ export default () => {
};
},
computed: {
...mapState(['isShowingEpicsSwimlanes']),
...mapGetters(['shouldUseGraphQL']),
...mapGetters(['isSwimlanesOn', 'shouldUseGraphQL']),
detailIssueVisible() {
return Object.keys(this.detailIssue.issue).length;
},
......@@ -154,7 +152,12 @@ export default () => {
eventHub.$off('initialBoardLoad', this.initialBoardLoad);
},
mounted() {
this.filterManager = new FilteredSearchBoards(boardsStore.filter, true, boardsStore.cantEdit);
this.filterManager = new FilteredSearchBoards(
boardsStore.filter,
store,
true,
boardsStore.cantEdit,
);
this.filterManager.setup();
this.performSearch();
......@@ -193,11 +196,11 @@ export default () => {
},
performSearch() {
this.setFilters(convertObjectPropsToCamelCase(urlParamsToObject(window.location.search)));
if (gon.features.boardsWithSwimlanes && this.isShowingEpicsSwimlanes) {
if (this.isSwimlanesOn) {
this.resetEpics();
this.resetIssues();
this.fetchEpicsSwimlanes({});
} else if (gon.features.graphqlBoardLists && !this.isShowingEpicsSwimlanes) {
} else if (gon.features.graphqlBoardLists) {
this.fetchLists();
this.resetIssues();
}
......
......@@ -302,11 +302,7 @@ const boardsStore = {
onNewListIssueResponse(list, issue, data) {
issue.refreshData(data);
if (
!gon.features.boardsWithSwimlanes &&
!gon.features.graphqlBoardLists &&
list.issues.length > 1
) {
if (list.issues.length > 1) {
const moveBeforeId = list.issues[1].id;
this.moveIssue(issue.id, null, null, null, moveBeforeId);
}
......
......@@ -4,13 +4,7 @@ import { inactiveId } from '../constants';
export default {
labelToggleState: state => (state.isShowingLabels ? 'on' : 'off'),
isSidebarOpen: state => state.activeId !== inactiveId,
isSwimlanesOn: state => {
if (!gon?.features?.boardsWithSwimlanes && !gon?.features?.swimlanes) {
return false;
}
return state.isShowingEpicsSwimlanes;
},
isSwimlanesOn: () => false,
getIssueById: state => id => {
return state.issues[id] || {};
},
......
......@@ -8,7 +8,6 @@ class Groups::BoardsController < Groups::ApplicationController
before_action :assign_endpoint_vars
before_action do
push_frontend_feature_flag(:graphql_board_lists, group, default_enabled: false)
push_frontend_feature_flag(:boards_with_swimlanes, group, default_enabled: true)
end
feature_category :boards
......
......@@ -7,9 +7,6 @@ class Projects::BoardsController < Projects::ApplicationController
before_action :check_issues_available!
before_action :authorize_read_board!, only: [:index, :show]
before_action :assign_endpoint_vars
before_action do
push_frontend_feature_flag(:boards_with_swimlanes, project, default_enabled: true)
end
feature_category :boards
......
......@@ -17,23 +17,12 @@
= render 'shared/issuable/search_bar', type: :boards, board: board
#board-app.boards-app.position-relative{ "v-cloak" => "true", data: board_data, ":class" => "{ 'is-compact': detailIssueVisible }" }
- if Feature.enabled?(:boards_with_swimlanes, current_board_parent, default_enabled: true) || Feature.enabled?(:graphql_board_lists, current_board_parent)
%board-content{ "v-cloak" => "true",
"ref" => "board_content",
":lists" => "state.lists",
":can-admin-list" => can_admin_list,
":disabled" => "disabled" }
- else
.boards-list.w-100.py-3.px-2.text-nowrap{ data: { qa_selector: "boards_list" } }
.boards-app-loading.w-100.text-center{ "v-if" => "loading" }
= loading_icon(css_class: 'gl-mb-3')
%board{ "v-cloak" => "true",
"v-for" => "list in state.lists",
"ref" => "board",
":can-admin-list" => can_admin_list,
":list" => "list",
":disabled" => "disabled",
":key" => "list.id" }
%board-content{ "v-cloak" => "true",
"ref" => "board_content",
":lists" => "state.lists",
":can-admin-list" => can_admin_list,
":disabled" => "disabled",
data: { qa_selector: "boards_list" } }
= render "shared/boards/components/sidebar", group: group
%board-settings-sidebar{ ":can-admin-list" => can_admin_list }
- if @project
......
......@@ -182,7 +182,7 @@
= render 'shared/issuable/board_create_list_dropdown', board: board
- if @project
#js-add-issues-btn.gl-ml-3{ data: { can_admin_list: can?(current_user, :admin_list, @project) } }
- if current_user && Feature.enabled?(:boards_with_swimlanes, @group, default_enabled: true)
- if current_user
#js-board-epics-swimlanes-toggle
#js-toggle-focus-btn
- elsif is_not_boards_modal_or_productivity_analytics && show_sorting_dropdown
......
---
name: boards_with_swimlanes
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/218040
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/238222
milestone: 13.6
group: group::product planning
type: development
default_enabled: true
......@@ -3,6 +3,9 @@ import gettersCE from '~/boards/stores/getters';
export default {
...gettersCE,
isSwimlanesOn: state => {
return Boolean(gon?.features?.swimlanes && state.isShowingEpicsSwimlanes);
},
getIssuesByEpic: (state, getters) => (listId, epicId) => {
return getters.getIssuesByList(listId).filter(issue => issue.epic && issue.epic.id === epicId);
},
......@@ -16,9 +19,6 @@ export default {
},
shouldUseGraphQL: state => {
return (
(gon?.features?.boardsWithSwimlanes && state.isShowingEpicsSwimlanes) ||
gon?.features?.graphqlBoardLists
);
return state.isShowingEpicsSwimlanes || gon?.features?.graphqlBoardLists;
},
};
......@@ -16,7 +16,6 @@ module Resolvers
def resolve(**args)
return Epic.none unless board.present?
return Epic.none unless group.present?
return unless ::Feature.enabled?(:boards_with_swimlanes, group, default_enabled: true)
context.scoped_set!(:board, board)
......
......@@ -75,10 +75,9 @@ RSpec.describe 'issue boards', :js do
end
context 'swimlanes dropdown' do
context 'feature flag on' do
context 'license feature on' do
before do
stub_licensed_features(swimlanes: true)
stub_feature_flags(boards_with_swimlanes: true, swimlanes: true)
end
it 'does not show Group by dropdown when user is not logged in' do
......@@ -96,9 +95,9 @@ RSpec.describe 'issue boards', :js do
end
end
context 'feature flag off' do
context 'license feature off' do
before do
stub_feature_flags(boards_with_swimlanes: false, swimlanes: false)
stub_licensed_features(swimlanes: false)
end
it 'does not show Group by dropdown when user is not logged in' do
......
......@@ -30,7 +30,6 @@ RSpec.describe 'epics swimlanes', :js do
project.add_maintainer(user)
group.add_maintainer(user)
stub_licensed_features(epics: true, swimlanes: true)
stub_feature_flags(epics: true, boards_with_swimlanes: true, swimlanes: true)
sign_in(user)
visit_board_page
......
......@@ -23,7 +23,7 @@ RSpec.describe 'epics swimlanes', :js do
context 'link to swimlanes view' do
before do
stub_licensed_features(epics: true)
stub_licensed_features(epics: true, swimlanes: true)
sign_in(user)
visit_epics_swimlanes_page
end
......
......@@ -42,7 +42,7 @@ describe('ee/BoardContent', () => {
${false} | ${{ isShowingEpicsSwimlanes: false }} | ${false}
`('with featureFlag=$featureFlag and state=$state', ({ featureFlag, state, result }) => {
beforeEach(() => {
gon.features.boardsWithSwimlanes = featureFlag;
gon.features.swimlanes = featureFlag;
Object.assign(store.state, state);
createComponent();
});
......
......@@ -12,7 +12,6 @@ import axios from '~/lib/utils/axios_utils';
describe('BoardListSelector', () => {
global.gon.features = {
...(global.gon.features || {}),
boardsWithSwimlanes: false,
graphqlBoardLists: false,
};
......
......@@ -16,6 +16,60 @@ describe('EE Boards Store Getters', () => {
issues,
};
describe('isSwimlanesOn', () => {
afterEach(() => {
window.gon = { features: {} };
});
describe('when swimlanes feature is true', () => {
beforeEach(() => {
window.gon = { features: { swimlanes: true } };
});
describe('when isShowingEpicsSwimlanes is true', () => {
it('returns true', () => {
const state = {
isShowingEpicsSwimlanes: true,
};
expect(getters.isSwimlanesOn(state)).toBe(true);
});
});
describe('when isShowingEpicsSwimlanes is false', () => {
it('returns false', () => {
const state = {
isShowingEpicsSwimlanes: false,
};
expect(getters.isSwimlanesOn(state)).toBe(false);
});
});
});
describe('when swimlanes feature is false', () => {
describe('when isShowingEpicsSwimlanes is true', () => {
it('returns false', () => {
const state = {
isShowingEpicsSwimlanes: true,
};
expect(getters.isSwimlanesOn(state)).toBe(false);
});
});
describe('when isShowingEpicsSwimlanes is false', () => {
it('returns false', () => {
const state = {
isShowingEpicsSwimlanes: false,
};
expect(getters.isSwimlanesOn(state)).toBe(false);
});
});
});
});
describe('getIssuesByEpic', () => {
it('returns issues for a given listId and epicId', () => {
const getIssuesByList = () => mockIssues;
......
......@@ -50,18 +50,6 @@ RSpec.describe Resolvers::BoardGroupings::EpicsResolver do
end
end
context 'when boards_with_swimlanes is disabled' do
before do
stub_feature_flags(boards_with_swimlanes: false)
end
it 'returns nil' do
result = resolve_board_epics(board)
expect(result).to be_nil
end
end
context 'when user can access the group' do
before do
group.add_developer(current_user)
......
......@@ -184,7 +184,6 @@ describe('List model', () => {
}),
);
list.issues = [];
global.gon.features = { boardsWithSwimlanes: false };
});
it('adds new issue to top of list', done => {
......
......@@ -51,52 +51,8 @@ describe('Boards - Getters', () => {
window.gon = { features: {} };
});
describe('when boardsWithSwimlanes is true', () => {
beforeEach(() => {
window.gon = { features: { boardsWithSwimlanes: true } };
});
describe('when isShowingEpicsSwimlanes is true', () => {
it('returns true', () => {
const state = {
isShowingEpicsSwimlanes: true,
};
expect(getters.isSwimlanesOn(state)).toBe(true);
});
});
describe('when isShowingEpicsSwimlanes is false', () => {
it('returns false', () => {
const state = {
isShowingEpicsSwimlanes: false,
};
expect(getters.isSwimlanesOn(state)).toBe(false);
});
});
});
describe('when boardsWithSwimlanes is false', () => {
describe('when isShowingEpicsSwimlanes is true', () => {
it('returns false', () => {
const state = {
isShowingEpicsSwimlanes: true,
};
expect(getters.isSwimlanesOn(state)).toBe(false);
});
});
describe('when isShowingEpicsSwimlanes is false', () => {
it('returns false', () => {
const state = {
isShowingEpicsSwimlanes: false,
};
expect(getters.isSwimlanesOn(state)).toBe(false);
});
});
it('returns false', () => {
expect(getters.isSwimlanesOn()).toBe(false);
});
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment