226 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
| <script>
 | |
| /**
 | |
|  * Common component to render a system note, icon and user information.
 | |
|  *
 | |
|  * This component needs to be used with a vuex store.
 | |
|  * That vuex store needs to have a `targetNoteHash` getter
 | |
|  *
 | |
|  * @example
 | |
|  * <system-note
 | |
|  *   :note="{
 | |
|  *     id: String,
 | |
|  *     author: Object,
 | |
|  *     createdAt: String,
 | |
|  *     note_html: String,
 | |
|  *     system_note_icon_name: String
 | |
|  *    }"
 | |
|  *   />
 | |
|  */
 | |
| import {
 | |
|   GlButton,
 | |
|   GlDeprecatedSkeletonLoading as GlSkeletonLoading,
 | |
|   GlTooltipDirective,
 | |
|   GlIcon,
 | |
|   GlSafeHtmlDirective as SafeHtml,
 | |
| } from '@gitlab/ui';
 | |
| import $ from 'jquery';
 | |
| import { mapGetters, mapActions, mapState } from 'vuex';
 | |
| import descriptionVersionHistoryMixin from 'ee_else_ce/notes/mixins/description_version_history';
 | |
| import '~/behaviors/markdown/render_gfm';
 | |
| import axios from '~/lib/utils/axios_utils';
 | |
| import { __ } from '~/locale';
 | |
| import noteHeader from '~/notes/components/note_header.vue';
 | |
| import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 | |
| import { spriteIcon } from '~/lib/utils/common_utils';
 | |
| import TimelineEntryItem from './timeline_entry_item.vue';
 | |
| 
 | |
| const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
 | |
| 
 | |
| export default {
 | |
|   i18n: {
 | |
|     deleteButtonLabel: __('Remove description history'),
 | |
|   },
 | |
|   name: 'SystemNote',
 | |
|   components: {
 | |
|     GlIcon,
 | |
|     noteHeader,
 | |
|     TimelineEntryItem,
 | |
|     GlButton,
 | |
|     GlSkeletonLoading,
 | |
|   },
 | |
|   directives: {
 | |
|     GlTooltip: GlTooltipDirective,
 | |
|     SafeHtml,
 | |
|   },
 | |
|   mixins: [descriptionVersionHistoryMixin, glFeatureFlagsMixin()],
 | |
|   props: {
 | |
|     note: {
 | |
|       type: Object,
 | |
|       required: true,
 | |
|     },
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       expanded: false,
 | |
|       lines: [],
 | |
|       showLines: false,
 | |
|       loadingDiff: false,
 | |
|     };
 | |
|   },
 | |
|   computed: {
 | |
|     ...mapGetters(['targetNoteHash', 'descriptionVersions']),
 | |
|     ...mapState(['isLoadingDescriptionVersion']),
 | |
|     noteAnchorId() {
 | |
|       return `note_${this.note.id}`;
 | |
|     },
 | |
|     isTargetNote() {
 | |
|       return this.targetNoteHash === this.noteAnchorId;
 | |
|     },
 | |
|     iconHtml() {
 | |
|       return spriteIcon(this.note.system_note_icon_name);
 | |
|     },
 | |
|     toggleIcon() {
 | |
|       return this.expanded ? 'chevron-up' : 'chevron-down';
 | |
|     },
 | |
|     // following 2 methods taken from code in `collapseLongCommitList` of notes.js:
 | |
|     actionTextHtml() {
 | |
|       return $(this.note.note_html).unwrap().html();
 | |
|     },
 | |
|     hasMoreCommits() {
 | |
|       return $(this.note.note_html).filter('ul').children().length > MAX_VISIBLE_COMMIT_LIST_COUNT;
 | |
|     },
 | |
|     descriptionVersion() {
 | |
|       return this.descriptionVersions[this.note.description_version_id];
 | |
|     },
 | |
|   },
 | |
|   mounted() {
 | |
|     $(this.$refs['gfm-content']).renderGFM();
 | |
|   },
 | |
|   methods: {
 | |
|     ...mapActions(['fetchDescriptionVersion', 'softDeleteDescriptionVersion']),
 | |
|     async toggleDiff() {
 | |
|       this.showLines = !this.showLines;
 | |
| 
 | |
|       if (!this.lines.length) {
 | |
|         this.loadingDiff = true;
 | |
|         const { data } = await axios.get(this.note.outdated_line_change_path);
 | |
| 
 | |
|         this.lines = data.map((l) => ({
 | |
|           ...l,
 | |
|           rich_text: l.rich_text.replace(/^[+ -]/, ''),
 | |
|         }));
 | |
|         this.loadingDiff = false;
 | |
|       }
 | |
|     },
 | |
|   },
 | |
|   safeHtmlConfig: {
 | |
|     ADD_TAGS: ['use'], // to support icon SVGs
 | |
|   },
 | |
|   userColorSchemeClass: window.gon.user_color_scheme,
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <template>
 | |
|   <timeline-entry-item
 | |
|     :id="noteAnchorId"
 | |
|     :class="{ target: isTargetNote, 'pr-0': shouldShowDescriptionVersion }"
 | |
|     class="note system-note note-wrapper"
 | |
|   >
 | |
|     <div v-safe-html:[$options.safeHtmlConfig]="iconHtml" class="timeline-icon"></div>
 | |
|     <div class="timeline-content">
 | |
|       <div class="note-header">
 | |
|         <note-header :author="note.author" :created-at="note.created_at" :note-id="note.id">
 | |
|           <span ref="gfm-content" v-safe-html="actionTextHtml"></span>
 | |
|           <template
 | |
|             v-if="canSeeDescriptionVersion || note.outdated_line_change_path"
 | |
|             #extra-controls
 | |
|           >
 | |
|             ·
 | |
|             <gl-button
 | |
|               v-if="canSeeDescriptionVersion"
 | |
|               variant="link"
 | |
|               :icon="descriptionVersionToggleIcon"
 | |
|               data-testid="compare-btn"
 | |
|               class="gl-vertical-align-text-bottom"
 | |
|               @click="toggleDescriptionVersion"
 | |
|               >{{ __('Compare with previous version') }}</gl-button
 | |
|             >
 | |
|             <gl-button
 | |
|               v-if="note.outdated_line_change_path"
 | |
|               :icon="showLines ? 'chevron-up' : 'chevron-down'"
 | |
|               variant="link"
 | |
|               data-testid="outdated-lines-change-btn"
 | |
|               class="gl-vertical-align-text-bottom"
 | |
|               @click="toggleDiff"
 | |
|             >
 | |
|               {{ __('Compare changes') }}
 | |
|             </gl-button>
 | |
|           </template>
 | |
|         </note-header>
 | |
|       </div>
 | |
|       <div class="note-body">
 | |
|         <div
 | |
|           v-safe-html="note.note_html"
 | |
|           :class="{ 'system-note-commit-list': hasMoreCommits, 'hide-shade': expanded }"
 | |
|           class="note-text md"
 | |
|         ></div>
 | |
|         <div v-if="hasMoreCommits" class="flex-list">
 | |
|           <div class="system-note-commit-list-toggler flex-row" @click="expanded = !expanded">
 | |
|             <gl-icon :name="toggleIcon" :size="8" class="gl-mr-2" />
 | |
|             <span>{{ __('Toggle commit list') }}</span>
 | |
|           </div>
 | |
|         </div>
 | |
|         <div v-if="shouldShowDescriptionVersion" class="description-version pt-2">
 | |
|           <pre v-if="isLoadingDescriptionVersion" class="loading-state">
 | |
|             <gl-skeleton-loading />
 | |
|           </pre>
 | |
|           <pre v-else v-safe-html="descriptionVersion" class="wrapper mt-2"></pre>
 | |
|           <gl-button
 | |
|             v-if="displayDeleteButton"
 | |
|             v-gl-tooltip
 | |
|             :title="$options.i18n.deleteButtonLabel"
 | |
|             :aria-label="$options.i18n.deleteButtonLabel"
 | |
|             variant="default"
 | |
|             category="tertiary"
 | |
|             icon="remove"
 | |
|             class="delete-description-history"
 | |
|             data-testid="delete-description-version-button"
 | |
|             @click="deleteDescriptionVersion"
 | |
|           />
 | |
|         </div>
 | |
|         <div
 | |
|           v-if="lines.length && showLines"
 | |
|           class="diff-content gl-border-solid gl-border-1 gl-border-gray-200 gl-mt-4 gl-rounded-small gl-overflow-hidden"
 | |
|         >
 | |
|           <table
 | |
|             :class="$options.userColorSchemeClass"
 | |
|             class="code js-syntax-highlight"
 | |
|             data-testid="outdated-lines"
 | |
|           >
 | |
|             <tr v-for="line in lines" v-once :key="line.line_code" class="line_holder">
 | |
|               <td
 | |
|                 :class="line.type"
 | |
|                 class="diff-line-num old_line gl-border-bottom-0! gl-border-top-0!"
 | |
|               >
 | |
|                 {{ line.old_line }}
 | |
|               </td>
 | |
|               <td
 | |
|                 :class="line.type"
 | |
|                 class="diff-line-num new_line gl-border-bottom-0! gl-border-top-0!"
 | |
|               >
 | |
|                 {{ line.new_line }}
 | |
|               </td>
 | |
|               <td
 | |
|                 :class="line.type"
 | |
|                 class="line_content gl-display-table-cell!"
 | |
|                 v-html="line.rich_text /* eslint-disable-line vue/no-v-html */"
 | |
|               ></td>
 | |
|             </tr>
 | |
|           </table>
 | |
|         </div>
 | |
|         <gl-skeleton-loading v-else-if="showLines" class="gl-mt-4" />
 | |
|       </div>
 | |
|     </div>
 | |
|   </timeline-entry-item>
 | |
| </template>
 |