diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-05-02 06:09:04 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-05-02 06:09:04 +0000 |
commit | 9ecca14b2b3f05673a15399a2d1cc439206f3e0f (patch) | |
tree | 750343fab3388130b3485eee3cb4b539c1903e71 | |
parent | 7f119dc26391dc953126b4fc902ade7b44a10ce2 (diff) | |
download | gitlab-ce-9ecca14b2b3f05673a15399a2d1cc439206f3e0f.tar.gz |
Add latest changes from gitlab-org/gitlab@master
7 files changed, 103 insertions, 35 deletions
diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue index 814ff16efec..af1d0bf0807 100644 --- a/app/assets/javascripts/boards/components/board_card_inner.vue +++ b/app/assets/javascripts/boards/components/board_card_inner.vue @@ -11,10 +11,12 @@ import { sortBy } from 'lodash'; import { mapActions, mapGetters, mapState } from 'vuex'; import boardCardInner from 'ee_else_ce/boards/mixins/board_card_inner'; import { isScopedLabel } from '~/lib/utils/common_utils'; +import { updateHistory } from '~/lib/utils/url_utility'; import { sprintf, __, n__ } from '~/locale'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import { ListType } from '../constants'; +import eventHub from '../eventhub'; import BoardBlockedIcon from './board_blocked_icon.vue'; import IssueDueDate from './issue_due_date.vue'; import IssueTimeEstimate from './issue_time_estimate.vue'; @@ -174,10 +176,19 @@ export default { ) ); }, - labelTarget(label) { + filterByLabel(label) { + if (!this.updateFilters) return; + const filterPath = window.location.search ? `${window.location.search}&` : '?'; - const value = encodeURIComponent(label.title); - return `${filterPath}label_name[]=${value}`; + const filter = `label_name[]=${encodeURIComponent(label.title)}`; + + if (!filterPath.includes(filter)) { + updateHistory({ + url: `${filterPath}${filter}`, + }); + this.performSearch(); + eventHub.$emit('updateTokens'); + } }, showScopedLabel(label) { return this.scopedLabelsAvailable && isScopedLabel(label); @@ -232,7 +243,7 @@ export default { :description="label.description" size="sm" :scoped="showScopedLabel(label)" - :target="labelTarget(label)" + @click="filterByLabel(label)" /> </template> </div> diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue index aeb2cee590d..fa0c798ca9d 100644 --- a/app/assets/javascripts/boards/components/board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/board_filtered_search.vue @@ -2,7 +2,8 @@ import { pickBy, isEmpty, mapValues } from 'lodash'; import { mapActions } from 'vuex'; import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils'; -import { updateHistory, setUrlParams } from '~/lib/utils/url_utility'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { updateHistory, setUrlParams, queryToObject } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import { FILTERED_SEARCH_TERM, @@ -10,6 +11,7 @@ import { } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import { AssigneeFilterType } from '~/boards/constants'; +import eventHub from '../eventhub'; export default { i18n: { @@ -33,6 +35,7 @@ export default { data() { return { filterParams: this.initialFilterParams, + filteredSearchKey: 0, }; }, computed: { @@ -306,12 +309,21 @@ export default { }, }, created() { + eventHub.$on('updateTokens', this.updateTokens); if (!isEmpty(this.eeFilters)) { this.filterParams = this.eeFilters; } }, + beforeDestroy() { + eventHub.$off('updateTokens', this.updateTokens); + }, methods: { ...mapActions(['performSearch']), + updateTokens() { + const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true }); + this.filterParams = convertObjectPropsToCamelCase(rawFilterParams, {}); + this.filteredSearchKey += 1; + }, handleFilter(filters) { this.filterParams = this.getFilterParams(filters); @@ -399,6 +411,7 @@ export default { <template> <filtered-search + :key="filteredSearchKey" class="gl-w-full" namespace="" :tokens="tokens" diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb index 50573dbd3ba..90e378cb3c8 100644 --- a/lib/api/internal/kubernetes.rb +++ b/lib/api/internal/kubernetes.rb @@ -5,12 +5,6 @@ module API module Internal class Kubernetes < ::API::Base feature_category :kubernetes_management - urgency :low, [ - '/api/:version/internal/kubernetes/agent_configuration', - '/api/:version/internal/kubernetes/agent_info', - '/api/:version/internal/kubernetes/project_info' - ] - before do check_feature_enabled authenticate_gitlab_kas_request! @@ -73,7 +67,7 @@ module API detail 'Retrieves agent info for the given token' end route_setting :authentication, cluster_agent_token_allowed: true - get '/agent_info' do + get '/agent_info', urgency: :low do project = agent.project status 200 @@ -87,7 +81,7 @@ module API end end - namespace 'kubernetes/agent_configuration' do + namespace 'kubernetes/agent_configuration', urgency: :low do desc 'POST agent configuration' do detail 'Store configuration for an agent' end diff --git a/qa/qa/resource/project_imported_from_github.rb b/qa/qa/resource/project_imported_from_github.rb index 28a0f12b3e3..b9dbd2a6131 100644 --- a/qa/qa/resource/project_imported_from_github.rb +++ b/qa/qa/resource/project_imported_from_github.rb @@ -17,7 +17,7 @@ module QA Page::Project::Import::Github.perform do |import_page| import_page.add_personal_access_token(github_personal_access_token) import_page.import!(github_repository_path, group.full_path, name) - import_page.wait_for_success(github_repository_path) + import_page.wait_for_success(github_repository_path, wait: 240) end reload! diff --git a/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb index 79bba484bea..79509bdbe01 100644 --- a/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb +++ b/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb @@ -36,7 +36,7 @@ module QA imported_project.reload! # import the project expect { imported_project.project_import_status[:import_status] }.to eventually_eq('finished') - .within(max_duration: 90, sleep_interval: 1) + .within(max_duration: 240, sleep_interval: 1) aggregate_failures do verify_status_data diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb index 3bf5a11b074..0477a9b8a1f 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb @@ -46,7 +46,7 @@ module QA import_page.import!(github_repo, group.full_path, imported_project.name) aggregate_failures do - expect(import_page).to have_imported_project(github_repo) + expect(import_page).to have_imported_project(github_repo, wait: 240) # validate button is present instead of navigating to avoid dealing with multiple tabs # which makes the test more complicated expect(import_page).to have_go_to_project_button(github_repo) diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js index 677978d31ca..c6de3ee69f3 100644 --- a/spec/frontend/boards/board_card_inner_spec.js +++ b/spec/frontend/boards/board_card_inner_spec.js @@ -2,12 +2,15 @@ import { GlLabel, GlLoadingIcon, GlTooltip } from '@gitlab/ui'; import { range } from 'lodash'; import Vuex from 'vuex'; import { nextTick } from 'vue'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import BoardBlockedIcon from '~/boards/components/board_blocked_icon.vue'; import BoardCardInner from '~/boards/components/board_card_inner.vue'; import { issuableTypes } from '~/boards/constants'; +import eventHub from '~/boards/eventhub'; import defaultStore from '~/boards/stores'; +import { updateHistory } from '~/lib/utils/url_utility'; import { mockLabelList, mockIssue, mockIssueFullPath } from './mock_data'; jest.mock('~/lib/utils/url_utility'); @@ -34,7 +37,7 @@ describe('Board card component', () => { let list; let store; - const findBoardBlockedIcon = () => wrapper.find(BoardBlockedIcon); + const findBoardBlockedIcon = () => wrapper.findComponent(BoardBlockedIcon); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findEpicCountablesTotalTooltip = () => wrapper.findComponent(GlTooltip); const findEpicCountables = () => wrapper.findByTestId('epic-countables'); @@ -45,9 +48,14 @@ describe('Board card component', () => { const findEpicProgressTooltip = () => wrapper.findByTestId('epic-progress-tooltip-content'); const findHiddenIssueIcon = () => wrapper.findByTestId('hidden-icon'); + const performSearchMock = jest.fn(); + const createStore = ({ isEpicBoard = false, isProjectBoard = false } = {}) => { store = new Vuex.Store({ ...defaultStore, + actions: { + performSearch: performSearchMock, + }, state: { ...defaultStore.state, issuableType: issuableTypes.issue, @@ -70,7 +78,6 @@ describe('Board card component', () => { ...props, }, stubs: { - GlLabel: true, GlLoadingIcon: true, }, directives: { @@ -179,7 +186,7 @@ describe('Board card component', () => { describe('confidential issue', () => { beforeEach(() => { - wrapper.setProps({ + createWrapper({ item: { ...wrapper.props('item'), confidential: true, @@ -194,7 +201,7 @@ describe('Board card component', () => { describe('hidden issue', () => { beforeEach(() => { - wrapper.setProps({ + createWrapper({ item: { ...wrapper.props('item'), hidden: true, @@ -219,7 +226,7 @@ describe('Board card component', () => { describe('with assignee', () => { describe('with avatar', () => { beforeEach(() => { - wrapper.setProps({ + createWrapper({ item: { ...wrapper.props('item'), assignees: [user], @@ -272,7 +279,7 @@ describe('Board card component', () => { beforeEach(() => { global.gon.default_avatar_url = 'default_avatar'; - wrapper.setProps({ + createWrapper({ item: { ...wrapper.props('item'), assignees: [ @@ -301,7 +308,7 @@ describe('Board card component', () => { describe('multiple assignees', () => { beforeEach(() => { - wrapper.setProps({ + createWrapper({ item: { ...wrapper.props('item'), assignees: [ @@ -342,7 +349,7 @@ describe('Board card component', () => { avatarUrl: 'test_image', }); - wrapper.setProps({ + createWrapper({ item: { ...wrapper.props('item'), assignees, @@ -368,7 +375,7 @@ describe('Board card component', () => { avatarUrl: 'test_image', })), ]; - wrapper.setProps({ + createWrapper({ item: { ...wrapper.props('item'), assignees, @@ -384,31 +391,74 @@ describe('Board card component', () => { describe('labels', () => { beforeEach(() => { - wrapper.setProps({ item: { ...issue, labels: [list.label, label1] } }); + createWrapper({ item: { ...issue, labels: [list.label, label1] } }); }); it('does not render list label but renders all other labels', () => { - expect(wrapper.findAll(GlLabel).length).toBe(1); - const label = wrapper.find(GlLabel); + expect(wrapper.findAllComponents(GlLabel).length).toBe(1); + const label = wrapper.findComponent(GlLabel); expect(label.props('title')).toEqual(label1.title); expect(label.props('description')).toEqual(label1.description); expect(label.props('backgroundColor')).toEqual(label1.color); }); it('does not render label if label does not have an ID', async () => { - wrapper.setProps({ item: { ...issue, labels: [label1, { title: 'closed' }] } }); + createWrapper({ item: { ...issue, labels: [label1, { title: 'closed' }] } }); await nextTick(); - expect(wrapper.findAll(GlLabel).length).toBe(1); + expect(wrapper.findAllComponents(GlLabel).length).toBe(1); expect(wrapper.text()).not.toContain('closed'); }); + }); - describe('when label params arent set', () => { - it('passes the right target to GlLabel', () => { - expect(wrapper.findAll(GlLabel).at(0).props('target')).toEqual( - '?label_name[]=testing%20123', - ); + describe('filterByLabel method', () => { + beforeEach(() => { + createWrapper({ + item: { + ...issue, + labels: [label1], + }, + updateFilters: true, + }); + }); + + describe('when selected label is not in the filter', () => { + beforeEach(() => { + setWindowLocation('?'); + wrapper.findComponent(GlLabel).vm.$emit('click', label1); + }); + + it('calls updateHistory', () => { + expect(updateHistory).toHaveBeenCalledTimes(1); + }); + + it('dispatches performSearch vuex action', () => { + expect(performSearchMock).toHaveBeenCalledTimes(1); + }); + + it('emits updateTokens event', () => { + expect(eventHub.$emit).toHaveBeenCalledTimes(1); + expect(eventHub.$emit).toHaveBeenCalledWith('updateTokens'); + }); + }); + + describe('when selected label is already in the filter', () => { + beforeEach(() => { + setWindowLocation('?label_name[]=testing%20123'); + wrapper.findComponent(GlLabel).vm.$emit('click', label1); + }); + + it('does not call updateHistory', () => { + expect(updateHistory).not.toHaveBeenCalled(); + }); + + it('does not dispatch performSearch vuex action', () => { + expect(performSearchMock).not.toHaveBeenCalled(); + }); + + it('does not emit updateTokens event', () => { + expect(eventHub.$emit).not.toHaveBeenCalled(); }); }); }); |