diff options
Diffstat (limited to 'app/assets/javascripts/jobs/components/job_log_controllers.vue')
-rw-r--r-- | app/assets/javascripts/jobs/components/job_log_controllers.vue | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue index eb6a284dfaf..5e89dd5acc2 100644 --- a/app/assets/javascripts/jobs/components/job_log_controllers.vue +++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue @@ -1,21 +1,34 @@ <script> -import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui'; +import { GlTooltipDirective, GlLink, GlButton, GlSearchBoxByClick } from '@gitlab/ui'; +import { scrollToElement } from '~/lib/utils/common_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils'; import { __, s__, sprintf } from '~/locale'; +import HelpPopover from '~/vue_shared/components/help_popover.vue'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; export default { i18n: { scrollToBottomButtonLabel: s__('Job|Scroll to bottom'), scrollToTopButtonLabel: s__('Job|Scroll to top'), showRawButtonLabel: s__('Job|Show complete raw'), + searchPlaceholder: s__('Job|Search job log'), + noResults: s__('Job|No search results found'), + searchPopoverTitle: s__('Job|Job log search'), + searchPopoverDescription: s__( + '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'), }, components: { GlLink, GlButton, + GlSearchBoxByClick, + HelpPopover, }, directives: { GlTooltip: GlTooltipDirective, }, + mixins: [glFeatureFlagMixin()], props: { size: { type: Number, @@ -42,6 +55,16 @@ export default { type: Boolean, required: true, }, + jobLog: { + type: Array, + required: true, + }, + }, + data() { + return { + searchTerm: '', + searchResults: [], + }; }, computed: { jobLogSize() { @@ -49,6 +72,9 @@ export default { size: numberToHumanSize(this.size), }); }, + showJobLogSearch() { + return this.glFeatures.jobLogSearch; + }, }, methods: { handleScrollToTop() { @@ -57,6 +83,54 @@ export default { handleScrollToBottom() { this.$emit('scrollJobLogBottom'); }, + searchJobLog() { + this.searchResults = []; + + if (!this.searchTerm) return; + + const compactedLog = []; + + this.jobLog.forEach((obj) => { + if (obj.lines && obj.lines.length > 0) { + compactedLog.push(...obj.lines); + } + + if (!obj.lines && obj.content.length > 0) { + compactedLog.push(obj); + } + }); + + compactedLog.forEach((line) => { + const lineText = line.content[0].text; + + if (lineText.toLocaleLowerCase().includes(this.searchTerm.toLocaleLowerCase())) { + this.searchResults.push(line); + } + }); + + if (this.searchResults.length > 0) { + this.$emit('searchResults', this.searchResults); + + // BE returns zero based index, we need to add one to match the line numbers in the DOM + const firstSearchResult = `#L${this.searchResults[0].lineNumber + 1}`; + const logLine = document.querySelector(`.js-line ${firstSearchResult}`); + + if (logLine) { + setTimeout(() => scrollToElement(logLine)); + + const message = sprintf(s__('Job|%{searchLength} results found for %{searchTerm}'), { + searchLength: this.searchResults.length, + searchTerm: this.searchTerm, + }); + + this.$toast.show(message); + } else { + this.$toast.show(this.$options.i18n.logLineNumberNotFound); + } + } else { + this.$toast.show(this.$options.i18n.noResults); + } + }, }, }; </script> @@ -81,6 +155,25 @@ export default { <!-- eo truncate information --> <div class="controllers gl-float-right"> + <template v-if="showJobLogSearch"> + <gl-search-box-by-click + v-model="searchTerm" + class="gl-mr-3" + :placeholder="$options.i18n.searchPlaceholder" + data-testid="job-log-search-box" + @clear="$emit('searchResults', [])" + @submit="searchJobLog" + /> + + <help-popover class="gl-mr-3"> + <template #title>{{ $options.i18n.searchPopoverTitle }}</template> + + <p class="gl-mb-0"> + {{ $options.i18n.searchPopoverDescription }} + </p> + </help-popover> + </template> + <!-- links --> <gl-button v-if="rawPath" |