diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-24 12:10:14 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-24 12:10:14 +0300 |
commit | 2f752481c2e727834216a93dee82df9f8e2acb2e (patch) | |
tree | 47899c8a7f2be92d4824d84c48e9cf5e0410196c | |
parent | 273d780f9ede8f6ed5ebbd4f81c8a391a55f882a (diff) |
Add latest changes from gitlab-org/gitlab@master
24 files changed, 144 insertions, 25 deletions
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js index 85636f3e5d2..e4e5f16927b 100644 --- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js +++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js @@ -34,6 +34,7 @@ export default class Shortcuts { Mousetrap.bind('?', this.onToggleHelp); Mousetrap.bind('s', Shortcuts.focusSearch); + Mousetrap.bind('/', Shortcuts.focusSearch); Mousetrap.bind('f', this.focusFilter.bind(this)); Mousetrap.bind('p b', Shortcuts.onTogglePerfBar); diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index b7966dd869d..f421faeb52d 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -27,6 +27,11 @@ export default class FilteredSearchBoards extends FilteredSearchManager { updateObject(path) { this.store.path = path.substr(1); + if (gon.features.boardsWithSwimlanes) { + boardsStore.updateFiltersUrl(); + boardsStore.performSearch(); + } + if (this.updateUrl) { boardsStore.updateFiltersUrl(); } diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index 971edd71eec..21c362affbb 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import Vue from 'vue'; -import { mapActions } from 'vuex'; +import { mapActions, mapState } from 'vuex'; import 'ee_else_ce/boards/models/issue'; import 'ee_else_ce/boards/models/list'; @@ -42,6 +42,7 @@ import { NavigationType, convertObjectPropsToCamelCase, parseBoolean, + urlParamsToObject, } from '~/lib/utils/common_utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher'; @@ -104,6 +105,7 @@ export default () => { }; }, computed: { + ...mapState(['isShowingEpicsSwimlanes']), detailIssueVisible() { return Object.keys(this.detailIssue.issue).length; }, @@ -125,17 +127,21 @@ export default () => { eventHub.$on('newDetailIssue', this.updateDetailIssue); eventHub.$on('clearDetailIssue', this.clearDetailIssue); sidebarEventHub.$on('toggleSubscription', this.toggleSubscription); + eventHub.$on('performSearch', this.performSearch); }, beforeDestroy() { eventHub.$off('updateTokens', this.updateTokens); eventHub.$off('newDetailIssue', this.updateDetailIssue); eventHub.$off('clearDetailIssue', this.clearDetailIssue); sidebarEventHub.$off('toggleSubscription', this.toggleSubscription); + eventHub.$off('performSearch', this.performSearch); }, mounted() { this.filterManager = new FilteredSearchBoards(boardsStore.filter, true, boardsStore.cantEdit); this.filterManager.setup(); + this.performSearch(); + boardsStore.disabled = this.disabled; if (gon.features.graphqlBoardLists) { @@ -189,10 +195,16 @@ export default () => { } }, methods: { - ...mapActions(['setInitialBoardData']), + ...mapActions(['setInitialBoardData', 'setFilters', 'fetchEpicsSwimlanes']), updateTokens() { this.filterManager.updateTokens(); }, + performSearch() { + this.setFilters(convertObjectPropsToCamelCase(urlParamsToObject(window.location.search))); + if (gon.features.boardsWithSwimlanes && this.isShowingEpicsSwimlanes) { + this.fetchEpicsSwimlanes(false); + } + }, updateDetailIssue(newIssue, multiSelect = false) { const { sidebarInfoEndpoint } = newIssue; if (sidebarInfoEndpoint && newIssue.subscribed === undefined) { diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index b4be7546252..cce36dc6a14 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -21,6 +21,11 @@ export default { commit(types.SET_ACTIVE_ID, id); }, + setFilters: ({ commit }, filters) => { + const { scope, utf8, state, ...filterParams } = filters; + commit(types.SET_FILTERS, filterParams); + }, + fetchLists: () => { notImplemented(); }, diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index 30c71d64085..002a8bee3dc 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -513,6 +513,10 @@ const boardsStore = { eventHub.$emit('updateTokens'); }, + performSearch() { + eventHub.$emit('performSearch'); + }, + setListDetail(newList) { this.detail.list = newList; }, diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js index 0f96dc2e287..0f9e93dec5c 100644 --- a/app/assets/javascripts/boards/stores/mutation_types.js +++ b/app/assets/javascripts/boards/stores/mutation_types.js @@ -1,4 +1,5 @@ export const SET_INITIAL_BOARD_DATA = 'SET_INITIAL_BOARD_DATA'; +export const SET_FILTERS = 'SET_FILTERS'; export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST'; export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS'; export const RECEIVE_ADD_LIST_ERROR = 'RECEIVE_ADD_LIST_ERROR'; diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js index 1644c118868..738c4aa841a 100644 --- a/app/assets/javascripts/boards/stores/mutations.js +++ b/app/assets/javascripts/boards/stores/mutations.js @@ -17,6 +17,10 @@ export default { state.activeId = id; }, + [mutationTypes.SET_FILTERS](state, filterParams) { + state.filterParams = filterParams; + }, + [mutationTypes.REQUEST_ADD_LIST]: () => { notImplemented(); }, diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js index fde9e62149c..cf01e4fa0e3 100644 --- a/app/assets/javascripts/boards/stores/state.js +++ b/app/assets/javascripts/boards/stores/state.js @@ -8,6 +8,7 @@ export default () => ({ boardLists: [], issuesByListId: {}, isLoadingIssues: false, + filterParams: {}, error: undefined, // TODO: remove after ce/ee split of board_content.vue isShowingEpicsSwimlanes: false, diff --git a/app/assets/javascripts/clusters/components/knative_domain_editor.vue b/app/assets/javascripts/clusters/components/knative_domain_editor.vue index 1236d2a46c9..0194a8e5ac1 100644 --- a/app/assets/javascripts/clusters/components/knative_domain_editor.vue +++ b/app/assets/javascripts/clusters/components/knative_domain_editor.vue @@ -6,8 +6,8 @@ import { GlLoadingIcon, GlSearchBoxByType, GlSprintf, + GlButton, } from '@gitlab/ui'; -import LoadingButton from '~/vue_shared/components/loading_button.vue'; import ClipboardButton from '../../vue_shared/components/clipboard_button.vue'; import { __, s__ } from '~/locale'; @@ -17,7 +17,7 @@ const { UPDATING, UNINSTALLING } = APPLICATION_STATUS; export default { components: { - LoadingButton, + GlButton, ClipboardButton, GlLoadingIcon, GlDeprecatedDropdown, @@ -215,13 +215,16 @@ export default { }} </p> - <loading-button - class="btn-success js-knative-save-domain-button mt-3 ml-3" + <gl-button + class="js-knative-save-domain-button gl-mt-5 gl-ml-5" + variant="success" + category="primary" :loading="saving" :disabled="saveButtonDisabled" - :label="saveButtonLabel" @click="$emit('save')" - /> + > + {{ saveButtonLabel }} + </gl-button> </template> </div> </template> diff --git a/app/graphql/mutations/concerns/mutations/authorizes_project.rb b/app/graphql/mutations/concerns/mutations/authorizes_project.rb new file mode 100644 index 00000000000..87341525d6c --- /dev/null +++ b/app/graphql/mutations/concerns/mutations/authorizes_project.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Mutations + module AuthorizesProject + include ResolvesProject + + def authorized_find_project!(full_path:) + authorized_find!(full_path: full_path) + end + + private + + def find_object(full_path:) + resolve_project(full_path: full_path) + end + end +end diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml index 0bbe73d6f7e..a2b736c332c 100644 --- a/app/views/admin/runners/_runner.html.haml +++ b/app/views/admin/runners/_runner.html.haml @@ -76,4 +76,4 @@ = sprite_icon('play') .btn-group = link_to [:admin, runner], method: :delete, class: 'btn btn-danger has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do - = icon('remove') + = sprite_icon('close') diff --git a/app/views/groups/runners/_runner.html.haml b/app/views/groups/runners/_runner.html.haml index 07cbcd8401e..3fc50cc86d2 100644 --- a/app/views/groups/runners/_runner.html.haml +++ b/app/views/groups/runners/_runner.html.haml @@ -79,8 +79,8 @@ - if runner.belongs_to_more_than_one_project? .btn-group .btn.btn-danger.has-tooltip{ 'aria-label' => 'Remove', 'data-container' => 'body', 'data-original-title' => _('Multi-project Runners cannot be removed'), 'data-placement' => 'top', disabled: 'disabled' } - = icon('remove') + = sprite_icon('close') - else .btn-group = link_to group_runner_path(@group, runner), method: :delete, class: 'btn btn-danger has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do - = icon('remove') + = sprite_icon('close') diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml index 80df8581a9b..d252a279a45 100644 --- a/app/views/help/_shortcuts.html.haml +++ b/app/views/help/_shortcuts.html.haml @@ -40,6 +40,8 @@ %tr %td.shortcut %kbd s + \/ + %kbd / %td= _('Start search') %tr %td.shortcut diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index 23f9a6a8f6c..c7ab01a4ef7 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -102,7 +102,7 @@ - if can?(current_user, :update_build, job) - if job.active? = link_to cancel_project_job_path(job.project, job, continue: { to: request.fullpath }), method: :post, title: _('Cancel'), class: 'btn btn-build' do - = icon('remove', class: 'cred') + = sprite_icon('close') - elsif job.scheduled? .btn-group .btn.btn-default{ disabled: true } diff --git a/changelogs/unreleased/205578-move-package-metrics-to-core.yml b/changelogs/unreleased/205578-move-package-metrics-to-core.yml new file mode 100644 index 00000000000..a52c9c7a3c6 --- /dev/null +++ b/changelogs/unreleased/205578-move-package-metrics-to-core.yml @@ -0,0 +1,5 @@ +--- +title: Move package usage ping data to core +merge_request: 40032 +author: +type: changed diff --git a/changelogs/unreleased/239195-slash-to-start-search-shortcut.yml b/changelogs/unreleased/239195-slash-to-start-search-shortcut.yml new file mode 100644 index 00000000000..cfc02d2ad46 --- /dev/null +++ b/changelogs/unreleased/239195-slash-to-start-search-shortcut.yml @@ -0,0 +1,5 @@ +--- +title: Add `/` as keyboard shortcut for search +merge_request: 40057 +author: +type: added diff --git a/doc/user/shortcuts.md b/doc/user/shortcuts.md index 314fe367ca6..4d65cc61bd5 100644 --- a/doc/user/shortcuts.md +++ b/doc/user/shortcuts.md @@ -27,7 +27,7 @@ These shortcuts are available in most areas of GitLab | <kbd>Shift</kbd> + <kbd>a</kbd> | Go to your Activity page. | | <kbd>Shift</kbd> + <kbd>l</kbd> | Go to your Milestones page. | | <kbd>Shift</kbd> + <kbd>s</kbd> | Go to your Snippets page. | -| <kbd>s</kbd> | Put cursor in the issues/merge requests search. | +| <kbd>s</kbd> / <kbd>/</kbd> | Put cursor in the search bar. | | <kbd>Shift</kbd> + <kbd>i</kbd> | Go to your Issues page. | | <kbd>Shift</kbd> + <kbd>m</kbd> | Go to your Merge requests page.| | <kbd>Shift</kbd> + <kbd>t</kbd> | Go to your To-Do List page. | diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb index c0b671abd44..733214a7cce 100644 --- a/lib/gitlab/middleware/multipart.rb +++ b/lib/gitlab/middleware/multipart.rb @@ -123,9 +123,9 @@ module Gitlab def allowed_paths [ ::FileUploader.root, - Gitlab.config.uploads.storage_path, - JobArtifactUploader.workhorse_upload_path, - LfsObjectUploader.workhorse_upload_path, + ::Gitlab.config.uploads.storage_path, + ::JobArtifactUploader.workhorse_upload_path, + ::LfsObjectUploader.workhorse_upload_path, File.join(Rails.root, 'public/uploads/tmp') ] + package_allowed_paths end @@ -139,9 +139,9 @@ module Gitlab encoded_message = env.delete(RACK_ENV_KEY) return @app.call(env) if encoded_message.blank? - message = Gitlab::Workhorse.decode_jwt(encoded_message)[0] + message = ::Gitlab::Workhorse.decode_jwt(encoded_message)[0] - Handler.new(env, message).with_open_files do + ::Gitlab::Middleware::Multipart::Handler.new(env, message).with_open_files do @app.call(env) end rescue UploadedFile::InvalidPathError => e diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 42be49bdbd6..7f3025ff983 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -129,6 +129,7 @@ module Gitlab lfs_objects: count(LfsObject), milestone_lists: count(List.milestone), milestones: count(Milestone), + projects_with_packages: distinct_count(::Packages::Package, :project_id), pages_domains: count(PagesDomain), pool_repositories: count(PoolRepository), projects: count(Project), @@ -527,9 +528,13 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord + # rubocop: disable CodeReuse/ActiveRecord def usage_activity_by_stage_package(time_period) - {} + { + projects_with_packages: distinct_count(::Project.with_packages.where(time_period), :creator_id) + } end + # rubocop: enable CodeReuse/ActiveRecord # Omitted because no user, creator or author associated: `boards`, `labels`, `milestones`, `uploads` # Omitted because too expensive: `epics_deepest_relationship_level` diff --git a/spec/factories/usage_data.rb b/spec/factories/usage_data.rb index d2b8fd94aca..e5dd92e71cb 100644 --- a/spec/factories/usage_data.rb +++ b/spec/factories/usage_data.rb @@ -94,6 +94,10 @@ FactoryBot.define do create(:grafana_integration, project: projects[1], enabled: true) create(:grafana_integration, project: projects[2], enabled: false) + create(:package, project: projects[0]) + create(:package, project: projects[0]) + create(:package, project: projects[1]) + ProjectFeature.first.update_attribute('repository_access_level', 0) # Create fresh & a month (28-days SMAU) old data diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js index d539cba76ca..71e62a4ac5d 100644 --- a/spec/frontend/boards/stores/actions_spec.js +++ b/spec/frontend/boards/stores/actions_spec.js @@ -26,6 +26,25 @@ describe('setInitialBoardData', () => { }); }); +describe('setFilters', () => { + it('should commit mutation SET_FILTERS', done => { + const state = { + filters: {}, + }; + + const filters = { labelName: 'label' }; + + testAction( + actions.setFilters, + filters, + state, + [{ type: types.SET_FILTERS, payload: filters }], + [], + done, + ); + }); +}); + describe('setActiveId', () => { it('should commit mutation SET_ACTIVE_ID', done => { const state = { diff --git a/spec/frontend/boards/stores/mutations_spec.js b/spec/frontend/boards/stores/mutations_spec.js index cf2f86f1e34..e5b26e9994e 100644 --- a/spec/frontend/boards/stores/mutations_spec.js +++ b/spec/frontend/boards/stores/mutations_spec.js @@ -44,6 +44,16 @@ describe('Board Store Mutations', () => { }); }); + describe('SET_FILTERS', () => { + it('updates filterParams to be the value that is passed', () => { + const filterParams = { labelName: 'label' }; + + mutations.SET_FILTERS(state, filterParams); + + expect(state.filterParams).toBe(filterParams); + }); + }); + describe('REQUEST_ADD_LIST', () => { expectNotImplemented(mutations.REQUEST_ADD_LIST); }); diff --git a/spec/frontend/clusters/components/knative_domain_editor_spec.js b/spec/frontend/clusters/components/knative_domain_editor_spec.js index a07258dcc69..11ebe1b5d61 100644 --- a/spec/frontend/clusters/components/knative_domain_editor_spec.js +++ b/spec/frontend/clusters/components/knative_domain_editor_spec.js @@ -1,7 +1,6 @@ import { shallowMount } from '@vue/test-utils'; -import { GlDeprecatedDropdownItem } from '@gitlab/ui'; +import { GlDeprecatedDropdownItem, GlButton } from '@gitlab/ui'; import KnativeDomainEditor from '~/clusters/components/knative_domain_editor.vue'; -import LoadingButton from '~/vue_shared/components/loading_button.vue'; import { APPLICATION_STATUS } from '~/clusters/constants'; const { UPDATING } = APPLICATION_STATUS; @@ -79,7 +78,7 @@ describe('KnativeDomainEditor', () => { }); it('triggers save event and pass current knative hostname', () => { - wrapper.find(LoadingButton).vm.$emit('click'); + wrapper.find(GlButton).vm.$emit('click'); return wrapper.vm.$nextTick().then(() => { expect(wrapper.emitted('save').length).toEqual(1); }); @@ -166,15 +165,15 @@ describe('KnativeDomainEditor', () => { }); it('renders loading spinner in save button', () => { - expect(wrapper.find(LoadingButton).props('loading')).toBe(true); + expect(wrapper.find(GlButton).props('loading')).toBe(true); }); it('renders disabled save button', () => { - expect(wrapper.find(LoadingButton).props('disabled')).toBe(true); + expect(wrapper.find(GlButton).props('disabled')).toBe(true); }); it('renders save button with "Saving" label', () => { - expect(wrapper.find(LoadingButton).props('label')).toBe('Saving'); + expect(wrapper.find(GlButton).text()).toBe('Saving'); }); }); }); diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index d38635292a5..45deec259f1 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -57,6 +57,21 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do end end + describe 'usage_activity_by_stage_package' do + it 'includes accurate usage_activity_by_stage data' do + for_defined_days_back do + create(:project, packages: [create(:package)] ) + end + + expect(described_class.usage_activity_by_stage_package({})).to eq( + projects_with_packages: 2 + ) + expect(described_class.usage_activity_by_stage_package(described_class.last_28_days_time_period)).to eq( + projects_with_packages: 1 + ) + end + end + describe '.usage_activity_by_stage_configure' do it 'includes accurate usage_activity_by_stage data' do for_defined_days_back do @@ -400,6 +415,8 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do expect(count_data[:snippets]).to eq(6) expect(count_data[:personal_snippets]).to eq(2) expect(count_data[:project_snippets]).to eq(4) + + expect(count_data[:projects_with_packages]).to eq(2) end it 'gathers object store usage correctly' do |