diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-16 15:10:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-16 15:10:54 +0300 |
commit | f01d3c8c095e70981ffc1d20c050c153f3766421 (patch) | |
tree | 1f072a51c12791df3847fd90bd8e6a369631e990 /app | |
parent | cb20cd86e45ad06b0dc43562c0a1121c3e505c36 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
29 files changed, 236 insertions, 115 deletions
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue index f7e3675c983..a4211002f71 100644 --- a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue +++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue @@ -29,7 +29,7 @@ export default { </script> <template> - <list-item> + <list-item data-testid="abuse-report-row"> <template #left-primary> <div class="gl-font-weight-normal" data-testid="title">{{ title }}</div> </template> diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue index 8726cd2f6fa..b60fe3ae9b8 100644 --- a/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue +++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue @@ -102,6 +102,7 @@ export default { :initial-filter-value="initialFilterValue" :initial-sort-by="initialSortBy" :sort-options="$options.sortOptions" + data-testid="abuse-reports-filtered-search-bar" @onFilter="handleFilter" @onSort="handleSort" /> diff --git a/app/assets/javascripts/admin/abuse_reports/components/app.vue b/app/assets/javascripts/admin/abuse_reports/components/app.vue index a3e04b16ff9..e1e75a4f8d0 100644 --- a/app/assets/javascripts/admin/abuse_reports/components/app.vue +++ b/app/assets/javascripts/admin/abuse_reports/components/app.vue @@ -1,5 +1,5 @@ <script> -import { GlPagination } from '@gitlab/ui'; +import { GlEmptyState, GlPagination } from '@gitlab/ui'; import { mergeUrlParams } from '~/lib/utils/url_utility'; import FilteredSearchBar from './abuse_reports_filtered_search_bar.vue'; import AbuseReportRow from './abuse_report_row.vue'; @@ -9,6 +9,7 @@ export default { components: { AbuseReportRow, FilteredSearchBar, + GlEmptyState, GlPagination, }, props: { @@ -37,7 +38,13 @@ export default { <div> <filtered-search-bar /> - <abuse-report-row v-for="(report, index) in abuseReports" :key="index" :report="report" /> + <gl-empty-state v-if="abuseReports.length == 0" :title="s__('AbuseReports|No reports found')" /> + <abuse-report-row + v-for="(report, index) in abuseReports" + v-else + :key="index" + :report="report" + /> <gl-pagination v-if="showPagination" diff --git a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue index b52b7f6cdeb..65aa4cba074 100644 --- a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue +++ b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue @@ -15,13 +15,22 @@ import { s__ } from '~/locale'; import { createAlert, VARIANT_DANGER } from '~/alert'; import { redirectTo } from '~/lib/utils/url_utility'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { BROADCAST_MESSAGES_PATH, THEMES, TYPES, TYPE_BANNER } from '../constants'; +import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; +import SafeHtml from '~/vue_shared/directives/safe_html'; +import { + BROADCAST_MESSAGES_PATH, + MESSAGES_PREVIEW_PATH, + THEMES, + TYPES, + TYPE_BANNER, +} from '../constants'; import MessageFormGroup from './message_form_group.vue'; import DatetimePicker from './datetime_picker.vue'; const FORM_HEADERS = { headers: { 'Content-Type': 'application/json; charset=utf-8' } }; export default { + DEFAULT_DEBOUNCE_AND_THROTTLE_MS, name: 'MessageForm', components: { DatetimePicker, @@ -36,6 +45,9 @@ export default { GlFormTextarea, MessageFormGroup, }, + directives: { + SafeHtml, + }, mixins: [glFeatureFlagsMixin()], inject: ['targetAccessLevelOptions'], i18n: { @@ -81,6 +93,7 @@ export default { })), startsAt: new Date(this.broadcastMessage.startsAt.getTime()), endsAt: new Date(this.broadcastMessage.endsAt.getTime()), + renderedMessage: '', }; }, computed: { @@ -91,7 +104,7 @@ export default { return this.message.trim() === ''; }, messagePreview() { - return this.messageBlank ? this.$options.i18n.messagePlaceholder : this.message; + return this.messageBlank ? this.$options.i18n.messagePlaceholder : this.renderedMessage; }, isAddForm() { return !this.broadcastMessage.id; @@ -114,6 +127,11 @@ export default { }); }, }, + watch: { + message() { + this.renderPreview(); + }, + }, methods: { async onSubmit() { this.loading = true; @@ -140,13 +158,25 @@ export default { } return true; }, + + async renderPreview() { + try { + const res = await axios.post(MESSAGES_PREVIEW_PATH, this.formPayload, FORM_HEADERS); + this.renderedMessage = res.data; + } catch (e) { + this.renderedMessage = ''; + } + }, + }, + safeHtmlConfig: { + ADD_TAGS: ['use'], }, }; </script> <template> <gl-form @submit.prevent="onSubmit"> <gl-broadcast-message class="gl-my-6" :type="type" :theme="theme" :dismissible="dismissable"> - {{ messagePreview }} + <div v-safe-html:[$options.safeHtmlConfig]="messagePreview"></div> </gl-broadcast-message> <message-form-group :label="$options.i18n.message" label-for="message-textarea"> @@ -154,6 +184,7 @@ export default { id="message-textarea" v-model="message" size="sm" + :debounce="$options.DEFAULT_DEBOUNCE_AND_THROTTLE_MS" :placeholder="$options.i18n.messagePlaceholder" /> </message-form-group> diff --git a/app/assets/javascripts/admin/broadcast_messages/constants.js b/app/assets/javascripts/admin/broadcast_messages/constants.js index 6250d5a943d..323ac6857f6 100644 --- a/app/assets/javascripts/admin/broadcast_messages/constants.js +++ b/app/assets/javascripts/admin/broadcast_messages/constants.js @@ -1,6 +1,7 @@ import { s__ } from '~/locale'; export const BROADCAST_MESSAGES_PATH = '/admin/broadcast_messages'; +export const MESSAGES_PREVIEW_PATH = '/admin/broadcast_messages/preview'; export const TYPE_BANNER = 'banner'; export const TYPE_NOTIFICATION = 'notification'; diff --git a/app/assets/javascripts/ci/runner/components/registration/platforms_drawer.vue b/app/assets/javascripts/ci/runner/components/registration/platforms_drawer.vue index 694ab7b526e..ff182c61ccf 100644 --- a/app/assets/javascripts/ci/runner/components/registration/platforms_drawer.vue +++ b/app/assets/javascripts/ci/runner/components/registration/platforms_drawer.vue @@ -88,6 +88,7 @@ export default { :open="open" :header-height="drawerHeightOffset" :z-index="$options.DRAWER_Z_INDEX" + data-testid="runner-platforms-drawer" @close="onClose" > <template #title> diff --git a/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue b/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue index c2b7b9aea8a..ee9ca5dc08c 100644 --- a/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue +++ b/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue @@ -97,7 +97,7 @@ export default { " > <template #link="{ content }"> - <gl-link @click="toggleDrawer">{{ content }}</gl-link> + <gl-link data-testid="runner-install-link" @click="toggleDrawer">{{ content }}</gl-link> </template> </gl-sprintf> </p> diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index f530c05ae1e..10a6a872fe4 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -90,6 +90,12 @@ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) = export const getDiffFileByHash = (state) => (fileHash) => state.diffFiles.find((file) => file.file_hash === fileHash); +export function isTreePathLoaded(state) { + return (path) => { + return Boolean(state.treeEntries[path]?.diffLoaded); + }; +} + export const flatBlobsList = (state) => Object.values(state.treeEntries).filter((f) => f.type === 'blob'); diff --git a/app/assets/javascripts/related_issues/components/related_issuable_input.vue b/app/assets/javascripts/related_issues/components/related_issuable_input.vue index 8d6a3110f35..1846b9cf8f4 100644 --- a/app/assets/javascripts/related_issues/components/related_issuable_input.vue +++ b/app/assets/javascripts/related_issues/components/related_issuable_input.vue @@ -182,7 +182,7 @@ export default { <div ref="issuableFormWrapper" :class="{ focus: isInputFocused }" - class="add-issuable-form-input-wrapper form-control gl-field-error-outline gl-h-auto gl-p-3 gl-pb-2" + class="add-issuable-form-input-wrapper form-control gl-field-error-outline gl-h-auto gl-px-3 gl-pt-2 gl-pb-0" role="button" @click="onIssuableFormWrapperClick" > diff --git a/app/assets/javascripts/vue_merge_request_widget/constants.js b/app/assets/javascripts/vue_merge_request_widget/constants.js index dbfbd35b9b6..18503720814 100644 --- a/app/assets/javascripts/vue_merge_request_widget/constants.js +++ b/app/assets/javascripts/vue_merge_request_widget/constants.js @@ -2,6 +2,11 @@ import { s__ } from '~/locale'; import { helpPagePath } from '~/helpers/help_page_helper'; import { stateToComponentMap as classStateMap, stateKey } from './stores/state_maps'; +export const FOUR_MINUTES_IN_MS = 1000 * 60 * 4; + +export const STATE_QUERY_POLLING_INTERVAL_DEFAULT = 5000; +export const STATE_QUERY_POLLING_INTERVAL_BACKOFF = 2; + export const SUCCESS = 'success'; export const WARNING = 'warning'; export const INFO = 'info'; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 8867478654a..bbad2c13220 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -1,5 +1,5 @@ <script> -import { isEmpty } from 'lodash'; +import { isEmpty, clamp } from 'lodash'; import { registerExtension, registeredExtensions, @@ -10,7 +10,6 @@ import MRWidgetService from 'ee_else_ce/vue_merge_request_widget/services/mr_wid import MRWidgetStore from 'ee_else_ce/vue_merge_request_widget/stores/mr_widget_store'; import { stateToComponentMap as classState } from 'ee_else_ce/vue_merge_request_widget/stores/state_maps'; import { createAlert } from '~/alert'; -import { secondsToMilliseconds } from '~/lib/utils/datetime_utility'; import notify from '~/lib/utils/notify'; import { sprintf, s__, __ } from '~/locale'; import Project from '~/pages/projects/project'; @@ -44,7 +43,13 @@ import UnresolvedDiscussionsState from './components/states/unresolved_discussio import WorkInProgressState from './components/states/work_in_progress.vue'; import ExtensionsContainer from './components/extensions/container'; import WidgetContainer from './components/widget/app.vue'; -import { STATE_MACHINE, stateToComponentMap } from './constants'; +import { + STATE_MACHINE, + stateToComponentMap, + STATE_QUERY_POLLING_INTERVAL_DEFAULT, + STATE_QUERY_POLLING_INTERVAL_BACKOFF, + FOUR_MINUTES_IN_MS, +} from './constants'; import eventHub from './event_hub'; import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variables'; import getStateQuery from './queries/get_state.query.graphql'; @@ -99,6 +104,7 @@ export default { apollo: { state: { query: getStateQuery, + notifyOnNetworkStatusChange: true, manual: true, skip() { return !this.mr; @@ -106,10 +112,19 @@ export default { variables() { return this.mergeRequestQueryVariables; }, - result({ data: { project } }) { - if (project) { - this.mr.setGraphqlData(project); - this.loading = false; + pollInterval() { + return this.pollInterval; + }, + result(response) { + if (!response.loading) { + this.pollInterval = this.apolloStateQueryPollingInterval; + + if (response.data?.project) { + this.mr.setGraphqlData(response.data.project); + this.loading = false; + } + } else { + this.checkStatus(undefined, undefined, false); } }, subscribeToMore: { @@ -158,9 +173,27 @@ export default { loading: true, recomputeComponentName: 0, issuableId: false, + startingPollInterval: STATE_QUERY_POLLING_INTERVAL_DEFAULT, + pollInterval: STATE_QUERY_POLLING_INTERVAL_DEFAULT, }; }, computed: { + apolloStateQueryMaxPollingInterval() { + return this.startingPollInterval + FOUR_MINUTES_IN_MS; + }, + apolloStateQueryPollingInterval() { + if (this.startingPollInterval < 0) { + return 0; + } + + const unboundedInterval = STATE_QUERY_POLLING_INTERVAL_BACKOFF * this.pollInterval; + + return clamp( + unboundedInterval, + this.startingPollInterval, + this.apolloStateQueryMaxPollingInterval, + ); + }, shouldRenderApprovals() { return this.mr.state !== 'nothingToMerge'; }, @@ -284,7 +317,8 @@ export default { mounted() { MRWidgetService.fetchInitialData() .then(({ data, headers }) => { - this.startingPollInterval = Number(headers['POLL-INTERVAL']); + this.startingPollInterval = + Number(headers['POLL-INTERVAL']) || STATE_QUERY_POLLING_INTERVAL_DEFAULT; this.initWidget(data); }) .catch(() => @@ -295,9 +329,6 @@ export default { }, beforeDestroy() { eventHub.$off('mr.discussion.updated', this.checkStatus); - if (this.pollingInterval) { - this.pollingInterval.destroy(); - } if (this.deploymentsInterval) { this.deploymentsInterval.destroy(); @@ -332,7 +363,6 @@ export default { this.initPostMergeDeploymentsPolling(); } - this.initPolling(); this.bindEventHubListeners(); eventHub.$on('mr.discussion.updated', this.checkStatus); @@ -363,8 +393,10 @@ export default { createService(store) { return new MRWidgetService(this.getServiceEndpoints(store)); }, - checkStatus(cb, isRebased) { - this.$apollo.queries.state.refetch(); + checkStatus(cb, isRebased, refetch = true) { + if (refetch) { + this.$apollo.queries.state.refetch(); + } return this.service .checkStatus() @@ -389,17 +421,6 @@ export default { } return Promise.resolve(); }, - initPolling() { - if (this.startingPollInterval <= 0) return; - - this.pollingInterval = new SmartInterval({ - callback: this.checkStatus, - startingInterval: this.startingPollInterval, - maxInterval: this.startingPollInterval + secondsToMilliseconds(4 * 60), - hiddenInterval: secondsToMilliseconds(6 * 60), - incrementByFactorOf: 2, - }); - }, initDeploymentsPolling() { this.deploymentsInterval = this.deploymentsPoll(this.fetchPreMergeDeployments); }, @@ -476,10 +497,10 @@ export default { notify.notifyMe(title, message, this.mr.gitlabLogo); }, resumePolling() { - this.pollingInterval?.resume(); + this.$apollo.queries.state.startPolling(this.pollInterval); }, stopPolling() { - this.pollingInterval?.stopTimer(); + this.$apollo.queries.state.stopPolling(); }, bindEventHubListeners() { eventHub.$on('MRWidgetUpdateRequested', (cb) => { diff --git a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue index f010fb1b5ce..1396d19d679 100644 --- a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue +++ b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue @@ -96,30 +96,41 @@ export default { </script> <template> - <form class="common-note-form gfm-form js-main-target-form gl-flex-grow-1"> - <markdown-editor - :value="commentText" - :render-markdown-path="markdownPreviewPath" - :markdown-docs-path="$options.constantOptions.markdownDocsPath" - :form-field-props="formFieldProps" - data-testid="work-item-add-comment" - class="gl-mb-3" - autofocus - @input="setCommentText" - @keydown.meta.enter="$emit('submitForm', commentText)" - @keydown.ctrl.enter="$emit('submitForm', commentText)" - @keydown.esc.stop="cancelEditing" - /> - <gl-button - category="primary" - variant="confirm" - data-testid="confirm-button" - :loading="isSubmitting" - @click="$emit('submitForm', commentText)" - >{{ commentButtonText }} - </gl-button> - <gl-button data-testid="cancel-button" category="primary" class="gl-ml-3" @click="cancelEditing" - >{{ __('Cancel') }} - </gl-button> - </form> + <div class="timeline-content"> + <div class="timeline-discussion-body"> + <div class="note-body"> + <form class="common-note-form gfm-form js-main-target-form gl-flex-grow-1"> + <markdown-editor + :value="commentText" + :render-markdown-path="markdownPreviewPath" + :markdown-docs-path="$options.constantOptions.markdownDocsPath" + :form-field-props="formFieldProps" + data-testid="work-item-add-comment" + class="gl-mb-3" + autofocus + use-bottom-toolbar + @input="setCommentText" + @keydown.meta.enter="$emit('submitForm', commentText)" + @keydown.ctrl.enter="$emit('submitForm', commentText)" + @keydown.esc.stop="cancelEditing" + /> + <gl-button + category="primary" + variant="confirm" + data-testid="confirm-button" + :loading="isSubmitting" + @click="$emit('submitForm', commentText)" + >{{ commentButtonText }} + </gl-button> + <gl-button + data-testid="cancel-button" + category="primary" + class="gl-ml-3" + @click="cancelEditing" + >{{ __('Cancel') }} + </gl-button> + </form> + </div> + </div> + </div> </template> diff --git a/app/assets/javascripts/work_items/components/widget_wrapper.vue b/app/assets/javascripts/work_items/components/widget_wrapper.vue index ba1470f97cd..db36b4e1bbe 100644 --- a/app/assets/javascripts/work_items/components/widget_wrapper.vue +++ b/app/assets/javascripts/work_items/components/widget_wrapper.vue @@ -73,7 +73,7 @@ export default { <div v-if="isOpen" class="gl-bg-gray-10 gl-rounded-bottom-left-base gl-rounded-bottom-right-base" - :class="{ 'gl-px-5 gl-py-4': !error }" + :class="{ 'gl-p-3': !error }" data-testid="widget-body" > <slot name="body"></slot> diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index 3f5e1c74c31..ad7a54aaf16 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -115,11 +115,6 @@ export default { required: false, default: null, }, - modal: { - type: Object, - required: false, - default: null, - }, }, data() { const workItemId = getParameterByName('work_item_id'); @@ -707,20 +702,16 @@ export default { @removeChild="removeChild" @show-modal="openInModal" /> - <template v-if="workItemsMvcEnabled"> - <work-item-notes - v-if="workItemNotes" - :work-item-id="workItem.id" - :query-variables="queryVariables" - :full-path="fullPath" - :fetch-by-iid="fetchByIid" - :work-item-type="workItemType" - :is-modal="isModal" - class="gl-pt-5" - @error="updateError = $event" - @has-notes="updateHasNotes" - /> - </template> + <work-item-notes + v-if="workItemNotes" + :work-item-id="workItem.id" + :query-variables="queryVariables" + :full-path="fullPath" + :fetch-by-iid="fetchByIid" + :work-item-type="workItemType" + class="gl-pt-5" + @error="updateError = $event" + /> <gl-empty-state v-if="error" :title="$options.i18n.fetchErrorTitle" diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue index 620d86bb363..d119cdc2785 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue @@ -109,7 +109,9 @@ export default { return this.isItemOpen ? __('Created') : __('Closed'); }, childPath() { - return `/${this.projectPath}/-/work_items/${this.childItem.iid}?iid_path=true`; + return `${gon?.relative_url_root || ''}/${this.projectPath}/-/work_items/${ + this.childItem.iid + }?iid_path=true`; }, hasChildren() { return this.getWidgetByType(this.childItem, WIDGET_TYPE_HIERARCHY)?.hasChildren; @@ -171,7 +173,7 @@ export default { <template> <div> <div - class="gl-display-flex gl-align-items-flex-start gl-mb-3" + class="gl-display-flex gl-align-items-flex-start" :class="{ 'gl-ml-6': canHaveChildren && !hasChildren && hasIndirectChildren }" > <gl-button @@ -181,18 +183,20 @@ export default { :aria-label="chevronTooltip" :icon="chevronType" category="tertiary" + size="small" :loading="isLoadingChildren" class="gl-px-0! gl-py-3! gl-mr-3" data-testid="expand-child" @click="toggleItem" /> <div - class="gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-bg-white gl-py-3 gl-px-4 gl-border gl-border-gray-100 gl-rounded-base gl-line-height-32" + class="work-item-link-child gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-pl-3 gl-pr-2 gl-rounded-base" + :class="[hasMetadata ? 'gl-py-3' : 'gl-py-0']" data-testid="links-child" > <span :id="`stateIcon-${childItem.id}`" - class="gl-mr-3" + class="gl-cursor-help gl-mr-3 gl-line-height-32" :class="{ 'gl-display-flex': hasMetadata }" data-testid="item-status-icon" > @@ -239,7 +243,7 @@ export default { <work-item-link-child-metadata v-if="hasMetadata" :metadata-widgets="metadataWidgets" - class="gl-mt-3" + class="gl-mt-1" /> </div> <div diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue index d7e54ea1eb0..8f0e429234f 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue @@ -334,11 +334,11 @@ export default { </gl-dropdown> </template> <template #body> - <gl-loading-icon v-if="isLoading" color="dark" class="gl-my-3" /> + <gl-loading-icon v-if="isLoading" color="dark" class="gl-my-2" /> <template v-else> <div v-if="isChildrenEmpty && !isShownAddForm && !error" data-testid="links-empty"> - <p class="gl-mb-0 gl-text-gray-500"> + <p class="gl-px-3 gl-py-2 gl-mb-0 gl-text-gray-500"> {{ $options.i18n.emptyStateMessage }} </p> </div> diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue index 5169a77dd33..af475496075 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue @@ -340,7 +340,7 @@ export default { <template> <gl-form - class="gl-bg-white gl-mb-3 gl-p-4 gl-border gl-border-gray-100 gl-rounded-base" + class="gl-bg-white gl-mt-1 gl-mb-3 gl-p-4 gl-border gl-border-gray-100 gl-rounded-base" @submit.prevent="addOrCreateMethod" > <gl-alert v-if="error" variant="danger" class="gl-mb-3" @dismiss="unsetError"> diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue index 1aa4a433a58..fb3ed7af736 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_menu.vue @@ -11,8 +11,8 @@ export default { </script> <template> - <span class="gl-ml-2"> - <gl-dropdown category="tertiary" toggle-class="btn-icon" :right="true"> + <span class="gl-ml-5"> + <gl-dropdown category="tertiary" toggle-class="btn-icon btn-sm" :right="true"> <template #button-content> <gl-icon name="ellipsis_v" :size="14" /> </template> diff --git a/app/assets/javascripts/work_items/router/index.js b/app/assets/javascripts/work_items/router/index.js index 777badeb5be..8d67bcaf84f 100644 --- a/app/assets/javascripts/work_items/router/index.js +++ b/app/assets/javascripts/work_items/router/index.js @@ -11,6 +11,6 @@ export function createRouter(fullPath) { return new VueRouter({ routes: routes(), mode: 'history', - base: joinPaths(fullPath, '-', 'work_items'), + base: joinPaths(gon?.relative_url_root, fullPath, '-', 'work_items'), }); } diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index b685a27b216..b6ac4939a9c 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -289,3 +289,22 @@ label { .input-group-text { max-height: $input-height; } + +.add-issuable-form-input-wrapper { + &.focus { + border-color: var(--gray-700, $gray-700); + + input { + @include gl-shadow-none; + } + } + + .gl-show-field-errors &.form-control:not(textarea) { + height: auto; + } +} + +.add-issuable-form-input-wrapper.focus, +.issue-token-remove-button:focus { + @include gl-focus; +} diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss index 32e9bba8712..699693bd354 100644 --- a/app/assets/stylesheets/framework/timeline.scss +++ b/app/assets/stylesheets/framework/timeline.scss @@ -31,6 +31,7 @@ &:not(.note-form).internal-note .timeline-content, &:not(.note-form).draft-note .timeline-content { background-color: $orange-50 !important; + border-radius: 3px; } .timeline-entry-inner { diff --git a/app/assets/stylesheets/page_bundles/issuable.scss b/app/assets/stylesheets/page_bundles/issuable.scss index 7321da1526d..6ec6a282329 100644 --- a/app/assets/stylesheets/page_bundles/issuable.scss +++ b/app/assets/stylesheets/page_bundles/issuable.scss @@ -139,21 +139,6 @@ } } -.add-issuable-form-input-wrapper { - &.focus { - border-color: var(--gray-700, $gray-700); - @include gl-focus; - - input { - @include gl-shadow-none; - } - } - - .gl-show-field-errors &.form-control:not(textarea) { - height: auto; - } -} - /* * Following overrides are done to prevent * legacy dropdown styles from influencing diff --git a/app/assets/stylesheets/page_bundles/work_items.scss b/app/assets/stylesheets/page_bundles/work_items.scss index 5f6883623b2..00c86c46ac8 100644 --- a/app/assets/stylesheets/page_bundles/work_items.scss +++ b/app/assets/stylesheets/page_bundles/work_items.scss @@ -87,6 +87,19 @@ } } +.work-item-link-child { + @include gl-border-1; + @include gl-border-solid; + @include gl-border-transparent; + @include gl-rounded-base; + + &:hover, + &:focus-within { + @include gl-bg-white; + @include gl-border-gray-50; + } +} + // sticky error placement for errors in modals , by default it is 83px for full view #work-item-detail-modal { .flash-container.flash-container-page.sticky { diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb index d641a26c9fb..654b8309937 100644 --- a/app/controllers/admin/broadcast_messages_controller.rb +++ b/app/controllers/admin/broadcast_messages_controller.rb @@ -72,7 +72,7 @@ module Admin def preview @broadcast_message = BroadcastMessage.new(broadcast_message_params) - render partial: 'admin/broadcast_messages/preview' + render plain: render_broadcast_message(@broadcast_message), status: :ok end protected diff --git a/app/controllers/groups/children_controller.rb b/app/controllers/groups/children_controller.rb index fb3a86d5219..ca3be1542aa 100644 --- a/app/controllers/groups/children_controller.rb +++ b/app/controllers/groups/children_controller.rb @@ -5,6 +5,8 @@ module Groups extend ::Gitlab::Utils::Override before_action :group + before_action :validate_per_page + skip_cross_project_access_check :index feature_category :subgroups @@ -44,7 +46,7 @@ module Groups @children = GroupDescendantsFinder.new( current_user: current_user, parent_group: parent, - params: params.to_unsafe_h + params: group_descendants_params ).execute.page(params[:page]) end @@ -54,5 +56,25 @@ module Groups def has_project_list? true end + + def group_descendants_params + @group_descendants_params ||= params.to_unsafe_h.compact + end + + def validate_per_page + return unless group_descendants_params.key?(:per_page) + + per_page = begin + Integer(group_descendants_params[:per_page]) + rescue ArgumentError, TypeError + 0 + end + + respond_to do |format| + format.json do + render status: :bad_request, json: { message: 'per_page does not have a valid value' } if per_page < 1 + end + end + end end end diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index a5f938dc1c7..604ca7e3a1a 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -10,6 +10,7 @@ class CommitStatus < Ci::ApplicationRecord include TaggableQueries self.table_name = 'ci_builds' + self.primary_key = :id partitionable scope: :pipeline belongs_to :user diff --git a/app/views/admin/broadcast_messages/_preview.html.haml b/app/views/admin/broadcast_messages/_preview.html.haml deleted file mode 100644 index 56168926a6e..00000000000 --- a/app/views/admin/broadcast_messages/_preview.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -.js-broadcast-banner-message-preview - = render "shared/broadcast_message", { message: @broadcast_message, preview: true } do - = _('Your message here') diff --git a/app/views/projects/commit/diff_files.html.haml b/app/views/projects/commit/diff_files.html.haml index 0c52c1a15a4..7287d10a109 100644 --- a/app/views/projects/commit/diff_files.html.haml +++ b/app/views/projects/commit/diff_files.html.haml @@ -1 +1,5 @@ -= render partial: 'projects/diffs/file', collection: diffs.diff_files, as: :diff_file, locals: { project: diffs.project, environment: environment, diff_page_context: 'is-commit' } +- diff_files = conditionally_paginate_diff_files(diffs, paginate: true, page: params[:page], per: Projects::CommitController::COMMIT_DIFFS_PER_PAGE) + += render partial: 'projects/diffs/file', collection: diff_files, as: :diff_file, locals: { project: diffs.project, environment: environment, diff_page_context: 'is-commit' } + += paginate(diff_files, theme: "gitlab", params: { action: :show }) diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index 8ff6d348d95..03e26fd4456 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -3,7 +3,7 @@ - can_create_note = !@diff_notes_disabled && can?(current_user, :create_note, diffs.project) - diff_page_context = local_assigns.fetch(:diff_page_context, nil) - load_diff_files_async = Feature.enabled?(:async_commit_diff_files, @project) && diff_page_context == "is-commit" -- paginate_diffs = local_assigns.fetch(:paginate_diffs, false) && !load_diff_files_async +- paginate_diffs = local_assigns.fetch(:paginate_diffs, false) - paginate_diffs_per_page = local_assigns.fetch(:paginate_diffs_per_page, nil) - page = local_assigns.fetch(:page, nil) - diff_files = conditionally_paginate_diff_files(diffs, paginate: paginate_diffs, page: page, per: paginate_diffs_per_page) @@ -32,7 +32,7 @@ .files{ data: { can_create_note: can_create_note } } - if load_diff_files_async - - url = url_for(safe_params.merge(action: 'diff_files')) + - url = url_for(safe_params.merge(action: 'diff_files', page: page)) .js-diffs-batch{ data: { diff_files_path: url } } = gl_loading_icon(size: "md", css_class: "gl-mt-4") - else |