diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-08 09:09:43 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-08 09:09:43 +0000 |
commit | f5050253469fc0961c02deec0e698ad62bdd9de5 (patch) | |
tree | 30bbd8f8b556fd5b730f0123921138ee1d6bdaa2 /app/assets | |
parent | f6cdec670b9b757fc2225a2c6627ab79765e5b8a (diff) | |
download | gitlab-ce-f5050253469fc0961c02deec0e698ad62bdd9de5.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
18 files changed, 226 insertions, 178 deletions
diff --git a/app/assets/javascripts/ide/components/external_link.vue b/app/assets/javascripts/ide/components/external_link.vue deleted file mode 100644 index 558da9b706e..00000000000 --- a/app/assets/javascripts/ide/components/external_link.vue +++ /dev/null @@ -1,34 +0,0 @@ -<script> -import Icon from '~/vue_shared/components/icon.vue'; - -export default { - components: { - Icon, - }, - props: { - file: { - type: Object, - required: true, - }, - }, - computed: { - showButtons() { - return this.file.permalink; - }, - }, -}; -</script> - -<template> - <div v-if="showButtons" class="pull-right ide-btn-group"> - <a - :href="file.permalink" - :title="s__('IDE|Open in file view')" - target="_blank" - rel="noopener noreferrer" - > - <span class="vertical-align-middle">{{ __('Open in file view') }}</span> - <icon :size="16" name="external-link" class="vertical-align-middle space-right" /> - </a> - </div> -</template> diff --git a/app/assets/javascripts/logs/components/environment_logs.vue b/app/assets/javascripts/logs/components/environment_logs.vue index 70b3af8dc75..487b4f30b5b 100644 --- a/app/assets/javascripts/logs/components/environment_logs.vue +++ b/app/assets/javascripts/logs/components/environment_logs.vue @@ -56,7 +56,6 @@ export default { required: true, }, }, - traceHeight: 600, data() { return { isElasticStackCalloutDismissed: false, @@ -94,6 +93,9 @@ export default { 'showEnvironment', 'fetchEnvironments', 'fetchMoreLogsPrepend', + 'dismissRequestEnvironmentsError', + 'dismissInvalidTimeRangeWarning', + 'dismissRequestLogsError', ]), isCurrentEnvironment(envName) { @@ -115,7 +117,7 @@ export default { }; </script> <template> - <div class="environment-logs-viewer mt-3"> + <div class="environment-logs-viewer d-flex flex-column py-3"> <gl-alert v-if="shouldShowElasticStackCallout" class="mb-3 js-elasticsearch-alert" @@ -132,6 +134,31 @@ export default { </strong> </a> </gl-alert> + <gl-alert + v-if="environments.fetchError" + class="mb-3" + variant="danger" + @dismiss="dismissRequestEnvironmentsError" + > + {{ s__('Metrics|There was an error fetching the environments data, please try again') }} + </gl-alert> + <gl-alert + v-if="timeRange.invalidWarning" + class="mb-3" + variant="warning" + @dismiss="dismissInvalidTimeRangeWarning" + > + {{ s__('Metrics|Invalid time range, please verify.') }} + </gl-alert> + <gl-alert + v-if="logs.fetchError" + class="mb-3" + variant="danger" + @dismiss="dismissRequestLogsError" + > + {{ s__('Environments|There was an error fetching the logs. Please try again.') }} + </gl-alert> + <div class="top-bar d-md-flex border bg-secondary-50 pt-2 pr-1 pb-0 pl-2"> <div class="flex-grow-0"> <gl-dropdown @@ -183,16 +210,15 @@ export default { <gl-infinite-scroll ref="infiniteScroll" - class="log-lines" - :style="{ height: `${$options.traceHeight}px` }" - :max-list-height="$options.traceHeight" + class="log-lines overflow-auto flex-grow-1 min-height-0" :fetched-items="logs.lines.length" @topReached="topReached" @scroll="scroll" > <template #items> <pre - class="build-trace js-log-trace" + ref="logTrace" + class="build-trace" ><code class="bash js-build-output"><div v-if="showLoader" class="build-loader-animation js-build-loader-animation"> <div class="dot"></div> <div class="dot"></div> @@ -205,7 +231,7 @@ export default { ></template> </gl-infinite-scroll> - <div ref="logFooter" class="log-footer py-2 px-3"> + <div ref="logFooter" class="py-2 px-3 text-white bg-secondary-900"> <gl-sprintf :message="s__('Environments|Logs from %{start} to %{end}.')"> <template #start>{{ timeRange.current.start | formatDate }}</template> <template #end>{{ timeRange.current.end | formatDate }}</template> diff --git a/app/assets/javascripts/logs/stores/actions.js b/app/assets/javascripts/logs/stores/actions.js index 1e71b2c7314..be847108a49 100644 --- a/app/assets/javascripts/logs/stores/actions.js +++ b/app/assets/javascripts/logs/stores/actions.js @@ -1,20 +1,10 @@ import { backOff } from '~/lib/utils/common_utils'; import httpStatusCodes from '~/lib/utils/http_status'; import axios from '~/lib/utils/axios_utils'; -import flash from '~/flash'; -import { s__ } from '~/locale'; import { convertToFixedRange } from '~/lib/utils/datetime_range'; import * as types from './mutation_types'; -const flashTimeRangeWarning = () => { - flash(s__('Metrics|Invalid time range, please verify.'), 'warning'); -}; - -const flashLogsError = () => { - flash(s__('Metrics|There was an error fetching the logs, please try again')); -}; - const requestUntilData = (url, params) => backOff((next, stop) => { axios @@ -31,7 +21,7 @@ const requestUntilData = (url, params) => }); }); -const requestLogsUntilData = state => { +const requestLogsUntilData = ({ commit, state }) => { const params = {}; const { logs_api_path } = state.environments.options.find( ({ name }) => name === state.environments.current, @@ -49,7 +39,7 @@ const requestLogsUntilData = state => { params.start_time = start; params.end_time = end; } catch { - flashTimeRangeWarning(); + commit(types.SHOW_TIME_RANGE_INVALID_WARNING); } } if (state.logs.cursor) { @@ -101,26 +91,22 @@ export const fetchEnvironments = ({ commit, dispatch }, environmentsPath) => { }) .catch(() => { commit(types.RECEIVE_ENVIRONMENTS_DATA_ERROR); - flash(s__('Metrics|There was an error fetching the environments data, please try again')); }); }; export const fetchLogs = ({ commit, state }) => { commit(types.REQUEST_LOGS_DATA); - return requestLogsUntilData(state) + return requestLogsUntilData({ commit, state }) .then(({ data }) => { const { pod_name, pods, logs, cursor } = data; commit(types.RECEIVE_LOGS_DATA_SUCCESS, { logs, cursor }); - commit(types.SET_CURRENT_POD_NAME, pod_name); - commit(types.RECEIVE_PODS_DATA_SUCCESS, pods); }) .catch(() => { commit(types.RECEIVE_PODS_DATA_ERROR); commit(types.RECEIVE_LOGS_DATA_ERROR); - flashLogsError(); }); }; @@ -132,16 +118,27 @@ export const fetchMoreLogsPrepend = ({ commit, state }) => { commit(types.REQUEST_LOGS_DATA_PREPEND); - return requestLogsUntilData(state) + return requestLogsUntilData({ commit, state }) .then(({ data }) => { const { logs, cursor } = data; commit(types.RECEIVE_LOGS_DATA_PREPEND_SUCCESS, { logs, cursor }); }) .catch(() => { commit(types.RECEIVE_LOGS_DATA_PREPEND_ERROR); - flashLogsError(); }); }; +export const dismissRequestEnvironmentsError = ({ commit }) => { + commit(types.HIDE_REQUEST_ENVIRONMENTS_ERROR); +}; + +export const dismissRequestLogsError = ({ commit }) => { + commit(types.HIDE_REQUEST_LOGS_ERROR); +}; + +export const dismissInvalidTimeRangeWarning = ({ commit }) => { + commit(types.HIDE_TIME_RANGE_INVALID_WARNING); +}; + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/logs/stores/mutation_types.js b/app/assets/javascripts/logs/stores/mutation_types.js index 7e7771a9df8..c1cc7eca52e 100644 --- a/app/assets/javascripts/logs/stores/mutation_types.js +++ b/app/assets/javascripts/logs/stores/mutation_types.js @@ -1,11 +1,16 @@ export const SET_PROJECT_ENVIRONMENT = 'SET_PROJECT_ENVIRONMENT'; export const SET_SEARCH = 'SET_SEARCH'; + export const SET_TIME_RANGE = 'SET_TIME_RANGE'; +export const SHOW_TIME_RANGE_INVALID_WARNING = 'SHOW_TIME_RANGE_INVALID_WARNING'; +export const HIDE_TIME_RANGE_INVALID_WARNING = 'HIDE_TIME_RANGE_INVALID_WARNING'; + export const SET_CURRENT_POD_NAME = 'SET_CURRENT_POD_NAME'; export const REQUEST_ENVIRONMENTS_DATA = 'REQUEST_ENVIRONMENTS_DATA'; export const RECEIVE_ENVIRONMENTS_DATA_SUCCESS = 'RECEIVE_ENVIRONMENTS_DATA_SUCCESS'; export const RECEIVE_ENVIRONMENTS_DATA_ERROR = 'RECEIVE_ENVIRONMENTS_DATA_ERROR'; +export const HIDE_REQUEST_ENVIRONMENTS_ERROR = 'HIDE_REQUEST_ENVIRONMENTS_ERROR'; export const REQUEST_LOGS_DATA = 'REQUEST_LOGS_DATA'; export const RECEIVE_LOGS_DATA_SUCCESS = 'RECEIVE_LOGS_DATA_SUCCESS'; @@ -13,6 +18,7 @@ export const RECEIVE_LOGS_DATA_ERROR = 'RECEIVE_LOGS_DATA_ERROR'; export const REQUEST_LOGS_DATA_PREPEND = 'REQUEST_LOGS_DATA_PREPEND'; export const RECEIVE_LOGS_DATA_PREPEND_SUCCESS = 'RECEIVE_LOGS_DATA_PREPEND_SUCCESS'; export const RECEIVE_LOGS_DATA_PREPEND_ERROR = 'RECEIVE_LOGS_DATA_PREPEND_ERROR'; +export const HIDE_REQUEST_LOGS_ERROR = 'HIDE_REQUEST_LOGS_ERROR'; export const RECEIVE_PODS_DATA_SUCCESS = 'RECEIVE_PODS_DATA_SUCCESS'; export const RECEIVE_PODS_DATA_ERROR = 'RECEIVE_PODS_DATA_ERROR'; diff --git a/app/assets/javascripts/logs/stores/mutations.js b/app/assets/javascripts/logs/stores/mutations.js index d77c2894a05..5e1c794c3a9 100644 --- a/app/assets/javascripts/logs/stores/mutations.js +++ b/app/assets/javascripts/logs/stores/mutations.js @@ -18,6 +18,12 @@ export default { state.timeRange.selected = timeRange; state.timeRange.current = convertToFixedRange(timeRange); }, + [types.SHOW_TIME_RANGE_INVALID_WARNING](state) { + state.timeRange.invalidWarning = true; + }, + [types.HIDE_TIME_RANGE_INVALID_WARNING](state) { + state.timeRange.invalidWarning = false; + }, // Environments Data [types.SET_PROJECT_ENVIRONMENT](state, environmentName) { @@ -38,6 +44,10 @@ export default { [types.RECEIVE_ENVIRONMENTS_DATA_ERROR](state) { state.environments.options = []; state.environments.isLoading = false; + state.environments.fetchError = true; + }, + [types.HIDE_REQUEST_ENVIRONMENTS_ERROR](state) { + state.environments.fetchError = false; }, // Logs data @@ -63,6 +73,7 @@ export default { [types.RECEIVE_LOGS_DATA_ERROR](state) { state.logs.lines = []; state.logs.isLoading = false; + state.logs.fetchError = true; }, [types.REQUEST_LOGS_DATA_PREPEND](state) { @@ -80,6 +91,10 @@ export default { }, [types.RECEIVE_LOGS_DATA_PREPEND_ERROR](state) { state.logs.isLoading = false; + state.logs.fetchError = true; + }, + [types.HIDE_REQUEST_LOGS_ERROR](state) { + state.logs.fetchError = false; }, // Pods data diff --git a/app/assets/javascripts/logs/stores/state.js b/app/assets/javascripts/logs/stores/state.js index 2c8f47294cc..11185c9ccf1 100644 --- a/app/assets/javascripts/logs/stores/state.js +++ b/app/assets/javascripts/logs/stores/state.js @@ -16,6 +16,8 @@ export default () => ({ selected: defaultTimeRange, // Current time range, must be fixed current: convertToFixedRange(defaultTimeRange), + + invalidWarning: false, }, /** @@ -25,6 +27,7 @@ export default () => ({ options: [], isLoading: false, current: null, + fetchError: false, }, /** @@ -39,6 +42,8 @@ export default () => ({ */ cursor: null, isComplete: false, + + fetchError: false, }, /** diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index 6a836adba01..ef3f4d0e3f6 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -99,7 +99,17 @@ export default { downstreamNode.classList.contains('child-pipeline') ? 15 : 30, ); - this.$emit('onClickTriggered', this.pipeline, pipeline); + /** + * If the expanded trigger is defined and the id is different than the + * pipeline we clicked, then it means we clicked on a sibling downstream link + * and we want to reset the pipeline store. Triggering the reset without + * this condition would mean not allowing downstreams of downstreams to expand + */ + if (this.expandedTriggered?.id !== pipeline.id) { + this.$emit('onResetTriggered', this.pipeline, pipeline); + } + + this.$emit('onClickTriggered', pipeline); }, calculateMarginTop(downstreamNode, pixelDiff) { return `${downstreamNode.offsetTop - downstreamNode.offsetParent.offsetTop - pixelDiff}px`; @@ -136,9 +146,7 @@ export default { :pipeline="expandedTriggeredBy" :is-linked-pipeline="true" :mediator="mediator" - @onClickTriggeredBy=" - (parentPipeline, pipeline) => clickTriggeredByPipeline(parentPipeline, pipeline) - " + @onClickTriggeredBy="clickTriggeredByPipeline" @refreshPipelineGraph="requestRefreshPipelineGraph" /> @@ -148,9 +156,7 @@ export default { :column-title="__('Upstream')" :project-id="pipelineProjectId" graph-position="left" - @linkedPipelineClick=" - linkedPipeline => $emit('onClickTriggeredBy', pipeline, linkedPipeline) - " + @linkedPipelineClick="$emit('onClickTriggeredBy', $event)" /> <ul @@ -197,9 +203,7 @@ export default { :is-linked-pipeline="true" :style="{ 'margin-top': downstreamMarginTop }" :mediator="mediator" - @onClickTriggered=" - (parentPipeline, pipeline) => clickTriggeredPipeline(parentPipeline, pipeline) - " + @onClickTriggered="clickTriggeredPipeline" @refreshPipelineGraph="requestRefreshPipelineGraph" /> </div> diff --git a/app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js b/app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js index 1d9366f26df..f987c8f1dd4 100644 --- a/app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js +++ b/app/assets/javascripts/pipelines/mixins/graph_pipeline_bundle_mixin.js @@ -27,9 +27,9 @@ export default { * @param {String} resetStoreKey Store key for the visible pipeline that will need to be reset * @param {Object} pipeline The clicked pipeline */ - clickPipeline(parentPipeline, pipeline, openMethod, closeMethod) { + clickPipeline(pipeline, openMethod, closeMethod) { if (!pipeline.isExpanded) { - this.mediator.store[openMethod](parentPipeline, pipeline); + this.mediator.store[openMethod](pipeline); this.mediator.store.toggleLoading(pipeline); this.mediator.poll.stop(); @@ -41,21 +41,14 @@ export default { this.mediator.poll.enable({ data: this.mediator.getExpandedParameters() }); } }, - clickTriggeredByPipeline(parentPipeline, pipeline) { - this.clickPipeline( - parentPipeline, - pipeline, - 'openTriggeredByPipeline', - 'closeTriggeredByPipeline', - ); + resetTriggeredPipelines(parentPipeline, pipeline) { + this.mediator.store.resetTriggeredPipelines(parentPipeline, pipeline); }, - clickTriggeredPipeline(parentPipeline, pipeline) { - this.clickPipeline( - parentPipeline, - pipeline, - 'openTriggeredPipeline', - 'closeTriggeredPipeline', - ); + clickTriggeredByPipeline(pipeline) { + this.clickPipeline(pipeline, 'openPipeline', 'closePipeline'); + }, + clickTriggeredPipeline(pipeline) { + this.clickPipeline(pipeline, 'openPipeline', 'closePipeline'); }, requestRefreshPipelineGraph() { // When an action is clicked diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js index c901971be50..d76425c96b7 100644 --- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js +++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js @@ -42,10 +42,10 @@ export default () => { }, on: { refreshPipelineGraph: this.requestRefreshPipelineGraph, - onClickTriggeredBy: (parentPipeline, pipeline) => - this.clickTriggeredByPipeline(parentPipeline, pipeline), - onClickTriggered: (parentPipeline, pipeline) => - this.clickTriggeredPipeline(parentPipeline, pipeline), + onResetTriggered: (parentPipeline, pipeline) => + this.resetTriggeredPipelines(parentPipeline, pipeline), + onClickTriggeredBy: pipeline => this.clickTriggeredByPipeline(pipeline), + onClickTriggered: pipeline => this.clickTriggeredPipeline(pipeline), }, }); }, diff --git a/app/assets/javascripts/pipelines/stores/pipeline_store.js b/app/assets/javascripts/pipelines/stores/pipeline_store.js index 69e3579a3c7..1ef73760e02 100644 --- a/app/assets/javascripts/pipelines/stores/pipeline_store.js +++ b/app/assets/javascripts/pipelines/stores/pipeline_store.js @@ -54,16 +54,24 @@ export default class PipelineStore { */ parseTriggeredByPipelines(oldPipeline = {}, newPipeline) { // keep old value in case it's opened because we're polling - Vue.set(newPipeline, 'isExpanded', oldPipeline.isExpanded || false); // add isLoading property Vue.set(newPipeline, 'isLoading', false); + // Because there can only ever be one `triggered_by` for any given pipeline, + // the API returns an object for the value instead of an Array. However, + // it's easier to deal with an array in the FE so we convert it. if (newPipeline.triggered_by) { if (!Array.isArray(newPipeline.triggered_by)) { Object.assign(newPipeline, { triggered_by: [newPipeline.triggered_by] }); } - this.parseTriggeredByPipelines(oldPipeline, newPipeline.triggered_by[0]); + + if (newPipeline.triggered_by?.length > 0) { + newPipeline.triggered_by.forEach(el => { + const oldTriggeredBy = oldPipeline.triggered_by?.find(element => element.id === el.id); + this.parseTriggeredPipelines(oldTriggeredBy, el); + }); + } } } diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue index a057913fd5a..00ccc49d770 100644 --- a/app/assets/javascripts/repository/components/table/row.vue +++ b/app/assets/javascripts/repository/components/table/row.vue @@ -1,10 +1,16 @@ <script> import { escapeRegExp } from 'lodash'; -import { GlBadge, GlLink, GlSkeletonLoading, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui'; +import { + GlBadge, + GlLink, + GlSkeletonLoading, + GlTooltipDirective, + GlLoadingIcon, + GlIcon, +} from '@gitlab/ui'; import { escapeFileUrl } from '~/lib/utils/url_utility'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; -import Icon from '~/vue_shared/components/icon.vue'; -import { getIconName } from '../../utils/icon'; +import FileIcon from '~/vue_shared/components/file_icon.vue'; import getRefMixin from '../../mixins/get_ref'; import getCommit from '../../queries/getCommit.query.graphql'; @@ -14,8 +20,9 @@ export default { GlLink, GlSkeletonLoading, GlLoadingIcon, + GlIcon, TimeagoTooltip, - Icon, + FileIcon, }, directives: { GlTooltip: GlTooltipDirective, @@ -95,9 +102,6 @@ export default { ? { path: `/-/tree/${escape(this.ref)}/${escapeFileUrl(this.path)}` } : null; }, - iconName() { - return `fa-${getIconName(this.type, this.path)}`; - }, isFolder() { return this.type === 'tree'; }, @@ -123,12 +127,6 @@ export default { <template> <tr class="tree-item"> <td class="tree-item-file-name cursor-default position-relative"> - <gl-loading-icon - v-if="path === loadingPath" - size="sm" - inline - class="d-inline-block align-text-bottom fa-fw" - /> <component :is="linkComponent" ref="link" @@ -140,27 +138,27 @@ export default { class="tree-item-link str-truncated" data-qa-selector="file_name_link" > - <i - v-if="path !== loadingPath" - :aria-label="type" - role="img" - :class="iconName" - class="fa fa-fw mr-1" - ></i - ><span class="position-relative">{{ fullPath }}</span> + <file-icon + :file-name="fullPath" + :folder="isFolder" + :submodule="isSubmodule" + :loading="path === loadingPath" + css-classes="position-relative file-icon" + class="mr-1 position-relative text-secondary" + /><span class="position-relative">{{ fullPath }}</span> </component> <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings --> <gl-badge v-if="lfsOid" variant="default" class="label-lfs ml-1">LFS</gl-badge> <template v-if="isSubmodule"> @ <gl-link :href="submoduleTreeUrl" class="commit-sha">{{ shortSha }}</gl-link> </template> - <icon + <gl-icon v-if="hasLockLabel" v-gl-tooltip :title="commit.lockLabel" name="lock" :size="12" - class="ml-2 vertical-align-middle" + class="ml-1" /> </td> <td class="d-none d-sm-table-cell tree-commit cursor-default"> diff --git a/app/assets/javascripts/vue_shared/components/file_icon.vue b/app/assets/javascripts/vue_shared/components/file_icon.vue index 952ffa1fa0e..b084ebdf774 100644 --- a/app/assets/javascripts/vue_shared/components/file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/file_icon.vue @@ -1,7 +1,6 @@ <script> -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; import getIconForFile from './file_icon/file_icon_map'; -import icon from '../../vue_shared/components/icon.vue'; /* This is a re-usable vue component for rendering a svg sprite icon @@ -17,8 +16,8 @@ import icon from '../../vue_shared/components/icon.vue'; */ export default { components: { - icon, GlLoadingIcon, + GlIcon, }, props: { fileName: { @@ -31,7 +30,11 @@ export default { required: false, default: false, }, - + submodule: { + type: Boolean, + required: false, + default: false, + }, opened: { type: Boolean, required: false, @@ -58,7 +61,7 @@ export default { }, computed: { spriteHref() { - const iconName = getIconForFile(this.fileName) || 'file'; + const iconName = this.submodule ? 'folder-git' : getIconForFile(this.fileName) || 'file'; return `${gon.sprite_file_icons}#${iconName}`; }, folderIconName() { @@ -73,9 +76,12 @@ export default { <template> <span> <svg v-if="!loading && !folder" :class="[iconSizeClass, cssClasses]"> - <use v-bind="{ 'xlink:href': spriteHref }" /> - </svg> - <icon v-if="!loading && folder" :name="folderIconName" :size="size" class="folder-icon" /> - <gl-loading-icon v-if="loading" :inline="true" /> + <use v-bind="{ 'xlink:href': spriteHref }" /></svg + ><gl-icon + v-if="!loading && folder" + :name="folderIconName" + :size="size" + class="folder-icon" + /><gl-loading-icon v-if="loading" :inline="true" /> </span> </template> diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 211e1e30161..320bd4adaaa 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -474,6 +474,9 @@ img.emoji { .mw-70p { max-width: 70%; } .mw-90p { max-width: 90%; } +// By default flex items don't shrink below their minimum content size. +// To change this, these clases set a min-width or min-height +.min-width-0 { min-width: 0; } .min-height-0 { min-height: 0; } .svg-w-100 { diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 76b12b2405f..52da1b9abfc 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -199,8 +199,8 @@ /* * Mixin that handles the container for the job logs (CI/CD and kubernetes pod logs) */ -@mixin build-trace { - background: $black; +@mixin build-trace($background: $black) { + background: $background; color: $gray-darkest; white-space: pre; overflow-x: auto; @@ -243,7 +243,7 @@ /* * Mixin that handles the position of the controls placed on the top bar */ -@mixin build-controllers($control-font-size, $flex-direction, $with-grow, $flex-grow-size, $svg-display: 'block', $svg-top: '2px') { +@mixin build-controllers($control-font-size, $flex-direction, $with-grow, $flex-grow-size, $svg-display: block, $svg-top: 2px) { display: flex; font-size: $control-font-size; justify-content: $flex-direction; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index a3c1d8b1709..65efbabaa4f 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -641,6 +641,14 @@ $issue-boards-breadcrumbs-height-xs: 63px; $issue-board-list-difference-xs: $header-height + $issue-boards-breadcrumbs-height-xs; $issue-board-list-difference-sm: $header-height + $breadcrumb-min-height; $issue-board-list-difference-md: $issue-board-list-difference-sm + $issue-boards-filter-height; +/* + The following heights are used in environment_logs.scss and are used for calculation of the log viewer height. +*/ +$environment-logs-breadcrumbs-height: 63px; +$environment-logs-breadcrumbs-height-md: $breadcrumb-min-height; + +$environment-logs-difference-xs-up: $header-height + $environment-logs-breadcrumbs-height; +$environment-logs-difference-md-up: $header-height + $environment-logs-breadcrumbs-height-md; /* * Avatar diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index f8b8a7271ce..f50d4bc736e 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -356,54 +356,3 @@ } } } - -.environment-logs-viewer { - .build-trace-container { - position: relative; - } - - .log-lines, - .gl-infinite-scroll-container { - // makes scrollbar visible by creating contrast - background: $black; - } - - .gl-infinite-scroll-legend { - margin: 0; - } - - .build-trace { - @include build-trace(); - margin: 0; - } - - .top-bar { - .date-time-picker-wrapper, - .dropdown-toggle { - @include media-breakpoint-up(md) { - width: 140px; - } - - @include media-breakpoint-up(lg) { - width: 160px; - } - } - - .controllers { - @include build-controllers(16px, flex-end, false, 2); - } - } - - .btn-refresh svg { - top: 0; - } - - .build-loader-animation { - @include build-loader-animation; - } - - .log-footer { - color: $white-normal; - background-color: $gray-900; - } -} diff --git a/app/assets/stylesheets/pages/environment_logs.scss b/app/assets/stylesheets/pages/environment_logs.scss new file mode 100644 index 00000000000..81cec14062f --- /dev/null +++ b/app/assets/stylesheets/pages/environment_logs.scss @@ -0,0 +1,58 @@ +.environment-logs-page { + .content-wrapper { + padding-bottom: 0; + } +} + +.environment-logs-viewer { + height: calc(100vh - #{$environment-logs-difference-xs-up}); + min-height: 700px; + + @include media-breakpoint-up(md) { + height: calc(100vh - #{$environment-logs-difference-md-up}); + } + + .with-performance-bar & { + height: calc(100vh - #{$environment-logs-difference-xs-up} - #{$performance-bar-height}); + + @include media-breakpoint-up(md) { + height: calc(100vh - #{$environment-logs-difference-md-up} - #{$performance-bar-height}); + } + } + + .top-bar { + .date-time-picker-wrapper, + .dropdown-toggle { + @include media-breakpoint-up(md) { + width: 140px; + } + + @include media-breakpoint-up(lg) { + width: 160px; + } + } + + .controllers { + @include build-controllers(16px, flex-end, false, 2, inline); + } + } + + .log-lines, + .gl-infinite-scroll-container { + // makes scrollbar visible by creating contrast + background: $black; + height: 100%; + } + + .build-trace { + @include build-trace($black); + } + + .gl-infinite-scroll-legend { + margin: 0; + } + + .build-loader-animation { + @include build-loader-animation; + } +} diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index a03101c66ac..142078588df 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -138,6 +138,12 @@ } .tree-item { + .file-icon, + .folder-icon { + position: relative; + top: 2px; + } + .link-container { padding: 0; |