diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-12 21:09:09 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-12 21:09:09 +0300 |
commit | dd1c093e289dab5b2142e8e7f02883f2281e7910 (patch) | |
tree | e16d1733ecd3b693c205816102f42b78bd65394b /app | |
parent | d9b3f39acad88d81eb7a75627c4325651fb7ff13 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
18 files changed, 189 insertions, 76 deletions
diff --git a/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue b/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue index 7b169b68d20..1137951ccfc 100644 --- a/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue +++ b/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue @@ -5,14 +5,14 @@ import highlight from '~/lib/utils/highlight'; import { truncateNamespace } from '~/lib/utils/text_utility'; import { mapVuexModuleState } from '~/lib/utils/vuex_module_mappers'; import Tracking from '~/tracking'; -import Identicon from '~/vue_shared/components/identicon.vue'; +import ProjectAvatar from '~/vue_shared/components/project_avatar.vue'; const trackingMixin = Tracking.mixin(); export default { components: { - Identicon, GlButton, + ProjectAvatar, }, mixins: [trackingMixin], inject: ['vuexModule'], @@ -64,19 +64,12 @@ export default { class="gl-text-left gl-justify-content-start!" @click="track('click_link', { label: `${dropdownType}_dropdown_frequent_items_list_item` })" > - <div - ref="frequentItemsItemAvatarContainer" - class="frequent-items-item-avatar-container avatar-container rect-avatar s32" - > - <img v-if="avatarUrl" ref="frequentItemsItemAvatar" :src="avatarUrl" class="avatar s32" /> - <identicon - v-else - :entity-id="itemId" - :entity-name="itemName" - size-class="s32" - class="rect-avatar" - /> - </div> + <project-avatar + class="gl-float-left gl-mr-3" + :project-avatar-url="avatarUrl" + :project-name="itemName" + aria-hidden="true" + /> <div ref="frequentItemsItemMetadataContainer" class="frequent-items-item-metadata-container"> <div ref="frequentItemsItemTitle" diff --git a/app/assets/javascripts/jobs/components/log/collapsible_section.vue b/app/assets/javascripts/jobs/components/log/collapsible_section.vue index 55cdfb691f4..c0d5fac0e8d 100644 --- a/app/assets/javascripts/jobs/components/log/collapsible_section.vue +++ b/app/assets/javascripts/jobs/components/log/collapsible_section.vue @@ -1,4 +1,6 @@ <script> +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF } from '../../constants'; import LogLine from './line.vue'; import LogLineHeader from './line_header.vue'; @@ -7,7 +9,9 @@ export default { components: { LogLine, LogLineHeader, + CollapsibleLogSection: () => import('./collapsible_section.vue'), }, + mixins: [glFeatureFlagsMixin()], props: { section: { type: Object, @@ -22,6 +26,9 @@ export default { badgeDuration() { return this.section.line && this.section.line.section_duration; }, + infinitelyCollapsibleSectionsFlag() { + return this.glFeatures?.[INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF]; + }, }, methods: { handleOnClickCollapsibleLine(section) { @@ -40,12 +47,26 @@ export default { @toggleLine="handleOnClickCollapsibleLine(section)" /> <template v-if="!section.isClosed"> - <log-line - v-for="line in section.lines" - :key="line.offset" - :line="line" - :path="traceEndpoint" - /> + <template v-if="infinitelyCollapsibleSectionsFlag"> + <template v-for="line in section.lines"> + <collapsible-log-section + v-if="line.isHeader" + :key="line.line.offset" + :section="line" + :trace-endpoint="traceEndpoint" + @onClickCollapsibleLine="handleOnClickCollapsibleLine" + /> + <log-line v-else :key="line.offset" :line="line" :path="traceEndpoint" /> + </template> + </template> + <template v-else> + <log-line + v-for="line in section.lines" + :key="line.offset" + :line="line" + :path="traceEndpoint" + /> + </template> </template> </div> </template> diff --git a/app/assets/javascripts/jobs/components/log/line_number.vue b/app/assets/javascripts/jobs/components/log/line_number.vue index 7ca9154d2fe..c8ceac2c7ff 100644 --- a/app/assets/javascripts/jobs/components/log/line_number.vue +++ b/app/assets/javascripts/jobs/components/log/line_number.vue @@ -1,4 +1,6 @@ <script> +import { INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF } from '../../constants'; + export default { functional: true, props: { @@ -14,7 +16,9 @@ export default { render(h, { props }) { const { lineNumber, path } = props; - const parsedLineNumber = lineNumber + 1; + const parsedLineNumber = gon.features?.[INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF] + ? lineNumber + : lineNumber + 1; const lineId = `L${parsedLineNumber}`; const lineHref = `${path}#${lineId}`; diff --git a/app/assets/javascripts/jobs/constants.js b/app/assets/javascripts/jobs/constants.js index 3040d4e2379..97f31eee57c 100644 --- a/app/assets/javascripts/jobs/constants.js +++ b/app/assets/javascripts/jobs/constants.js @@ -24,3 +24,5 @@ export const JOB_RETRY_FORWARD_DEPLOYMENT_MODAL = { }; export const SUCCESS_STATUS = 'SUCCESS'; + +export const INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF = 'infinitelyCollapsibleSections'; diff --git a/app/assets/javascripts/jobs/store/mutations.js b/app/assets/javascripts/jobs/store/mutations.js index 924b811d0d6..4045d8a0c16 100644 --- a/app/assets/javascripts/jobs/store/mutations.js +++ b/app/assets/javascripts/jobs/store/mutations.js @@ -1,6 +1,7 @@ import Vue from 'vue'; +import { INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF } from '../constants'; import * as types from './mutation_types'; -import { logLinesParser, updateIncrementalTrace } from './utils'; +import { logLinesParser, logLinesParserLegacy, updateIncrementalTrace } from './utils'; export default { [types.SET_JOB_ENDPOINT](state, endpoint) { @@ -20,12 +21,26 @@ export default { }, [types.RECEIVE_TRACE_SUCCESS](state, log = {}) { + const infinitelyCollapsibleSectionsFlag = + gon.features?.[INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF]; if (log.state) { state.traceState = log.state; } if (log.append) { - state.trace = log.lines ? updateIncrementalTrace(log.lines, state.trace) : state.trace; + if (infinitelyCollapsibleSectionsFlag) { + if (log.lines) { + const parsedResult = logLinesParser( + log.lines, + state.auxiliaryPartialTraceHelpers, + state.trace, + ); + state.trace = parsedResult.parsedLines; + state.auxiliaryPartialTraceHelpers = parsedResult.auxiliaryPartialTraceHelpers; + } + } else { + state.trace = log.lines ? updateIncrementalTrace(log.lines, state.trace) : state.trace; + } state.traceSize += log.size; } else { @@ -33,7 +48,14 @@ export default { // the trace response will not have a defined // html or size. We keep the old value otherwise these // will be set to `null` - state.trace = log.lines ? logLinesParser(log.lines) : state.trace; + + if (infinitelyCollapsibleSectionsFlag) { + const parsedResult = logLinesParser(log.lines); + state.trace = parsedResult.parsedLines; + state.auxiliaryPartialTraceHelpers = parsedResult.auxiliaryPartialTraceHelpers; + } else { + state.trace = log.lines ? logLinesParserLegacy(log.lines) : state.trace; + } state.traceSize = log.size || state.traceSize; } diff --git a/app/assets/javascripts/jobs/store/state.js b/app/assets/javascripts/jobs/store/state.js index 2fe945b2985..718324c8bad 100644 --- a/app/assets/javascripts/jobs/store/state.js +++ b/app/assets/javascripts/jobs/store/state.js @@ -30,4 +30,7 @@ export default () => ({ selectedStage: '', stages: [], jobs: [], + + // to parse partial logs + auxiliaryPartialTraceHelpers: {}, }); diff --git a/app/assets/javascripts/jobs/store/utils.js b/app/assets/javascripts/jobs/store/utils.js index a0e0a0fb8bd..36391a4d433 100644 --- a/app/assets/javascripts/jobs/store/utils.js +++ b/app/assets/javascripts/jobs/store/utils.js @@ -104,7 +104,7 @@ export const getIncrementalLineNumber = (acc) => { * @param Array accumulator * @returns Array parsed log lines */ -export const logLinesParser = (lines = [], accumulator = []) => +export const logLinesParserLegacy = (lines = [], accumulator = []) => lines.reduce( (acc, line, index) => { const lineNumber = accumulator.length > 0 ? getIncrementalLineNumber(acc) : index; @@ -131,6 +131,77 @@ export const logLinesParser = (lines = [], accumulator = []) => [...accumulator], ); +export const logLinesParser = (lines = [], previousTraceState = {}, prevParsedLines = []) => { + let currentLine = previousTraceState?.prevLineCount ?? 0; + let currentHeader = previousTraceState?.currentHeader; + let isPreviousLineHeader = previousTraceState?.isPreviousLineHeader ?? false; + const parsedLines = prevParsedLines.length > 0 ? prevParsedLines : []; + const sectionsQueue = previousTraceState?.sectionsQueue ?? []; + + for (let i = 0; i < lines.length; i += 1) { + const line = lines[i]; + // First run we can use the current index, later runs we have to retrieve the last number of lines + currentLine = previousTraceState?.prevLineCount ? currentLine + 1 : i + 1; + + if (line.section_header && !isPreviousLineHeader) { + // If there's no previous line header that means we're at the root of the log + + isPreviousLineHeader = true; + parsedLines.push(parseHeaderLine(line, currentLine)); + currentHeader = { index: parsedLines.length - 1 }; + } else if (line.section_header && isPreviousLineHeader) { + // If there's a current section, we can't push to the parsedLines array + sectionsQueue.push(currentHeader); + currentHeader = parseHeaderLine(line, currentLine); // Let's parse the incoming header line + } else if (line.section && !line.section_duration) { + // We're inside a collapsible section and want to parse a standard line + if (currentHeader?.index) { + // If the current section header is only an index, add the line as part of the lines + // array of the current collapsible section + parsedLines[currentHeader.index].lines.push(parseLine(line, currentLine)); + } else { + // Otherwise add it to the innermost collapsible section lines array + currentHeader.lines.push(parseLine(line, currentLine)); + } + } else if (line.section && line.section_duration) { + // NOTE: This marks the end of a section_header + const previousSection = sectionsQueue.pop(); + + // Add the duration to section header + // If at the root, just push the end to the current parsedLine, + // otherwise, push it to the previous sections queue + if (currentHeader?.index) { + parsedLines[currentHeader.index].line.section_duration = line.section_duration; + isPreviousLineHeader = false; + currentHeader = null; + } else { + currentHeader.line.section_duration = line.section_duration; + + if (previousSection && previousSection?.index) { + // Is the previous section on root? + parsedLines[previousSection.index].lines.push(currentHeader); + } else if (previousSection && !previousSection?.index) { + previousSection.lines.push(currentHeader); + } + + currentHeader = previousSection; + } + } else { + parsedLines.push(parseLine(line, currentLine)); + } + } + + return { + parsedLines, + auxiliaryPartialTraceHelpers: { + isPreviousLineHeader, + currentHeader, + sectionsQueue, + prevLineCount: lines.length, + }, + }; +}; + /** * Finds the repeated offset, removes the old one * @@ -177,5 +248,5 @@ export const findOffsetAndRemove = (newLog = [], oldParsed = []) => { export const updateIncrementalTrace = (newLog = [], oldParsed = []) => { const parsedLog = findOffsetAndRemove(newLog, oldParsed); - return logLinesParser(newLog, parsedLog); + return logLinesParserLegacy(newLog, parsedLog); }; diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/create/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/create/index.js index d65be6bc69e..6dd21380bec 100644 --- a/app/assets/javascripts/pages/projects/pipeline_schedules/create/index.js +++ b/app/assets/javascripts/pages/projects/pipeline_schedules/create/index.js @@ -1,3 +1,3 @@ import initForm from '../shared/init_form'; -document.addEventListener('DOMContentLoaded', initForm); +initForm(); diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js index d65be6bc69e..6dd21380bec 100644 --- a/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js +++ b/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js @@ -1,3 +1,3 @@ import initForm from '../shared/init_form'; -document.addEventListener('DOMContentLoaded', initForm); +initForm(); diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js index d65be6bc69e..6dd21380bec 100644 --- a/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js +++ b/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js @@ -1,3 +1,3 @@ import initForm from '../shared/init_form'; -document.addEventListener('DOMContentLoaded', initForm); +initForm(); diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/update/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/update/index.js index d65be6bc69e..6dd21380bec 100644 --- a/app/assets/javascripts/pages/projects/pipeline_schedules/update/index.js +++ b/app/assets/javascripts/pages/projects/pipeline_schedules/update/index.js @@ -1,3 +1,3 @@ import initForm from '../shared/init_form'; -document.addEventListener('DOMContentLoaded', initForm); +initForm(); diff --git a/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue b/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue index 06b6d91a216..e14b3b17fa8 100644 --- a/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue +++ b/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue @@ -1,6 +1,6 @@ <script> import { cloneDeep } from 'lodash'; -import { __, s__ } from '~/locale'; +import { formatNumber, sprintf, __, s__ } from '~/locale'; import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue'; @@ -58,6 +58,10 @@ export default { type: String, required: true, }, + activeRunnersCount: { + type: Number, + required: true, + }, }, data() { // filtered_search_bar_root.vue may mutate the inital @@ -119,6 +123,11 @@ export default { }, ]; }, + activeRunnersMessage() { + return sprintf(__('Runners currently online: %{active_runners_count}'), { + active_runners_count: formatNumber(this.activeRunnersCount), + }); + }, }, methods: { onFilter(filters) { @@ -144,16 +153,20 @@ export default { }; </script> <template> - <filtered-search - v-bind="$attrs" - :namespace="namespace" - recent-searches-storage-key="runners-search" - :sort-options="$options.sortOptions" - :initial-filter-value="initialFilterValue" - :initial-sort-by="initialSortBy" - :tokens="searchTokens" - :search-input-placeholder="__('Search or filter results...')" - @onFilter="onFilter" - @onSort="onSort" - /> + <div> + <filtered-search + v-bind="$attrs" + :namespace="namespace" + recent-searches-storage-key="runners-search" + :sort-options="$options.sortOptions" + :initial-filter-value="initialFilterValue" + :initial-sort-by="initialSortBy" + :tokens="searchTokens" + :search-input-placeholder="__('Search or filter results...')" + data-testid="runners-filtered-search" + @onFilter="onFilter" + @onSort="onSort" + /> + <div class="gl-text-right" data-testid="active-runners-message">{{ activeRunnersMessage }}</div> + </div> </template> diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/runner/components/runner_list.vue index a3efd51cab5..69a1f106ca8 100644 --- a/app/assets/javascripts/runner/components/runner_list.vue +++ b/app/assets/javascripts/runner/components/runner_list.vue @@ -1,7 +1,7 @@ <script> import { GlTable, GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { formatNumber, sprintf, __, s__ } from '~/locale'; +import { formatNumber, __, s__ } from '~/locale'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import { RUNNER_JOB_COUNT_LIMIT } from '../constants'; import RunnerActionsCell from './cells/runner_actions_cell.vue'; @@ -52,17 +52,6 @@ export default { type: Array, required: true, }, - activeRunnersCount: { - type: Number, - required: true, - }, - }, - computed: { - activeRunnersMessage() { - return sprintf(__('Runners currently online: %{active_runners_count}'), { - active_runners_count: formatNumber(this.activeRunnersCount), - }); - }, }, methods: { formatProjectCount(projectCount) { @@ -101,12 +90,12 @@ export default { </script> <template> <div> - <div class="gl-text-right" data-testid="active-runners-message">{{ activeRunnersMessage }}</div> <gl-table :busy="loading" :items="runners" :fields="$options.fields" :tbody-tr-attr="runnerTrAttr" + data-testid="runner-list" stacked="md" fixed > diff --git a/app/assets/javascripts/runner/runner_list/index.js b/app/assets/javascripts/runner/runner_list/index.js index 5eba14a7948..16616f00d1e 100644 --- a/app/assets/javascripts/runner/runner_list/index.js +++ b/app/assets/javascripts/runner/runner_list/index.js @@ -12,7 +12,8 @@ export const initRunnerList = (selector = '#js-runner-list') => { return null; } - // TODO `activeRunnersCount` should be implemented using a GraphQL API. + // TODO `activeRunnersCount` should be implemented using a GraphQL API + // https://gitlab.com/gitlab-org/gitlab/-/issues/333806 const { activeRunnersCount, registrationToken, runnerInstallHelpPage } = el.dataset; const apolloProvider = new VueApollo({ diff --git a/app/assets/javascripts/runner/runner_list/runner_list_app.vue b/app/assets/javascripts/runner/runner_list/runner_list_app.vue index 8977d2a2a3d..8d39243d609 100644 --- a/app/assets/javascripts/runner/runner_list/runner_list_app.vue +++ b/app/assets/javascripts/runner/runner_list/runner_list_app.vue @@ -116,17 +116,17 @@ export default { </div> </div> - <runner-filtered-search-bar v-model="search" namespace="admin_runners" /> + <runner-filtered-search-bar + v-model="search" + namespace="admin_runners" + :active-runners-count="activeRunnersCount" + /> <div v-if="noRunnersFound" class="gl-text-center gl-p-5"> {{ __('No runners found') }} </div> <template v-else> - <runner-list - :runners="runners.items" - :loading="runnersLoading" - :active-runners-count="activeRunnersCount" - /> + <runner-list :runners="runners.items" :loading="runnersLoading" /> <runner-pagination v-model="search.pagination" :page-info="runners.pageInfo" /> </template> </div> diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 20d8d7d9469..144a396ea65 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -933,13 +933,9 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu { } .frequent-items-list-item-container { - .frequent-items-item-avatar-container, - .frequent-items-item-metadata-container { - flex-shrink: 0; - } - .frequent-items-item-metadata-container { display: flex; + flex-shrink: 0; flex-direction: column; justify-content: center; } @@ -951,12 +947,6 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu { white-space: nowrap; } - &:hover { - .frequent-items-item-avatar-container .avatar { - border-color: $gray-50; - } - } - .frequent-items-item-title { font-size: $gl-font-size; font-weight: 400; diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 92442fd4e28..49687a50ff6 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -17,6 +17,10 @@ class Projects::JobsController < Projects::ApplicationController before_action :verify_proxy_request!, only: :proxy_websocket_authorize before_action :push_jobs_table_vue, only: [:index] + before_action do + push_frontend_feature_flag(:infinitely_collapsible_sections, @project, default_enabled: :yaml) + end + layout 'project' feature_category :continuous_integration diff --git a/app/workers/repository_check/single_repository_worker.rb b/app/workers/repository_check/single_repository_worker.rb index a9a8201205e..31d68e65b23 100644 --- a/app/workers/repository_check/single_repository_worker.rb +++ b/app/workers/repository_check/single_repository_worker.rb @@ -46,7 +46,7 @@ module RepositoryCheck true rescue Gitlab::Git::Repository::GitError => e - Gitlab::RepositoryCheckLogger.error(e.message) + Gitlab::RepositoryCheckLogger.error("#{repository.full_path}: #{e.message}") false end |