Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/ci/job_details/components/job_log_controllers.vue45
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/log.vue4
-rw-r--r--app/assets/javascripts/ci/job_details/index.js9
-rw-r--r--app/assets/javascripts/ci/job_details/job_app.vue8
-rw-r--r--app/assets/javascripts/ci/job_details/store/actions.js74
-rw-r--r--app/assets/javascripts/ci/job_details/store/getters.js3
-rw-r--r--app/assets/javascripts/ci/job_details/store/mutation_types.js5
-rw-r--r--app/assets/javascripts/ci/job_details/store/mutations.js13
-rw-r--r--app/assets/javascripts/ci/job_details/store/state.js6
-rw-r--r--app/assets/stylesheets/page_bundles/build.scss8
10 files changed, 171 insertions, 4 deletions
diff --git a/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue b/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue
index a22ed8f599b..837efa154e2 100644
--- a/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue
+++ b/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue
@@ -20,6 +20,9 @@ export default {
'Job|Search for substrings in your job log output. Currently search is only supported for the visible job log output, not for any log output that is truncated due to size.',
),
logLineNumberNotFound: s__('Job|We could not find this element'),
+ enterFullscreen: s__('Job|Show full screen'),
+ exitFullScreen: s__('Job|Exit full screen'),
+ fullScreenNotAvailable: s__('Job|Full screen mode is not available'),
},
components: {
GlLink,
@@ -65,6 +68,16 @@ export default {
type: Array,
required: true,
},
+ fullScreenModeAvailable: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ fullScreenEnabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -86,6 +99,9 @@ export default {
shouldDisableJumpToFailures() {
return !this.hasFailures;
},
+ fullScreenTooltipContent() {
+ return this.fullScreenModeAvailable ? '' : this.$options.i18n.fullScreenNotAvailable;
+ },
},
mounted() {
this.checkFailureCount();
@@ -121,6 +137,12 @@ export default {
this.$emit('scrollJobLogBottom');
this.failureIndex = 0;
},
+ handleFullscreenMode() {
+ this.$emit('enterFullscreen');
+ },
+ handleExitFullscreenMode() {
+ this.$emit('exitFullscreen');
+ },
searchJobLog() {
this.searchResults = [];
@@ -249,6 +271,29 @@ export default {
/>
</div>
<!-- eo scroll buttons -->
+
+ <div v-gl-tooltip="fullScreenTooltipContent">
+ <gl-button
+ v-if="!fullScreenEnabled"
+ :disabled="!fullScreenModeAvailable"
+ :title="$options.i18n.enterFullscreen"
+ :aria-label="$options.i18n.enterFullscreen"
+ class="btn-scroll gl-ml-3"
+ data-testid="job-controller-enter-fullscreen"
+ icon="maximize"
+ @click="handleFullscreenMode"
+ />
+ </div>
+
+ <gl-button
+ v-if="fullScreenEnabled"
+ :title="$options.i18n.exitFullScreen"
+ :aria-label="$options.i18n.exitFullScreen"
+ class="btn-scroll gl-ml-3"
+ data-testid="job-controller-exit-fullscreen"
+ icon="minimize"
+ @click="handleExitFullscreenMode"
+ />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/ci/job_details/components/log/log.vue b/app/assets/javascripts/ci/job_details/components/log/log.vue
index 8b43739d7ef..8ca9515996c 100644
--- a/app/assets/javascripts/ci/job_details/components/log/log.vue
+++ b/app/assets/javascripts/ci/job_details/components/log/log.vue
@@ -40,9 +40,11 @@ export default {
}
});
}
+
+ this.setupFullScreenListeners();
},
methods: {
- ...mapActions(['toggleCollapsibleLine', 'scrollBottom']),
+ ...mapActions(['toggleCollapsibleLine', 'scrollBottom', 'setupFullScreenListeners']),
handleOnClickCollapsibleLine(section) {
this.toggleCollapsibleLine(section);
},
diff --git a/app/assets/javascripts/ci/job_details/index.js b/app/assets/javascripts/ci/job_details/index.js
index 7748b6e83ef..9aa01c4686e 100644
--- a/app/assets/javascripts/ci/job_details/index.js
+++ b/app/assets/javascripts/ci/job_details/index.js
@@ -34,9 +34,16 @@ export const initJobDetails = () => {
pipelineTestReportUrl,
} = el.dataset;
+ const fullScreenAPIAvailable = document.fullscreenEnabled;
+
// init store to start fetching log
const store = createStore();
- store.dispatch('init', { jobEndpoint, logEndpoint, testReportSummaryUrl });
+ store.dispatch('init', {
+ jobEndpoint,
+ logEndpoint,
+ testReportSummaryUrl,
+ fullScreenAPIAvailable,
+ });
return new Vue({
el,
diff --git a/app/assets/javascripts/ci/job_details/job_app.vue b/app/assets/javascripts/ci/job_details/job_app.vue
index 491cd1d35b9..c2394aa4fac 100644
--- a/app/assets/javascripts/ci/job_details/job_app.vue
+++ b/app/assets/javascripts/ci/job_details/job_app.vue
@@ -81,6 +81,7 @@ export default {
'isScrollTopDisabled',
'hasError',
'selectedStage',
+ 'fullScreenEnabled',
]),
...mapGetters([
'headerTime',
@@ -94,6 +95,7 @@ export default {
'isScrollingDown',
'emptyStateAction',
'hasOfflineRunnersForProject',
+ 'fullScreenAPIAndContainerAvailable',
]),
shouldRenderContent() {
@@ -172,6 +174,8 @@ export default {
'stopPolling',
'toggleScrollButtons',
'toggleScrollAnimation',
+ 'enterFullscreen',
+ 'exitFullscreen',
]),
onHideManualVariablesForm() {
this.showUpdateVariablesState = false;
@@ -292,9 +296,13 @@ export default {
:is-scrolling-down="isScrollingDown"
:is-complete="isJobLogComplete"
:job-log="jobLog"
+ :full-screen-mode-available="fullScreenAPIAndContainerAvailable"
+ :full-screen-enabled="fullScreenEnabled"
@scrollJobLogTop="scrollTop"
@scrollJobLogBottom="scrollBottom"
@searchResults="setSearchResults"
+ @enterFullscreen="enterFullscreen"
+ @exitFullscreen="exitFullscreen"
/>
<log :search-results="searchResults" />
</div>
diff --git a/app/assets/javascripts/ci/job_details/store/actions.js b/app/assets/javascripts/ci/job_details/store/actions.js
index 03323e51583..e1225ecd2c9 100644
--- a/app/assets/javascripts/ci/job_details/store/actions.js
+++ b/app/assets/javascripts/ci/job_details/store/actions.js
@@ -15,8 +15,16 @@ import { __ } from '~/locale';
import { reportToSentry } from '~/ci/utils';
import * as types from './mutation_types';
-export const init = ({ commit, dispatch }, { jobEndpoint, logEndpoint, testReportSummaryUrl }) => {
- commit(types.SET_JOB_LOG_OPTIONS, { jobEndpoint, logEndpoint, testReportSummaryUrl });
+export const init = (
+ { commit, dispatch },
+ { jobEndpoint, logEndpoint, testReportSummaryUrl, fullScreenAPIAvailable = false },
+) => {
+ commit(types.SET_JOB_LOG_OPTIONS, {
+ jobEndpoint,
+ logEndpoint,
+ testReportSummaryUrl,
+ fullScreenAPIAvailable,
+ });
return dispatch('fetchJob');
};
@@ -24,6 +32,68 @@ export const init = ({ commit, dispatch }, { jobEndpoint, logEndpoint, testRepor
export const hideSidebar = ({ commit }) => commit(types.HIDE_SIDEBAR);
export const showSidebar = ({ commit }) => commit(types.SHOW_SIDEBAR);
+export const enterFullscreen = ({ dispatch }) => {
+ const el = document.querySelector('.build-log-container');
+
+ if (!document.fullscreenElement && el) {
+ el.requestFullscreen()
+ .then(() => {
+ dispatch('enterFullscreenSuccess');
+ })
+ .catch((err) => {
+ reportToSentry('job_enter_fullscreen_mode', err);
+ });
+ }
+};
+
+export const enterFullscreenSuccess = ({ commit }) => {
+ commit(types.ENTER_FULLSCREEN_SUCCESS);
+};
+
+export const exitFullscreen = ({ dispatch }) => {
+ if (document.fullscreenElement) {
+ document
+ .exitFullscreen()
+ .then(() => {
+ dispatch('exitFullscreenSuccess');
+ })
+ .catch((err) => {
+ reportToSentry('job_exit_fullscreen_mode', err);
+ });
+ }
+};
+
+export const exitFullscreenSuccess = ({ commit }) => {
+ commit(types.EXIT_FULLSCREEN_SUCCESS);
+};
+
+export const fullScreenContainerSetUpResult = ({ commit }, value) => {
+ commit(types.FULL_SCREEN_CONTAINER_SET_UP, value);
+};
+
+export const fullScreenModeAvailableSuccess = ({ commit }) => {
+ commit(types.FULL_SCREEN_MODE_AVAILABLE_SUCCESS);
+};
+
+export const setupFullScreenListeners = ({ dispatch, state, getters }) => {
+ if (!state.fullScreenContainerSetUp && getters.hasJobLog) {
+ const el = document.querySelector('.build-log-container');
+
+ if (el) {
+ dispatch('fullScreenModeAvailableSuccess');
+
+ el.addEventListener('fullscreenchange', () => {
+ if (!document.fullscreenElement) {
+ // Leaving fullscreen mode
+ dispatch('exitFullscreenSuccess');
+ }
+ });
+
+ dispatch('fullScreenContainerSetUpResult', true);
+ }
+ }
+};
+
export const toggleSidebar = ({ dispatch, state }) => {
if (state.isSidebarOpen) {
dispatch('hideSidebar');
diff --git a/app/assets/javascripts/ci/job_details/store/getters.js b/app/assets/javascripts/ci/job_details/store/getters.js
index a0f9db7409d..db967da87fb 100644
--- a/app/assets/javascripts/ci/job_details/store/getters.js
+++ b/app/assets/javascripts/ci/job_details/store/getters.js
@@ -48,3 +48,6 @@ export const isScrollingDown = (state) => isScrolledToBottom() && !state.isJobLo
export const hasOfflineRunnersForProject = (state) =>
state?.job?.runners?.available && !state?.job?.runners?.online;
+
+export const fullScreenAPIAndContainerAvailable = (state) =>
+ state.fullScreenAPIAvailable && state.fullScreenModeAvailable;
diff --git a/app/assets/javascripts/ci/job_details/store/mutation_types.js b/app/assets/javascripts/ci/job_details/store/mutation_types.js
index 1feb35c51d8..382bee9059f 100644
--- a/app/assets/javascripts/ci/job_details/store/mutation_types.js
+++ b/app/assets/javascripts/ci/job_details/store/mutation_types.js
@@ -29,3 +29,8 @@ export const RECEIVE_JOBS_FOR_STAGE_ERROR = 'RECEIVE_JOBS_FOR_STAGE_ERROR';
export const RECEIVE_TEST_SUMMARY_SUCCESS = 'RECEIVE_TEST_SUMMARY_SUCCESS';
export const RECEIVE_TEST_SUMMARY_COMPLETE = 'RECEIVE_TEST_SUMMARY_COMPLETE';
+
+export const ENTER_FULLSCREEN_SUCCESS = 'ENTER_FULLSCREEN_SUCCESS';
+export const EXIT_FULLSCREEN_SUCCESS = 'EXIT_FULLSCREEN_SUCCESS';
+export const FULL_SCREEN_CONTAINER_SET_UP = 'FULL_SCREEN_CONTAINER_SET_UP';
+export const FULL_SCREEN_MODE_AVAILABLE_SUCCESS = 'FULL_SCREEN_MODE_AVAILABLE_SUCCESS';
diff --git a/app/assets/javascripts/ci/job_details/store/mutations.js b/app/assets/javascripts/ci/job_details/store/mutations.js
index e8e65d690d8..866ce48ce9f 100644
--- a/app/assets/javascripts/ci/job_details/store/mutations.js
+++ b/app/assets/javascripts/ci/job_details/store/mutations.js
@@ -6,6 +6,7 @@ export default {
state.jobEndpoint = options.jobEndpoint;
state.logEndpoint = options.logEndpoint;
state.testReportSummaryUrl = options.testReportSummaryUrl;
+ state.fullScreenAPIAvailable = options.fullScreenAPIAvailable;
},
[types.HIDE_SIDEBAR](state) {
@@ -142,4 +143,16 @@ export default {
[types.RECEIVE_TEST_SUMMARY_COMPLETE](state) {
state.testSummaryComplete = true;
},
+ [types.ENTER_FULLSCREEN_SUCCESS](state) {
+ state.fullScreenEnabled = true;
+ },
+ [types.EXIT_FULLSCREEN_SUCCESS](state) {
+ state.fullScreenEnabled = false;
+ },
+ [types.FULL_SCREEN_CONTAINER_SET_UP](state, value) {
+ state.fullScreenContainerSetUp = value;
+ },
+ [types.FULL_SCREEN_MODE_AVAILABLE_SUCCESS](state) {
+ state.fullScreenModeAvailable = true;
+ },
};
diff --git a/app/assets/javascripts/ci/job_details/store/state.js b/app/assets/javascripts/ci/job_details/store/state.js
index 24736bedf56..a3c1e7692c3 100644
--- a/app/assets/javascripts/ci/job_details/store/state.js
+++ b/app/assets/javascripts/ci/job_details/store/state.js
@@ -16,6 +16,12 @@ export default () => ({
isScrollBottomDisabled: true,
isScrollTopDisabled: true,
+ // fullscreen mode
+ fullScreenAPIAvailable: false,
+ fullScreenModeAvailable: false,
+ fullScreenEnabled: false,
+ fullScreenContainerSetUp: false,
+
jobLog: [],
jobLogSections: {},
isJobLogComplete: false,
diff --git a/app/assets/stylesheets/page_bundles/build.scss b/app/assets/stylesheets/page_bundles/build.scss
index 37014292925..379f1470b20 100644
--- a/app/assets/stylesheets/page_bundles/build.scss
+++ b/app/assets/stylesheets/page_bundles/build.scss
@@ -179,6 +179,14 @@
background-color: $builds-log-bg;
}
+.build-log-container:fullscreen {
+ overflow-y: scroll;
+
+ .top-bar {
+ top: 0 !important;
+ }
+}
+
.job-log-line {
padding: 1px $gl-padding-8 1px $job-log-line-padding;
min-height: $gl-line-height-20;