summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/boards
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-03-18 20:02:30 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-18 20:02:30 +0000
commit41fe97390ceddf945f3d967b8fdb3de4c66b7dea (patch)
tree9c8d89a8624828992f06d892cd2f43818ff5dcc8 /app/assets/javascripts/boards
parent0804d2dc31052fb45a1efecedc8e06ce9bc32862 (diff)
downloadgitlab-ce-41fe97390ceddf945f3d967b8fdb3de4c66b7dea.tar.gz
Add latest changes from gitlab-org/gitlab@14-9-stable-eev14.9.0-rc42
Diffstat (limited to 'app/assets/javascripts/boards')
-rw-r--r--app/assets/javascripts/boards/boards_util.js14
-rw-r--r--app/assets/javascripts/boards/components/board_filtered_search.vue6
-rw-r--r--app/assets/javascripts/boards/components/board_form.vue40
-rw-r--r--app/assets/javascripts/boards/components/board_list_header.vue14
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue7
-rw-r--r--app/assets/javascripts/boards/filtered_search_boards.js81
-rw-r--r--app/assets/javascripts/boards/graphql.js1
-rw-r--r--app/assets/javascripts/boards/index.js42
-rw-r--r--app/assets/javascripts/boards/mount_filtered_search_issue_boards.js10
-rw-r--r--app/assets/javascripts/boards/stores/actions.js36
-rw-r--r--app/assets/javascripts/boards/stores/mutation_types.js3
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js17
-rw-r--r--app/assets/javascripts/boards/stores/state.js1
13 files changed, 103 insertions, 169 deletions
diff --git a/app/assets/javascripts/boards/boards_util.js b/app/assets/javascripts/boards/boards_util.js
index 7e4d3ebb686..96cc774a280 100644
--- a/app/assets/javascripts/boards/boards_util.js
+++ b/app/assets/javascripts/boards/boards_util.js
@@ -1,5 +1,6 @@
import { sortBy, cloneDeep } from 'lodash';
-import { isGid } from '~/graphql_shared/utils';
+import { TYPE_BOARD, TYPE_ITERATION, TYPE_MILESTONE, TYPE_USER } from '~/graphql_shared/constants';
+import { isGid, convertToGraphQLId } from '~/graphql_shared/utils';
import { ListType, MilestoneIDs, AssigneeFilterType, MilestoneFilterType } from './constants';
export function getMilestone() {
@@ -80,19 +81,22 @@ export function formatListsPageInfo(lists) {
}
export function fullBoardId(boardId) {
- return `gid://gitlab/Board/${boardId}`;
+ if (!boardId) {
+ return null;
+ }
+ return convertToGraphQLId(TYPE_BOARD, boardId);
}
export function fullIterationId(id) {
- return `gid://gitlab/Iteration/${id}`;
+ return convertToGraphQLId(TYPE_ITERATION, id);
}
export function fullUserId(id) {
- return `gid://gitlab/User/${id}`;
+ return convertToGraphQLId(TYPE_USER, id);
}
export function fullMilestoneId(id) {
- return `gid://gitlab/Milestone/${id}`;
+ return convertToGraphQLId(TYPE_MILESTONE, id);
}
export function fullLabelId(label) {
diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue
index 45192b5304a..95d4fd5bc0a 100644
--- a/app/assets/javascripts/boards/components/board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/board_filtered_search.vue
@@ -151,10 +151,10 @@ export default {
});
}
- if (this.filterParams['not[iteration_id]']) {
+ if (this.filterParams['not[iterationId]']) {
filteredSearchValue.push({
- type: 'iteration_id',
- value: { data: this.filterParams['not[iteration_id]'], operator: '!=' },
+ type: 'iteration',
+ value: { data: this.filterParams['not[iterationId]'], operator: '!=' },
});
}
diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue
index cc048e2af1a..5fcf9514708 100644
--- a/app/assets/javascripts/boards/components/board_form.vue
+++ b/app/assets/javascripts/boards/components/board_form.vue
@@ -1,11 +1,9 @@
<script>
import { GlModal, GlAlert } from '@gitlab/ui';
import { mapGetters, mapActions, mapState } from 'vuex';
-import { TYPE_USER, TYPE_ITERATION, TYPE_MILESTONE } from '~/graphql_shared/constants';
-import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { getParameterByName, visitUrl } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
-import { fullLabelId } from '../boards_util';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { formType } from '../constants';
import createBoardMutation from '../graphql/board_create.mutation.graphql';
@@ -18,6 +16,7 @@ const boardDefaults = {
name: '',
labels: [],
milestone: {},
+ iterationCadence: {},
iteration: {},
assignee: {},
weight: null,
@@ -44,6 +43,7 @@ export default {
BoardConfigurationOptions,
GlAlert,
},
+ mixins: [glFeatureFlagMixin()],
inject: {
fullPath: {
default: '',
@@ -158,33 +158,8 @@ export default {
groupPath: this.isGroupBoard ? this.fullPath : undefined,
};
},
- issueBoardScopeMutationVariables() {
- return {
- weight: this.board.weight,
- assigneeId: this.board.assignee?.id
- ? convertToGraphQLId(TYPE_USER, this.board.assignee.id)
- : null,
- // Temporarily converting to milestone ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779
- milestoneId: this.board.milestone?.id
- ? convertToGraphQLId(TYPE_MILESTONE, getIdFromGraphQLId(this.board.milestone.id))
- : null,
- // Temporarily converting to iteration ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779
- iterationId: this.board.iteration?.id
- ? convertToGraphQLId(TYPE_ITERATION, getIdFromGraphQLId(this.board.iteration.id))
- : null,
- };
- },
- boardScopeMutationVariables() {
- return {
- labelIds: this.board.labels.map(fullLabelId),
- ...(this.isIssueBoard && this.issueBoardScopeMutationVariables),
- };
- },
mutationVariables() {
- return {
- ...this.baseMutationVariables,
- ...(this.scopedIssueBoardFeatureEnabled ? this.boardScopeMutationVariables : {}),
- };
+ return this.baseMutationVariables;
},
},
mounted() {
@@ -259,9 +234,12 @@ export default {
this.board = { ...boardDefaults, ...this.currentBoard };
}
},
- setIteration(iterationId) {
+ setIteration(iteration) {
+ if (this.glFeatures.iterationCadences) {
+ this.board.iterationCadenceId = iteration.iterationCadenceId;
+ }
this.$set(this.board, 'iteration', {
- id: iterationId,
+ id: iteration.id,
});
},
setBoardLabels(labels) {
diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue
index 6835d83a66c..46b28d20da9 100644
--- a/app/assets/javascripts/boards/components/board_list_header.vue
+++ b/app/assets/javascripts/boards/components/board_list_header.vue
@@ -89,10 +89,6 @@ export default {
listTitle() {
return this.list?.label?.description || this.list?.assignee?.name || this.list.title || '';
},
- listIterationPeriod() {
- const iteration = this.list?.iteration;
- return iteration ? this.getIterationPeriod(iteration) : '';
- },
isIterationList() {
return this.listType === ListType.iteration;
},
@@ -108,9 +104,6 @@ export default {
showIterationListDetails() {
return this.isIterationList && this.showListDetails;
},
- iterationCadencesAvailable() {
- return this.isIterationList && this.glFeatures.iterationCadences;
- },
showListDetails() {
return !this.list.collapsed || !this.isSwimlanesHeader;
},
@@ -344,13 +337,6 @@ export default {
class="board-title-main-text gl-text-truncate"
>
{{ listTitle }}
- <span
- v-if="iterationCadencesAvailable"
- class="gl-display-inline-block gl-text-gray-400"
- data-testid="board-list-iteration-period"
- >
- {{ listIterationPeriod }}</span
- >
</span>
<span
v-if="listType === 'assignee'"
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index 6dbb1ea0050..91fdfd668fc 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -101,6 +101,7 @@ export default {
},
update(data) {
const board = data.workspace?.board;
+ this.setBoardConfig(board);
return {
...board,
labels: board?.labels?.nodes,
@@ -170,7 +171,7 @@ export default {
eventHub.$off('showBoardModal', this.showPage);
},
methods: {
- ...mapActions(['setError']),
+ ...mapActions(['setError', 'setBoardConfig']),
showPage(page) {
this.currentPage = page;
},
@@ -315,9 +316,7 @@ export default {
<gl-dropdown-item v-if="hasMissingBoards" class="no-pointer-events">
{{
- s__(
- 'IssueBoards|Some of your boards are hidden, activate a license to see them again.',
- )
+ s__('IssueBoards|Some of your boards are hidden, add a license to see them again.')
}}
</gl-dropdown-item>
</div>
diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js
deleted file mode 100644
index 72586970008..00000000000
--- a/app/assets/javascripts/boards/filtered_search_boards.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { transformBoardConfig } from 'ee_else_ce/boards/boards_util';
-import FilteredSearchManager from 'ee_else_ce/filtered_search/filtered_search_manager';
-import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys';
-import { updateHistory } from '~/lib/utils/url_utility';
-import FilteredSearchContainer from '../filtered_search/container';
-import vuexstore from './stores';
-
-export default class FilteredSearchBoards extends FilteredSearchManager {
- constructor(store, updateUrl = false, cantEdit = []) {
- super({
- page: 'boards',
- isGroupDecendent: true,
- stateFiltersSelector: '.issues-state-filters',
- isGroup: IS_EE,
- useDefaultState: false,
- filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
- });
-
- this.store = store;
- this.updateUrl = updateUrl;
-
- // Issue boards is slightly different, we handle all the requests async
- // instead or reloading the page, we just re-fire the list ajax requests
- this.isHandledAsync = true;
- this.cantEdit = cantEdit.filter((i) => typeof i === 'string');
- this.cantEditWithValue = cantEdit.filter((i) => typeof i === 'object');
-
- if (vuexstore.state.boardConfig) {
- const boardConfigPath = transformBoardConfig(vuexstore.state.boardConfig);
- // TODO Refactor: https://gitlab.com/gitlab-org/gitlab/-/issues/329274
- // here we are using "window.location.search" as a temporary store
- // only to unpack the params and do another validation inside
- // 'performSearch' and 'setFilter' vuex actions.
- if (boardConfigPath !== '') {
- const filterPath = window.location.search ? `${window.location.search}&` : '?';
- updateHistory({
- url: `${filterPath}${transformBoardConfig(vuexstore.state.boardConfig)}`,
- });
- }
- }
- }
-
- updateObject(path) {
- const groupByParam = new URLSearchParams(window.location.search).get('group_by');
- this.store.path = `${path.substr(1)}${groupByParam ? `&group_by=${groupByParam}` : ''}`;
-
- updateHistory({
- url: `?${path.substr(1)}${groupByParam ? `&group_by=${groupByParam}` : ''}`,
- });
- vuexstore.dispatch('performSearch');
- }
-
- removeTokens() {
- const tokens = FilteredSearchContainer.container.querySelectorAll('.js-visual-token');
-
- // Remove all the tokens as they will be replaced by the search manager
- [].forEach.call(tokens, (el) => {
- el.parentNode.removeChild(el);
- });
-
- this.filteredSearchInput.value = '';
- }
-
- updateTokens() {
- this.removeTokens();
-
- this.loadSearchParamsFromURL();
-
- // Get the placeholder back if search is empty
- this.filteredSearchInput.dispatchEvent(new Event('input'));
- }
-
- canEdit(tokenName, tokenValue) {
- if (this.cantEdit.includes(tokenName)) return false;
- return (
- this.cantEditWithValue.findIndex(
- (token) => token.name === tokenName && token.value === tokenValue,
- ) === -1
- );
- }
-}
diff --git a/app/assets/javascripts/boards/graphql.js b/app/assets/javascripts/boards/graphql.js
index 95863d4d5ac..d066a5d002e 100644
--- a/app/assets/javascripts/boards/graphql.js
+++ b/app/assets/javascripts/boards/graphql.js
@@ -10,5 +10,6 @@ export const gqlClient = createDefaultClient(
return object.__typename === 'BoardList' ? object.iid : defaultDataIdFromObject(object);
},
},
+ batchMax: 2,
},
);
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index f6073f9d981..b31b56e6839 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -8,8 +8,6 @@ import BoardAddNewColumnTrigger from '~/boards/components/board_add_new_column_t
import BoardApp from '~/boards/components/board_app.vue';
import '~/boards/filters/due_date_filters';
import { issuableTypes } from '~/boards/constants';
-import eventHub from '~/boards/eventhub';
-import FilteredSearchBoards from '~/boards/filtered_search_boards';
import initBoardsFilteredSearch from '~/boards/mount_filtered_search_issue_boards';
import store from '~/boards/stores';
import toggleFocusMode from '~/boards/toggle_focus';
@@ -30,6 +28,12 @@ const apolloProvider = new VueApollo({
function mountBoardApp(el) {
const { boardId, groupId, fullPath, rootPath } = el.dataset;
+ store.dispatch('fetchBoard', {
+ fullPath,
+ fullBoardId: fullBoardId(boardId),
+ boardType: el.dataset.parent,
+ });
+
store.dispatch('setInitialBoardData', {
boardId,
fullBoardId: fullBoardId(boardId),
@@ -37,30 +41,8 @@ function mountBoardApp(el) {
boardType: el.dataset.parent,
disabled: parseBoolean(el.dataset.disabled) || true,
issuableType: issuableTypes.issue,
- boardConfig: {
- milestoneId: parseInt(el.dataset.boardMilestoneId, 10),
- milestoneTitle: el.dataset.boardMilestoneTitle || '',
- iterationId: parseInt(el.dataset.boardIterationId, 10),
- iterationTitle: el.dataset.boardIterationTitle || '',
- assigneeId: el.dataset.boardAssigneeId,
- assigneeUsername: el.dataset.boardAssigneeUsername,
- labels: el.dataset.labels ? JSON.parse(el.dataset.labels) : [],
- labelIds: el.dataset.labelIds ? JSON.parse(el.dataset.labelIds) : [],
- weight: el.dataset.boardWeight ? parseInt(el.dataset.boardWeight, 10) : null,
- },
});
- if (!gon?.features?.issueBoardsFilteredSearch) {
- // Warning: FilteredSearchBoards has an implicit dependency on the Vuex state 'boardConfig'
- // Improve this situation in the future.
- const filterManager = new FilteredSearchBoards({ path: '' }, true, []);
- filterManager.setup();
-
- eventHub.$on('updateTokens', () => {
- filterManager.updateTokens();
- });
- }
-
// eslint-disable-next-line no-new
new Vue({
el,
@@ -110,10 +92,14 @@ export default () => {
}
});
- if (gon?.features?.issueBoardsFilteredSearch) {
- const { releasesFetchPath } = $boardApp.dataset;
- initBoardsFilteredSearch(apolloProvider, isLoggedIn(), releasesFetchPath);
- }
+ const { releasesFetchPath, epicFeatureAvailable, iterationFeatureAvailable } = $boardApp.dataset;
+ initBoardsFilteredSearch(
+ apolloProvider,
+ isLoggedIn(),
+ releasesFetchPath,
+ parseBoolean(epicFeatureAvailable),
+ parseBoolean(iterationFeatureAvailable),
+ );
mountBoardApp($boardApp);
diff --git a/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js b/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js
index 327fb9ba8d7..bb659eb075a 100644
--- a/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js
+++ b/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js
@@ -4,7 +4,13 @@ import store from '~/boards/stores';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { queryToObject } from '~/lib/utils/url_utility';
-export default (apolloProvider, isSignedIn, releasesFetchPath) => {
+export default (
+ apolloProvider,
+ isSignedIn,
+ releasesFetchPath,
+ epicFeatureAvailable,
+ iterationFeatureAvailable,
+) => {
const el = document.getElementById('js-issue-board-filtered-search');
const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true });
@@ -23,6 +29,8 @@ export default (apolloProvider, isSignedIn, releasesFetchPath) => {
initialFilterParams,
isSignedIn,
releasesFetchPath,
+ epicFeatureAvailable,
+ iterationFeatureAvailable,
},
store, // TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/324094
apolloProvider,
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index 1ebfcfc331b..82307da2572 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -36,6 +36,8 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { queryToObject } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import { gqlClient } from '../graphql';
+import projectBoardQuery from '../graphql/project_board.query.graphql';
+import groupBoardQuery from '../graphql/group_board.query.graphql';
import boardLabelsQuery from '../graphql/board_labels.query.graphql';
import groupBoardMilestonesQuery from '../graphql/group_board_milestones.query.graphql';
import groupProjectsQuery from '../graphql/group_projects.query.graphql';
@@ -46,10 +48,44 @@ import projectBoardMilestonesQuery from '../graphql/project_board_milestones.que
import * as types from './mutation_types';
export default {
+ fetchBoard: ({ commit, dispatch }, { fullPath, fullBoardId, boardType }) => {
+ const variables = {
+ fullPath,
+ boardId: fullBoardId,
+ };
+
+ return gqlClient
+ .query({
+ query: boardType === BoardType.group ? groupBoardQuery : projectBoardQuery,
+ variables,
+ })
+ .then(({ data }) => {
+ const board = data.workspace?.board;
+ commit(types.RECEIVE_BOARD_SUCCESS, board);
+ dispatch('setBoardConfig', board);
+ })
+ .catch(() => commit(types.RECEIVE_BOARD_FAILURE));
+ },
+
setInitialBoardData: ({ commit }, data) => {
commit(types.SET_INITIAL_BOARD_DATA, data);
},
+ setBoardConfig: ({ commit }, board) => {
+ const config = {
+ milestoneId: board.milestone?.id || null,
+ milestoneTitle: board.milestone?.title || null,
+ iterationId: board.iteration?.id || null,
+ iterationTitle: board.iteration?.title || null,
+ assigneeId: board.assignee?.id || null,
+ assigneeUsername: board.assignee?.username || null,
+ labels: board.labels?.nodes || [],
+ labelIds: board.labels?.nodes?.map((label) => label.id) || [],
+ weight: board.weight,
+ };
+ commit(types.SET_BOARD_CONFIG, config);
+ },
+
setActiveId({ commit }, { id, sidebarType }) {
commit(types.SET_ACTIVE_ID, { id, sidebarType });
},
diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js
index 31b78014525..668a3b5e0f9 100644
--- a/app/assets/javascripts/boards/stores/mutation_types.js
+++ b/app/assets/javascripts/boards/stores/mutation_types.js
@@ -1,4 +1,7 @@
+export const RECEIVE_BOARD_SUCCESS = 'RECEIVE_BOARD_SUCCESS';
+export const RECEIVE_BOARD_FAILURE = 'RECEIVE_BOARD_FAILURE';
export const SET_INITIAL_BOARD_DATA = 'SET_INITIAL_BOARD_DATA';
+export const SET_BOARD_CONFIG = 'SET_BOARD_CONFIG';
export const SET_FILTERS = 'SET_FILTERS';
export const CREATE_LIST_SUCCESS = 'CREATE_LIST_SUCCESS';
export const CREATE_LIST_FAILURE = 'CREATE_LIST_FAILURE';
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
index 2a2ce7652e6..9a50dcf05b8 100644
--- a/app/assets/javascripts/boards/stores/mutations.js
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -33,10 +33,20 @@ export const addItemToList = ({ state, listId, itemId, moveBeforeId, moveAfterId
};
export default {
+ [mutationTypes.RECEIVE_BOARD_SUCCESS]: (state, board) => {
+ state.board = {
+ ...board,
+ labels: board?.labels?.nodes || [],
+ };
+ },
+
+ [mutationTypes.RECEIVE_BOARD_FAILURE]: (state) => {
+ state.error = s__('Boards|An error occurred while fetching the board. Please reload the page.');
+ },
+
[mutationTypes.SET_INITIAL_BOARD_DATA](state, data) {
const {
allowSubEpics,
- boardConfig,
boardId,
boardType,
disabled,
@@ -45,7 +55,6 @@ export default {
issuableType,
} = data;
state.allowSubEpics = allowSubEpics;
- state.boardConfig = boardConfig;
state.boardId = boardId;
state.boardType = boardType;
state.disabled = disabled;
@@ -54,6 +63,10 @@ export default {
state.issuableType = issuableType;
},
+ [mutationTypes.SET_BOARD_CONFIG](state, boardConfig) {
+ state.boardConfig = boardConfig;
+ },
+
[mutationTypes.RECEIVE_BOARD_LISTS_SUCCESS]: (state, lists) => {
state.boardLists = lists;
},
diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js
index 80c51c966d2..7af4e5a8798 100644
--- a/app/assets/javascripts/boards/stores/state.js
+++ b/app/assets/javascripts/boards/stores/state.js
@@ -1,6 +1,7 @@
import { inactiveId, ListType } from '~/boards/constants';
export default () => ({
+ board: {},
boardType: null,
issuableType: null,
fullPath: null,