diff --git a/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue b/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue similarity index 89% rename from app/assets/javascripts/ci/job_details/components/job_log_controllers.vue rename to app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue index 837efa154e2f1f0dacef134fb8c874608de393ca..f65a46dcc70853e3306308fb1bc2fca51e6fc955 100644 --- a/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue +++ b/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue @@ -2,7 +2,7 @@ import { GlTooltipDirective, GlLink, GlButton, GlSearchBoxByClick } from '@gitlab/ui'; import { scrollToElement, backOff } from '~/lib/utils/common_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils'; -import { __, s__, sprintf } from '~/locale'; +import { s__, sprintf } from '~/locale'; import { compactJobLog } from '~/ci/job_details/utils'; import HelpPopover from '~/vue_shared/components/help_popover.vue'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -89,7 +89,7 @@ export default { }, computed: { jobLogSize() { - return sprintf(__('Showing last %{size} of log -'), { + return sprintf(s__('Job|Showing last %{size} of log.'), { size: numberToHumanSize(this.size), }); }, @@ -185,31 +185,22 @@ export default { }; </script> <template> - <div class="top-bar gl-display-flex gl-justify-content-space-between"> - <slot name="drawers"></slot> - <!-- truncate information --> - <div - class="truncated-info gl-display-none gl-sm-display-flex gl-flex-wrap gl-align-items-center" - data-testid="log-truncated-info" - > + <div class="top-bar gl-display-flex gl-align-items-center gl-justify-content-space-between"> + <!-- truncated log information --> + <div class="gl-display-none gl-sm-display-block gl-text-truncate" data-testid="showing-last"> <template v-if="isJobLogSizeVisible"> {{ jobLogSize }} - <gl-link - v-if="rawPath" - :href="rawPath" - class="text-plain text-underline gl-ml-2" - data-testid="raw-link" - >{{ s__('Job|Complete Raw') }}</gl-link - > + <gl-link v-if="rawPath" :href="rawPath">{{ s__('Job|View raw') }}</gl-link> </template> </div> - <!-- eo truncate information --> + <!-- eo truncated log information --> <div class="controllers"> <slot name="controllers"> </slot> + <gl-search-box-by-click v-model="searchTerm" - class="gl-mr-3" + class="gl-mr-3 gl-flex-nowrap" :placeholder="$options.i18n.searchPlaceholder" data-testid="job-log-search-box" @clear="$emit('searchResults', [])" @@ -243,7 +234,7 @@ export default { :aria-label="$options.i18n.scrollToNextFailureButtonLabel" :disabled="shouldDisableJumpToFailures" class="btn-scroll gl-ml-3" - data-testid="job-controller-scroll-to-failure" + data-testid="job-top-bar-scroll-to-failure" icon="soft-wrap" @click="handleScrollToNextFailure" /> @@ -252,7 +243,7 @@ export default { <gl-button :disabled="isScrollTopDisabled" class="btn-scroll" - data-testid="job-controller-scroll-top" + data-testid="job-top-bar-scroll-top" icon="scroll_up" :aria-label="$options.i18n.scrollToTopButtonLabel" @click="handleScrollToTop" @@ -263,7 +254,7 @@ export default { <gl-button :disabled="isScrollBottomDisabled" class="js-scroll-bottom btn-scroll" - data-testid="job-controller-scroll-bottom" + data-testid="job-top-bar-scroll-bottom" icon="scroll_down" :class="{ animate: isScrollingDown }" :aria-label="$options.i18n.scrollToBottomButtonLabel" @@ -279,7 +270,7 @@ export default { :title="$options.i18n.enterFullscreen" :aria-label="$options.i18n.enterFullscreen" class="btn-scroll gl-ml-3" - data-testid="job-controller-enter-fullscreen" + data-testid="job-top-bar-enter-fullscreen" icon="maximize" @click="handleFullscreenMode" /> @@ -290,7 +281,7 @@ export default { :title="$options.i18n.exitFullScreen" :aria-label="$options.i18n.exitFullScreen" class="btn-scroll gl-ml-3" - data-testid="job-controller-exit-fullscreen" + data-testid="job-top-bar-exit-fullscreen" icon="minimize" @click="handleExitFullscreenMode" /> diff --git a/app/assets/javascripts/ci/job_details/job_app.vue b/app/assets/javascripts/ci/job_details/job_app.vue index c2394aa4facc2e125fc5cb250a5a4bf8d5614731..99446029cef2c7433ba92b483842d5a4826a517b 100644 --- a/app/assets/javascripts/ci/job_details/job_app.vue +++ b/app/assets/javascripts/ci/job_details/job_app.vue @@ -4,7 +4,7 @@ import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils'; import { throttle, isEmpty } from 'lodash'; // eslint-disable-next-line no-restricted-imports import { mapGetters, mapState, mapActions } from 'vuex'; -import LogTopBar from 'ee_else_ce/ci/job_details/components/job_log_controllers.vue'; +import JobLogTopBar from 'ee_else_ce/ci/job_details/components/job_log_top_bar.vue'; import SafeHtml from '~/vue_shared/directives/safe_html'; import { isScrolledToBottom } from '~/lib/utils/scroll_utils'; import { __, sprintf } from '~/locale'; @@ -28,7 +28,7 @@ export default { ErasedBlock, GlIcon, Log, - LogTopBar, + JobLogTopBar, StuckBlock, UnmetPrerequisitesBlock, Sidebar, @@ -284,7 +284,7 @@ export default { </div> <!-- job log --> <div v-if="hasJobLog && !showUpdateVariablesState" class="build-log-container gl-relative"> - <log-top-bar + <job-log-top-bar :class="{ 'has-archived-block': job.archived, }" diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 7f093f062ab04ce7fd2f022e6e53b33beb6089a3..4e18c0aa785c9e28623f7fc411d91d730446f78d 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -251,10 +251,13 @@ padding: $grid-size; } -@mixin build-log-top-bar($height) { - @include build-log-bar($height); +@mixin job-log-top-bar { + @include build-log-bar(50px); + z-index: 2; position: sticky; top: calc(#{$calc-application-header-height} - 1px); + border-radius: $border-radius-default $border-radius-default 0 0; + box-shadow: 0 -4px 0 0 var(--white); } /* diff --git a/app/assets/stylesheets/page_bundles/build.scss b/app/assets/stylesheets/page_bundles/build.scss index 80f93f08e90aac14716a0010c408dad1ae77bbef..f077e8ca09021d53a71c782001f1c9a70a434ae9 100644 --- a/app/assets/stylesheets/page_bundles/build.scss +++ b/app/assets/stylesheets/page_bundles/build.scss @@ -14,10 +14,7 @@ } .top-bar { - @include build-log-top-bar(50px); - z-index: 2; - border-radius: $border-radius-default $border-radius-default 0 0; - box-shadow: 0 -4px 0 0 var(--white); + @include job-log-top-bar; &.has-archived-block { top: calc(#{$calc-application-header-height} + 28px); diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 8f52422b4b8edda80e90ed404cb0864a1f309f6b..bb81d6e292150dacb0c33fbb70ab2d1bde8fd05d 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -74,14 +74,3 @@ color: $gl-text-color; } } - -@include media-breakpoint-down(sm) { - .top-bar { - .truncated-info { - white-space: nowrap; - overflow: hidden; - max-width: 220px; - text-overflow: ellipsis; - } - } -} diff --git a/ee/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue b/ee/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue similarity index 95% rename from ee/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue rename to ee/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue index 375a5810564d3fe4795cea97924126c66a3a9687..7f3eb96aef67e6554133d8e88c84f8fff2785b10 100644 --- a/ee/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue +++ b/ee/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue @@ -6,12 +6,12 @@ import { s__ } from '~/locale'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { TYPENAME_CI_BUILD } from '~/graphql_shared/constants'; -import JobLogController from '~/ci/job_details/components/job_log_controllers.vue'; +import CeJobLogTopBar from '~/ci/job_details/components/job_log_top_bar.vue'; import RootCauseAnalysis from './sidebar/root_cause_analysis/root_cause_analysis_app.vue'; export default { components: { - JobLogController, + CeJobLogTopBar, GlButton, RootCauseAnalysis, }, @@ -110,7 +110,7 @@ export default { :is-job-loading="isLoading" @close="toggleDrawer" /> - <job-log-controller + <ce-job-log-top-bar :size="size" :raw-path="rawPath" :is-scroll-top-disabled="isScrollTopDisabled" @@ -132,6 +132,6 @@ export default { $options.i18n.buttonName }}</gl-button> </template> - </job-log-controller> + </ce-job-log-top-bar> </div> </template> diff --git a/ee/spec/frontend/ci/job_details/components/sidebar/job_log_controllers_spec.js b/ee/spec/frontend/ci/job_details/components/sidebar/job_log_top_bar_spec.js similarity index 71% rename from ee/spec/frontend/ci/job_details/components/sidebar/job_log_controllers_spec.js rename to ee/spec/frontend/ci/job_details/components/sidebar/job_log_top_bar_spec.js index 1418f4e112d149a23d0a68457c39c4ca7d24910d..a6aac74a5a5c61cc62dbe2bfdd7105e26aafbc77 100644 --- a/ee/spec/frontend/ci/job_details/components/sidebar/job_log_controllers_spec.js +++ b/ee/spec/frontend/ci/job_details/components/sidebar/job_log_top_bar_spec.js @@ -1,9 +1,9 @@ import { mount } from '@vue/test-utils'; -import EEJobLogControllers from 'ee/ci/job_details/components/job_log_controllers.vue'; -import JobLogControllers from '~/ci/job_details/components/job_log_controllers.vue'; +import EEJobLogTopBar from 'ee/ci/job_details/components/job_log_top_bar.vue'; +import CeJobLogTopBar from '~/ci/job_details/components/job_log_top_bar.vue'; import { mockJobLog } from '../../mock_data'; -describe('EE JobLogController', () => { +describe('EE JobLogTopBar', () => { let wrapper; const defaultProps = { @@ -18,7 +18,7 @@ describe('EE JobLogController', () => { }; const createComponent = (props) => { - wrapper = mount(EEJobLogControllers, { + wrapper = mount(EEJobLogTopBar, { propsData: { ...defaultProps, ...props, @@ -29,7 +29,7 @@ describe('EE JobLogController', () => { }); }; - const findJobLogController = () => wrapper.findComponent(JobLogControllers); + const findJobLogTopBar = () => wrapper.findComponent(CeJobLogTopBar); describe('when the underlying event is triggered', () => { beforeEach(() => { @@ -42,7 +42,7 @@ describe('EE JobLogController', () => { ${'scrollJobLogBottom'} | ${undefined} ${'searchResults'} | ${'searchResults'} `('should re-trigger events', ({ eventName, parameter }) => { - findJobLogController().vm.$emit(eventName, parameter); + findJobLogTopBar().vm.$emit(eventName, parameter); expect(wrapper.emitted(eventName)[0][0]).toBe(parameter); }); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 1e9facaa8a9558690511d438fb7e8038a885131f..d4f34842302ab23ac4738d600baa64666bba5a47 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -29142,9 +29142,6 @@ msgstr "" msgid "Job|Canceled" msgstr "" -msgid "Job|Complete Raw" -msgstr "" - msgid "Job|Created" msgstr "" @@ -29247,6 +29244,9 @@ msgstr "" msgid "Job|Show full screen" msgstr "" +msgid "Job|Showing last %{size} of log." +msgstr "" + msgid "Job|Skipped" msgstr "" @@ -29280,6 +29280,9 @@ msgstr "" msgid "Job|Update CI/CD variables" msgstr "" +msgid "Job|View raw" +msgstr "" + msgid "Job|Waiting for resource" msgstr "" @@ -48271,9 +48274,6 @@ msgstr "" msgid "Showing first 50 actions." msgstr "" -msgid "Showing last %{size} of log -" -msgstr "" - msgid "Showing latest version" msgstr "" diff --git a/spec/frontend/ci/job_details/components/job_log_controllers_spec.js b/spec/frontend/ci/job_details/components/job_log_top_bar_spec.js similarity index 91% rename from spec/frontend/ci/job_details/components/job_log_controllers_spec.js rename to spec/frontend/ci/job_details/components/job_log_top_bar_spec.js index 078ad4aee34b000f8dbc34065fd9a06002cf64fc..252af6ef27b8abd218680c47cffc5a39e3ddeed3 100644 --- a/spec/frontend/ci/job_details/components/job_log_controllers_spec.js +++ b/spec/frontend/ci/job_details/components/job_log_top_bar_spec.js @@ -1,6 +1,6 @@ -import { GlSearchBoxByClick } from '@gitlab/ui'; +import { GlLink, GlSearchBoxByClick } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; -import JobLogControllers from '~/ci/job_details/components/job_log_controllers.vue'; +import JobLogTopBar from '~/ci/job_details/components/job_log_top_bar.vue'; import HelpPopover from '~/vue_shared/components/help_popover.vue'; import { backoffMockImplementation } from 'helpers/backoff_helper'; import * as commonUtils from '~/lib/utils/common_utils'; @@ -8,7 +8,7 @@ import { mockJobLog } from 'jest/ci/jobs_mock_data'; const mockToastShow = jest.fn(); -describe('Job log controllers', () => { +describe('JobLogTopBar', () => { let wrapper; beforeEach(() => { @@ -31,7 +31,7 @@ describe('Job log controllers', () => { }; const createWrapper = (props) => { - wrapper = mount(JobLogControllers, { + wrapper = mount(JobLogTopBar, { propsData: { ...defaultProps, ...props, @@ -49,18 +49,18 @@ describe('Job log controllers', () => { }); }; - const findTruncatedInfo = () => wrapper.find('[data-testid="log-truncated-info"]'); - const findRawLink = () => wrapper.find('[data-testid="raw-link"]'); + const findShowingLast = () => wrapper.find('[data-testid="showing-last"]'); + const findShowingLastLinks = () => findShowingLast().findAllComponents(GlLink); const findRawLinkController = () => wrapper.find('[data-testid="job-raw-link-controller"]'); - const findScrollTop = () => wrapper.find('[data-testid="job-controller-scroll-top"]'); - const findScrollBottom = () => wrapper.find('[data-testid="job-controller-scroll-bottom"]'); + const findScrollTop = () => wrapper.find('[data-testid="job-top-bar-scroll-top"]'); + const findScrollBottom = () => wrapper.find('[data-testid="job-top-bar-scroll-bottom"]'); const findJobLogSearch = () => wrapper.findComponent(GlSearchBoxByClick); const findSearchHelp = () => wrapper.findComponent(HelpPopover); - const findScrollFailure = () => wrapper.find('[data-testid="job-controller-scroll-to-failure"]'); + const findScrollFailure = () => wrapper.find('[data-testid="job-top-bar-scroll-to-failure"]'); const findShowFullScreenButton = () => - wrapper.find('[data-testid="job-controller-enter-fullscreen"]'); + wrapper.find('[data-testid="job-top-bar-enter-fullscreen"]'); const findExitFullScreenButton = () => - wrapper.find('[data-testid="job-controller-exit-fullscreen"]'); + wrapper.find('[data-testid="job-top-bar-exit-fullscreen"]'); describe('Truncate information', () => { describe('with isJobLogSizeVisible', () => { @@ -69,11 +69,12 @@ describe('Job log controllers', () => { }); it('renders size information', () => { - expect(findTruncatedInfo().text()).toMatch('499.95 KiB'); + expect(findShowingLast().text()).toMatch('Showing last 499.95 KiB of log.'); }); - it('renders link to raw job log', () => { - expect(findRawLink().attributes('href')).toBe(defaultProps.rawPath); + it('renders link', () => { + expect(findShowingLastLinks()).toHaveLength(1); + expect(findShowingLastLinks().at(0).attributes('href')).toBe('/raw'); }); }); }); diff --git a/spec/frontend/ci/job_details/job_app_spec.js b/spec/frontend/ci/job_details/job_app_spec.js index 8601850a403bcbb8a281988e4913fec77ba1b151..dea8fd1e4ebf1c0c20a220f154a6df2378cb2027 100644 --- a/spec/frontend/ci/job_details/job_app_spec.js +++ b/spec/frontend/ci/job_details/job_app_spec.js @@ -9,7 +9,7 @@ import EnvironmentsBlock from '~/ci/job_details/components/environments_block.vu import ErasedBlock from '~/ci/job_details/components/erased_block.vue'; import JobApp from '~/ci/job_details/job_app.vue'; import JobLog from '~/ci/job_details/components/log/log.vue'; -import JobLogTopBar from 'ee_else_ce/ci/job_details/components/job_log_controllers.vue'; +import JobLogTopBar from 'ee_else_ce/ci/job_details/components/job_log_top_bar.vue'; import Sidebar from '~/ci/job_details/components/sidebar/sidebar.vue'; import StuckBlock from '~/ci/job_details/components/stuck_block.vue'; import UnmetPrerequisitesBlock from '~/ci/job_details/components/unmet_prerequisites_block.vue';