diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 00:08:05 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 00:08:05 +0300 |
commit | 680d18802596089dc407b7011bcf682d24846aec (patch) | |
tree | 09e1beea15fe9ba9d1a757c31b7836e5f7e9fa89 /app | |
parent | d84f18d66c1fc46f244b0f4dec8bf65b90d9882a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
14 files changed, 154 insertions, 75 deletions
diff --git a/app/assets/javascripts/clusters_list/components/clusters.vue b/app/assets/javascripts/clusters_list/components/clusters.vue index eb575b9ed6c..af3f1437c64 100644 --- a/app/assets/javascripts/clusters_list/components/clusters.vue +++ b/app/assets/javascripts/clusters_list/components/clusters.vue @@ -1,22 +1,32 @@ <script> import { mapState, mapActions } from 'vuex'; -import { GlTable, GlLink, GlLoadingIcon, GlBadge } from '@gitlab/ui'; +import { GlBadge, GlLink, GlLoadingIcon, GlPagination, GlTable } from '@gitlab/ui'; import tooltip from '~/vue_shared/directives/tooltip'; import { CLUSTER_TYPES, STATUSES } from '../constants'; import { __, sprintf } from '~/locale'; export default { components: { - GlTable, + GlBadge, GlLink, GlLoadingIcon, - GlBadge, + GlPagination, + GlTable, }, directives: { tooltip, }, computed: { - ...mapState(['clusters', 'loading']), + ...mapState(['clusters', 'clustersPerPage', 'loading', 'page', 'totalCulsters']), + currentPage: { + get() { + return this.page; + }, + set(newVal) { + this.setPage(newVal); + this.fetchClusters(); + }, + }, fields() { return [ { @@ -47,12 +57,15 @@ export default { }, ]; }, + hasClusters() { + return this.clustersPerPage > 0; + }, }, mounted() { this.fetchClusters(); }, methods: { - ...mapActions(['fetchClusters']), + ...mapActions(['fetchClusters', 'setPage']), statusClass(status) { const iconClass = STATUSES[status] || STATUSES.default; return iconClass.className; @@ -67,33 +80,46 @@ export default { <template> <gl-loading-icon v-if="loading" size="md" class="mt-3" /> - <gl-table v-else :items="clusters" :fields="fields" stacked="md" class="qa-clusters-table"> - <template #cell(name)="{ item }"> - <div class="d-flex flex-row-reverse flex-md-row js-status"> - <gl-link data-qa-selector="cluster" :data-qa-cluster-name="item.name" :href="item.path"> - {{ item.name }} - </gl-link> - <gl-loading-icon - v-if="item.status === 'deleting'" - v-tooltip - :title="statusTitle(item.status)" - size="sm" - class="mr-2 ml-md-2" - /> - <div - v-else - v-tooltip - class="cluster-status-indicator rounded-circle align-self-center gl-w-4 gl-h-4 mr-2 ml-md-2" - :class="statusClass(item.status)" - :title="statusTitle(item.status)" - ></div> - </div> - </template> - <template #cell(cluster_type)="{value}"> - <gl-badge variant="light"> - {{ value }} - </gl-badge> - </template> - </gl-table> + <section v-else> + <gl-table :items="clusters" :fields="fields" stacked="md" class="qa-clusters-table"> + <template #cell(name)="{ item }"> + <div class="d-flex flex-row-reverse flex-md-row js-status"> + <gl-link data-qa-selector="cluster" :data-qa-cluster-name="item.name" :href="item.path"> + {{ item.name }} + </gl-link> + + <gl-loading-icon + v-if="item.status === 'deleting'" + v-tooltip + :title="statusTitle(item.status)" + size="sm" + class="mr-2 ml-md-2" + /> + <div + v-else + v-tooltip + class="cluster-status-indicator rounded-circle align-self-center gl-w-4 gl-h-4 mr-2 ml-md-2" + :class="statusClass(item.status)" + :title="statusTitle(item.status)" + ></div> + </div> + </template> + <template #cell(cluster_type)="{value}"> + <gl-badge variant="light"> + {{ value }} + </gl-badge> + </template> + </gl-table> + + <gl-pagination + v-if="hasClusters" + v-model="currentPage" + :per-page="clustersPerPage" + :total-items="totalCulsters" + :prev-text="__('Prev')" + :next-text="__('Next')" + align="center" + /> + </section> </template> diff --git a/app/assets/javascripts/clusters_list/store/actions.js b/app/assets/javascripts/clusters_list/store/actions.js index d0ad92f5536..919625f69b4 100644 --- a/app/assets/javascripts/clusters_list/store/actions.js +++ b/app/assets/javascripts/clusters_list/store/actions.js @@ -2,18 +2,22 @@ import Poll from '~/lib/utils/poll'; import axios from '~/lib/utils/axios_utils'; import flash from '~/flash'; import { __ } from '~/locale'; +import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; import * as types from './mutation_types'; export const fetchClusters = ({ state, commit }) => { const poll = new Poll({ resource: { - fetchClusters: endpoint => axios.get(endpoint), + fetchClusters: paginatedEndPoint => axios.get(paginatedEndPoint), }, - data: state.endpoint, + data: `${state.endpoint}?page=${state.page}`, method: 'fetchClusters', - successCallback: ({ data }) => { + successCallback: ({ data, headers }) => { if (data.clusters) { - commit(types.SET_CLUSTERS_DATA, data); + const normalizedHeaders = normalizeHeaders(headers); + const paginationInformation = parseIntPagination(normalizedHeaders); + + commit(types.SET_CLUSTERS_DATA, { data, paginationInformation }); commit(types.SET_LOADING_STATE, false); poll.stop(); } @@ -24,5 +28,9 @@ export const fetchClusters = ({ state, commit }) => { poll.makeRequest(); }; +export const setPage = ({ commit }, page) => { + commit(types.SET_PAGE, page); +}; + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/clusters_list/store/mutation_types.js b/app/assets/javascripts/clusters_list/store/mutation_types.js index f056f3ab7d9..a5275f28c13 100644 --- a/app/assets/javascripts/clusters_list/store/mutation_types.js +++ b/app/assets/javascripts/clusters_list/store/mutation_types.js @@ -1,2 +1,3 @@ export const SET_CLUSTERS_DATA = 'SET_CLUSTERS_DATA'; export const SET_LOADING_STATE = 'SET_LOADING_STATE'; +export const SET_PAGE = 'SET_PAGE'; diff --git a/app/assets/javascripts/clusters_list/store/mutations.js b/app/assets/javascripts/clusters_list/store/mutations.js index ce53a033628..2a9df9f38f0 100644 --- a/app/assets/javascripts/clusters_list/store/mutations.js +++ b/app/assets/javascripts/clusters_list/store/mutations.js @@ -4,10 +4,15 @@ export default { [types.SET_LOADING_STATE](state, value) { state.loading = value; }, - [types.SET_CLUSTERS_DATA](state, data) { + [types.SET_CLUSTERS_DATA](state, { data, paginationInformation }) { Object.assign(state, { clusters: data.clusters, + clustersPerPage: paginationInformation.perPage, hasAncestorClusters: data.has_ancestor_clusters, + totalCulsters: paginationInformation.total, }); }, + [types.SET_PAGE](state, value) { + state.page = Number(value) || 1; + }, }; diff --git a/app/assets/javascripts/clusters_list/store/state.js b/app/assets/javascripts/clusters_list/store/state.js index 31e73558c2e..d590ea09e66 100644 --- a/app/assets/javascripts/clusters_list/store/state.js +++ b/app/assets/javascripts/clusters_list/store/state.js @@ -3,4 +3,7 @@ export default (initialState = {}) => ({ hasAncestorClusters: false, loading: true, clusters: [], + clustersPerPage: 0, + page: 1, + totalCulsters: 0, }); diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue index a323e08d26d..81812ee2279 100644 --- a/app/assets/javascripts/notes/components/note_header.vue +++ b/app/assets/javascripts/notes/components/note_header.vue @@ -1,5 +1,6 @@ <script> import { mapActions } from 'vuex'; +import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; export default { @@ -7,6 +8,10 @@ export default { timeAgoTooltip, GitlabTeamMemberBadge: () => import('ee_component/vue_shared/components/user_avatar/badges/gitlab_team_member_badge.vue'), + GlIcon, + }, + directives: { + GlTooltip: GlTooltipDirective, }, props: { author: { @@ -44,6 +49,11 @@ export default { required: false, default: true, }, + isConfidential: { + type: Boolean, + required: false, + default: false, + }, }, data() { return { @@ -174,6 +184,15 @@ export default { </a> <time-ago-tooltip v-else ref="noteTimestamp" :time="createdAt" tooltip-placement="bottom" /> </template> + <gl-icon + v-if="isConfidential" + v-gl-tooltip:tooltipcontainer.bottom + data-testid="confidentialIndicator" + name="eye-slash" + :size="14" + :title="s__('Notes|Private comments are accessible by internal staff only')" + class="gl-ml-1 gl-text-gray-800 align-middle" + /> <slot name="extra-controls"></slot> <i v-if="showSpinner" diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index a74207403e1..37675e20b3d 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -255,7 +255,13 @@ export default { </div> <div class="timeline-content"> <div class="note-header"> - <note-header v-once :author="author" :created-at="note.created_at" :note-id="note.id"> + <note-header + v-once + :author="author" + :created-at="note.created_at" + :note-id="note.id" + :is-confidential="note.confidential" + > <slot slot="note-header-info" name="note-header-info"></slot> <span v-if="commit" v-html="actionText"></span> <span v-else-if="note.created_at" class="d-none d-sm-inline">·</span> diff --git a/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue b/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue index 26adf4cbbe0..e18732d0fd5 100644 --- a/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue +++ b/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue @@ -68,7 +68,7 @@ export default { footer-primary-button-variant="warning" @submit="onSubmit" > - <template slot="title"> + <template #title> {{ title }} </template> <div> diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 50443048274..a24c0471d6c 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -316,6 +316,7 @@ class ProjectPolicy < BasePolicy enable :update_deployment enable :create_release enable :update_release + enable :daily_statistics enable :create_metrics_dashboard_annotation enable :delete_metrics_dashboard_annotation enable :update_metrics_dashboard_annotation @@ -358,7 +359,6 @@ class ProjectPolicy < BasePolicy enable :create_environment_terminal enable :destroy_release enable :destroy_artifacts - enable :daily_statistics enable :admin_operations enable :read_deploy_token enable :create_deploy_token diff --git a/app/services/snippets/base_service.rb b/app/services/snippets/base_service.rb index c8215e79c56..81d12997335 100644 --- a/app/services/snippets/base_service.rb +++ b/app/services/snippets/base_service.rb @@ -2,8 +2,32 @@ module Snippets class BaseService < ::BaseService + include SpamCheckMethods + + CreateRepositoryError = Class.new(StandardError) + + attr_reader :uploaded_files + + def initialize(project, user = nil, params = {}) + super + + @uploaded_files = Array(@params.delete(:files).presence) + + filter_spam_check_params + end + private + def visibility_allowed?(snippet, visibility_level) + Gitlab::VisibilityLevel.allowed_for?(current_user, visibility_level) + end + + def error_forbidden_visibility(snippet) + deny_visibility_level(snippet) + + snippet_error_response(snippet, 403) + end + def snippet_error_response(snippet, http_status) ServiceResponse.error( message: snippet.errors.full_messages.to_sentence, diff --git a/app/services/snippets/create_service.rb b/app/services/snippets/create_service.rb index bb58d1bc2bc..ed6da3a0ad0 100644 --- a/app/services/snippets/create_service.rb +++ b/app/services/snippets/create_service.rb @@ -2,25 +2,11 @@ module Snippets class CreateService < Snippets::BaseService - include SpamCheckMethods - - CreateRepositoryError = Class.new(StandardError) - def execute - filter_spam_check_params - - @files = Array(params.delete(:files).presence) - - @snippet = if project - project.snippets.build(params) - else - PersonalSnippet.new(params) - end - - unless Gitlab::VisibilityLevel.allowed_for?(current_user, @snippet.visibility_level) - deny_visibility_level(@snippet) + @snippet = build_from_params - return snippet_error_response(@snippet, 403) + unless visibility_allowed?(@snippet, @snippet.visibility_level) + return error_forbidden_visibility(@snippet) end @snippet.author = current_user @@ -41,6 +27,14 @@ module Snippets private + def build_from_params + if project + project.snippets.build(params) + else + PersonalSnippet.new(params) + end + end + def save_and_commit snippet_saved = @snippet.save @@ -91,7 +85,7 @@ module Snippets def move_temporary_files return unless @snippet.is_a?(PersonalSnippet) - @files.each do |file| + uploaded_files.each do |file| FileMover.new(file, from_model: current_user, to_model: @snippet).execute end end diff --git a/app/services/snippets/update_service.rb b/app/services/snippets/update_service.rb index e12610135c9..2dc9266dbd0 100644 --- a/app/services/snippets/update_service.rb +++ b/app/services/snippets/update_service.rb @@ -2,26 +2,15 @@ module Snippets class UpdateService < Snippets::BaseService - include SpamCheckMethods - COMMITTABLE_ATTRIBUTES = %w(file_name content).freeze UpdateError = Class.new(StandardError) - CreateRepositoryError = Class.new(StandardError) def execute(snippet) - # check that user is allowed to set specified visibility_level - new_visibility = visibility_level - - if new_visibility && new_visibility.to_i != snippet.visibility_level - unless Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility) - deny_visibility_level(snippet, new_visibility) - - return snippet_error_response(snippet, 403) - end + if visibility_changed?(snippet) && !visibility_allowed?(snippet, visibility_level) + return error_forbidden_visibility(snippet) end - filter_spam_check_params snippet.assign_attributes(params) spam_check(snippet, current_user) @@ -36,6 +25,10 @@ module Snippets private + def visibility_changed?(snippet) + visibility_level && visibility_level.to_i != snippet.visibility_level + end + def save_and_commit(snippet) return false unless snippet.save diff --git a/app/views/shared/access_tokens/_table.html.haml b/app/views/shared/access_tokens/_table.html.haml index a05d0a2c006..5518c31cb06 100644 --- a/app/views/shared/access_tokens/_table.html.haml +++ b/app/views/shared/access_tokens/_table.html.haml @@ -27,7 +27,7 @@ %td - if token.expires? %span{ class: ('text-warning' if token.expires_soon?) } - In #{distance_of_time_in_words_to_now(token.expires_at)} + = _('In %{time_to_now}') % { time_to_now: distance_of_time_in_words_to_now(token.expires_at) } - else %span.token-never-expires-label= _('Never') %td= token.scopes.present? ? token.scopes.join(', ') : _('<no scopes selected>') diff --git a/app/views/users/calendar_activities.html.haml b/app/views/users/calendar_activities.html.haml index 7516dfe1602..a5197a9950b 100644 --- a/app/views/users/calendar_activities.html.haml +++ b/app/views/users/calendar_activities.html.haml @@ -22,14 +22,14 @@ - elsif event.target = link_to event.target.to_reference, [event.project.namespace.becomes(Namespace), event.project, event.target], class: 'has-tooltip', title: event.target_title - at + = s_('UserProfile|at') %strong - if event.project = link_to_project(event.project) - else = event.resource_parent_name - else - made a private contribution + = s_('UserProfile|made a private contribution') - else %p = _('No contributions were found') |