diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 14:59:07 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 14:59:07 +0300 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /app/assets/javascripts/jobs | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'app/assets/javascripts/jobs')
-rw-r--r-- | app/assets/javascripts/jobs/components/job_app.vue | 15 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/components/log/line.vue | 65 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/components/unmet_prerequisites_block.vue | 27 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/mixins/delayed_job_mixin.js | 7 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/store/actions.js | 35 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/store/mutations.js | 1 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/utils.js | 14 |
7 files changed, 97 insertions, 67 deletions
diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue index c6adf2f231f..30093224631 100644 --- a/app/assets/javascripts/jobs/components/job_app.vue +++ b/app/assets/javascripts/jobs/components/job_app.vue @@ -1,12 +1,11 @@ <script> import { throttle, isEmpty } from 'lodash'; import { mapGetters, mapState, mapActions } from 'vuex'; -import { GlLoadingIcon, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; +import { GlLoadingIcon, GlIcon, GlSafeHtmlDirective as SafeHtml, GlAlert } from '@gitlab/ui'; import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils'; import { isScrolledToBottom } from '~/lib/utils/scroll_utils'; import { polyfillSticky } from '~/lib/utils/sticky'; import CiHeader from '~/vue_shared/components/header_ci_component.vue'; -import Callout from '~/vue_shared/components/callout.vue'; import EmptyState from './empty_state.vue'; import EnvironmentsBlock from './environments_block.vue'; import ErasedBlock from './erased_block.vue'; @@ -22,7 +21,6 @@ export default { name: 'JobPageApp', components: { CiHeader, - Callout, EmptyState, EnvironmentsBlock, ErasedBlock, @@ -34,6 +32,7 @@ export default { Sidebar, GlLoadingIcon, SharedRunner: () => import('ee_component/jobs/components/shared_runner_limit_block.vue'), + GlAlert, }, directives: { SafeHtml, @@ -223,10 +222,14 @@ export default { @clickedSidebarButton="toggleSidebar" /> </div> - - <callout v-if="shouldRenderHeaderCallout"> + <gl-alert + v-if="shouldRenderHeaderCallout" + variant="danger" + class="gl-mt-3" + :dismissible="false" + > <div v-safe-html="job.callout_message"></div> - </callout> + </gl-alert> </header> <!-- EO Header Section --> diff --git a/app/assets/javascripts/jobs/components/log/line.vue b/app/assets/javascripts/jobs/components/log/line.vue index affaddcdee2..87af387ca91 100644 --- a/app/assets/javascripts/jobs/components/log/line.vue +++ b/app/assets/javascripts/jobs/components/log/line.vue @@ -18,46 +18,33 @@ export default { render(h, { props }) { const { line, path } = props; - let chars; - if (gon?.features?.ciJobLineLinks) { - chars = line.content.map(content => { - return h( - 'span', - { - class: ['gl-white-space-pre-wrap', content.style], - }, - // Simple "tokenization": Split text in chunks of text - // which alternate between text and urls. - content.text.split(linkRegex).map(chunk => { - // Return normal string for non-links - if (!chunk.match(linkRegex)) { - return chunk; - } - return h( - 'a', - { - attrs: { - href: chunk, - class: 'gl-reset-color! gl-text-decoration-underline', - rel: 'nofollow noopener noreferrer', // eslint-disable-line @gitlab/require-i18n-strings - }, + const chars = line.content.map(content => { + return h( + 'span', + { + class: ['gl-white-space-pre-wrap', content.style], + }, + // Simple "tokenization": Split text in chunks of text + // which alternate between text and urls. + content.text.split(linkRegex).map(chunk => { + // Return normal string for non-links + if (!chunk.match(linkRegex)) { + return chunk; + } + return h( + 'a', + { + attrs: { + href: chunk, + class: 'gl-reset-color! gl-text-decoration-underline', + rel: 'nofollow noopener noreferrer', // eslint-disable-line @gitlab/require-i18n-strings }, - chunk, - ); - }), - ); - }); - } else { - chars = line.content.map(content => { - return h( - 'span', - { - class: ['gl-white-space-pre-wrap', content.style], - }, - content.text, - ); - }); - } + }, + chunk, + ); + }), + ); + }); return h('div', { class: 'js-line log-line' }, [ h(LineNumber, { diff --git a/app/assets/javascripts/jobs/components/unmet_prerequisites_block.vue b/app/assets/javascripts/jobs/components/unmet_prerequisites_block.vue index 633561c879e..c9747ca9f02 100644 --- a/app/assets/javascripts/jobs/components/unmet_prerequisites_block.vue +++ b/app/assets/javascripts/jobs/components/unmet_prerequisites_block.vue @@ -1,11 +1,19 @@ <script> -import { GlLink } from '@gitlab/ui'; +import { GlLink, GlAlert } from '@gitlab/ui'; +import { __, s__ } from '~/locale'; /** * Renders Unmet Prerequisites block for job's view. */ export default { + i18n: { + failMessage: s__( + 'Job|This job failed because the necessary resources were not successfully created.', + ), + moreInformation: __('More information'), + }, components: { GlLink, + GlAlert, }, props: { helpPath: { @@ -16,15 +24,10 @@ export default { }; </script> <template> - <div class="bs-callout bs-callout-danger"> - <p class="js-failed-unmet-prerequisites gl-mb-0"> - {{ - s__(`Job|This job failed because the necessary resources were not successfully created.`) - }} - - <gl-link :href="helpPath" class="js-help-path"> - <strong> {{ __('More information') }} </strong> - </gl-link> - </p> - </div> + <gl-alert variant="danger" class="gl-mt-3" :dismissible="false"> + {{ $options.i18n.failMessage }} + <gl-link :href="helpPath"> + {{ $options.i18n.moreInformation }} + </gl-link> + </gl-alert> </template> diff --git a/app/assets/javascripts/jobs/mixins/delayed_job_mixin.js b/app/assets/javascripts/jobs/mixins/delayed_job_mixin.js index 8c7fb785a61..7b17dc7f693 100644 --- a/app/assets/javascripts/jobs/mixins/delayed_job_mixin.js +++ b/app/assets/javascripts/jobs/mixins/delayed_job_mixin.js @@ -20,7 +20,10 @@ export default { computed: { isDelayedJob() { - return this.job && this.job.scheduled; + return this.job?.scheduled || this.job?.scheduledAt; + }, + scheduledTime() { + return this.job.scheduled_at || this.job.scheduledAt; }, }, @@ -43,7 +46,7 @@ export default { }, updateRemainingTime() { - const remainingMilliseconds = calculateRemainingMilliseconds(this.job.scheduled_at); + const remainingMilliseconds = calculateRemainingMilliseconds(this.scheduledTime); this.remainingTime = formatTime(remainingMilliseconds); }, }, diff --git a/app/assets/javascripts/jobs/store/actions.js b/app/assets/javascripts/jobs/store/actions.js index 1e4b5e986db..cac9dc06284 100644 --- a/app/assets/javascripts/jobs/store/actions.js +++ b/app/assets/javascripts/jobs/store/actions.js @@ -13,6 +13,7 @@ import { scrollDown, scrollUp, } from '~/lib/utils/scroll_utils'; +import httpStatusCodes from '~/lib/utils/http_status'; export const init = ({ dispatch }, { endpoint, logState, pagePath }) => { dispatch('setJobEndpoint', endpoint); @@ -20,8 +21,7 @@ export const init = ({ dispatch }, { endpoint, logState, pagePath }) => { logState, pagePath, }); - - return Promise.all([dispatch('fetchJob'), dispatch('fetchTrace')]); + dispatch('fetchJob'); }; export const setJobEndpoint = ({ commit }, endpoint) => commit(types.SET_JOB_ENDPOINT, endpoint); @@ -39,6 +39,7 @@ export const toggleSidebar = ({ dispatch, state }) => { }; let eTagPoll; +let isTraceReadyForRender; export const clearEtagPoll = () => { eTagPoll = null; @@ -70,7 +71,14 @@ export const fetchJob = ({ state, dispatch }) => { }); if (!Visibility.hidden()) { - eTagPoll.makeRequest(); + // eslint-disable-next-line promise/catch-or-return + eTagPoll.makeRequest().then(() => { + // if a job is canceled we still need to dispatch + // fetchTrace to get the trace so we check for has_trace + if (state.job.started || state.job.has_trace) { + dispatch('fetchTrace'); + } + }); } else { axios .get(state.jobEndpoint) @@ -80,9 +88,15 @@ export const fetchJob = ({ state, dispatch }) => { Visibility.change(() => { if (!Visibility.hidden()) { + // This check is needed to ensure the loading icon + // is not shown for a finished job during a visibility change + if (!isTraceReadyForRender && state.job.started) { + dispatch('startPollingTrace'); + } dispatch('restartPolling'); } else { dispatch('stopPolling'); + dispatch('stopPollingTrace'); } }); }; @@ -163,6 +177,8 @@ export const fetchTrace = ({ dispatch, state }) => params: { state: state.traceState }, }) .then(({ data }) => { + isTraceReadyForRender = data.complete; + dispatch('toggleScrollisInBottom', isScrolledToBottom()); dispatch('receiveTraceSuccess', data); @@ -172,7 +188,11 @@ export const fetchTrace = ({ dispatch, state }) => dispatch('startPollingTrace'); } }) - .catch(() => dispatch('receiveTraceError')); + .catch(e => + e.response.status === httpStatusCodes.FORBIDDEN + ? dispatch('receiveTraceUnauthorizedError') + : dispatch('receiveTraceError'), + ); export const startPollingTrace = ({ dispatch, commit }) => { const traceTimeout = setTimeout(() => { @@ -194,6 +214,10 @@ export const receiveTraceError = ({ dispatch }) => { dispatch('stopPollingTrace'); flash(__('An error occurred while fetching the job log.')); }; +export const receiveTraceUnauthorizedError = ({ dispatch }) => { + dispatch('stopPollingTrace'); + flash(__('The current user is not authorized to access the job log.')); +}; /** * When the user clicks a collapsible line in the job * log, we commit a mutation to update the state @@ -234,7 +258,7 @@ export const receiveJobsForStageError = ({ commit }) => { flash(__('An error occurred while fetching the jobs.')); }; -export const triggerManualJob = ({ state }, variables) => { +export const triggerManualJob = ({ state, dispatch }, variables) => { const parsedVariables = variables.map(variable => { const copyVar = { ...variable }; delete copyVar.id; @@ -245,5 +269,6 @@ export const triggerManualJob = ({ state }, variables) => { .post(state.job.status.action.path, { job_variables_attributes: parsedVariables, }) + .then(() => dispatch('fetchTrace')) .catch(() => flash(__('An error occurred while triggering the job.'))); }; diff --git a/app/assets/javascripts/jobs/store/mutations.js b/app/assets/javascripts/jobs/store/mutations.js index 924b811d0d6..dea53f715a7 100644 --- a/app/assets/javascripts/jobs/store/mutations.js +++ b/app/assets/javascripts/jobs/store/mutations.js @@ -49,6 +49,7 @@ export default { [types.SET_TRACE_TIMEOUT](state, id) { state.traceTimeout = id; + state.isTraceComplete = false; }, /** diff --git a/app/assets/javascripts/jobs/utils.js b/app/assets/javascripts/jobs/utils.js index 28a125b2b8f..122f23a5bb5 100644 --- a/app/assets/javascripts/jobs/utils.js +++ b/app/assets/javascripts/jobs/utils.js @@ -1,4 +1,12 @@ -// capture anything starting with http:// or https:// -// up until a disallowed character or whitespace -export const linkRegex = /(https?:\/\/[^"<>\\^`{|}\s]+)/g; +/** + * capture anything starting with http:// or https:// + * https?:\/\/ + * + * up until a disallowed character or whitespace + * [^"<>\\^`{|}\s]+ + * + * and a disallowed character or whitespace, including non-ending chars .,:;!? + * [^"<>\\^`{|}\s.,:;!?] + */ +export const linkRegex = /(https?:\/\/[^"<>\\^`{|}\s]+[^"<>\\^`{|}\s.,:;!?])/g; export default { linkRegex }; |