Replace existing uses of timeline-entry with timeline entry component
This commit is contained in:
parent
99862050de
commit
e3bddb6223
9 changed files with 378 additions and 379 deletions
|
@ -4,6 +4,7 @@ import { mapActions, mapGetters, mapState } from 'vuex';
|
|||
import _ from 'underscore';
|
||||
import Autosize from 'autosize';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
import Flash from '../../flash';
|
||||
import Autosave from '../../autosave';
|
||||
import {
|
||||
|
@ -30,6 +31,7 @@ export default {
|
|||
markdownField,
|
||||
userAvatarLink,
|
||||
loadingButton,
|
||||
TimelineEntryItem,
|
||||
},
|
||||
mixins: [issuableStateMixin],
|
||||
props: {
|
||||
|
@ -309,137 +311,135 @@ Please check your network connection and try again.`;
|
|||
<div>
|
||||
<note-signed-out-widget v-if="!isLoggedIn" />
|
||||
<discussion-locked-widget v-else-if="!canCreateNote" :issuable-type="issuableTypeTitle" />
|
||||
<div v-else-if="canCreateNote" class="notes notes-form timeline">
|
||||
<div class="timeline-entry note-form">
|
||||
<div class="timeline-entry-inner">
|
||||
<div class="flash-container error-alert timeline-content"></div>
|
||||
<div class="timeline-icon d-none d-sm-none d-md-block">
|
||||
<user-avatar-link
|
||||
v-if="author"
|
||||
:link-href="author.path"
|
||||
:img-src="author.avatar_url"
|
||||
:img-alt="author.name"
|
||||
:img-size="40"
|
||||
/>
|
||||
</div>
|
||||
<div class="timeline-content timeline-content-form">
|
||||
<form ref="commentForm" class="new-note common-note-form gfm-form js-main-target-form">
|
||||
<div class="error-alert"></div>
|
||||
<ul v-else-if="canCreateNote" class="notes notes-form timeline">
|
||||
<timeline-entry-item class="note-form">
|
||||
<div class="flash-container error-alert timeline-content"></div>
|
||||
<div class="timeline-icon d-none d-sm-none d-md-block">
|
||||
<user-avatar-link
|
||||
v-if="author"
|
||||
:link-href="author.path"
|
||||
:img-src="author.avatar_url"
|
||||
:img-alt="author.name"
|
||||
:img-size="40"
|
||||
/>
|
||||
</div>
|
||||
<div class="timeline-content timeline-content-form">
|
||||
<form ref="commentForm" class="new-note common-note-form gfm-form js-main-target-form">
|
||||
<div class="error-alert"></div>
|
||||
|
||||
<issue-warning
|
||||
v-if="hasWarning(getNoteableData)"
|
||||
:is-locked="isLocked(getNoteableData)"
|
||||
:is-confidential="isConfidential(getNoteableData)"
|
||||
<issue-warning
|
||||
v-if="hasWarning(getNoteableData)"
|
||||
:is-locked="isLocked(getNoteableData)"
|
||||
:is-confidential="isConfidential(getNoteableData)"
|
||||
/>
|
||||
|
||||
<markdown-field
|
||||
ref="markdownField"
|
||||
:markdown-preview-path="markdownPreviewPath"
|
||||
:markdown-docs-path="markdownDocsPath"
|
||||
:quick-actions-docs-path="quickActionsDocsPath"
|
||||
:markdown-version="markdownVersion"
|
||||
:add-spacing-classes="false"
|
||||
>
|
||||
<textarea
|
||||
id="note-body"
|
||||
ref="textarea"
|
||||
slot="textarea"
|
||||
v-model="note"
|
||||
:disabled="isSubmitting"
|
||||
name="note[note]"
|
||||
class="note-textarea js-vue-comment-form js-note-text
|
||||
js-gfm-input js-autosize markdown-area js-vue-textarea qa-comment-input"
|
||||
data-supports-quick-actions="true"
|
||||
aria-label="Description"
|
||||
placeholder="Write a comment or drag your files here…"
|
||||
@keydown.up="editCurrentUserLastNote();"
|
||||
@keydown.meta.enter="handleSave();"
|
||||
@keydown.ctrl.enter="handleSave();"
|
||||
>
|
||||
</textarea>
|
||||
</markdown-field>
|
||||
<div class="note-form-actions">
|
||||
<div
|
||||
class="float-left btn-group
|
||||
append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
|
||||
>
|
||||
<button
|
||||
:disabled="isSubmitButtonDisabled"
|
||||
class="btn btn-create comment-btn js-comment-button js-comment-submit-button
|
||||
qa-comment-button"
|
||||
type="submit"
|
||||
@click.prevent="handleSave();"
|
||||
>
|
||||
{{ __(commentButtonTitle) }}
|
||||
</button>
|
||||
<button
|
||||
:disabled="isSubmitButtonDisabled"
|
||||
name="button"
|
||||
type="button"
|
||||
class="btn comment-btn note-type-toggle js-note-new-discussion dropdown-toggle qa-note-dropdown"
|
||||
data-display="static"
|
||||
data-toggle="dropdown"
|
||||
aria-label="Open comment type dropdown"
|
||||
>
|
||||
<i aria-hidden="true" class="fa fa-caret-down toggle-icon"> </i>
|
||||
</button>
|
||||
|
||||
<ul class="note-type-dropdown dropdown-open-top dropdown-menu">
|
||||
<li :class="{ 'droplab-item-selected': noteType === 'comment' }">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent"
|
||||
@click.prevent="setNoteType('comment');"
|
||||
>
|
||||
<i aria-hidden="true" class="fa fa-check icon"> </i>
|
||||
<div class="description">
|
||||
<strong>Comment</strong>
|
||||
<p>Add a general comment to this {{ noteableDisplayName }}.</p>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
<li class="divider droplab-item-ignore"></li>
|
||||
<li :class="{ 'droplab-item-selected': noteType === 'discussion' }">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent qa-discussion-option"
|
||||
@click.prevent="setNoteType('discussion');"
|
||||
>
|
||||
<i aria-hidden="true" class="fa fa-check icon"> </i>
|
||||
<div class="description">
|
||||
<strong>Start discussion</strong>
|
||||
<p>{{ startDiscussionDescription }}</p>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<loading-button
|
||||
v-if="canUpdateIssue"
|
||||
:loading="isToggleStateButtonLoading"
|
||||
:container-class="[
|
||||
actionButtonClassNames,
|
||||
'btn btn-comment btn-comment-and-close js-action-button',
|
||||
]"
|
||||
:disabled="isToggleStateButtonLoading || isSubmitting"
|
||||
:label="issueActionButtonTitle"
|
||||
@click="handleSave(true);"
|
||||
/>
|
||||
|
||||
<markdown-field
|
||||
ref="markdownField"
|
||||
:markdown-preview-path="markdownPreviewPath"
|
||||
:markdown-docs-path="markdownDocsPath"
|
||||
:quick-actions-docs-path="quickActionsDocsPath"
|
||||
:markdown-version="markdownVersion"
|
||||
:add-spacing-classes="false"
|
||||
<button
|
||||
v-if="note.length"
|
||||
type="button"
|
||||
class="btn btn-cancel js-note-discard"
|
||||
@click="discard"
|
||||
>
|
||||
<textarea
|
||||
id="note-body"
|
||||
ref="textarea"
|
||||
slot="textarea"
|
||||
v-model="note"
|
||||
:disabled="isSubmitting"
|
||||
name="note[note]"
|
||||
class="note-textarea js-vue-comment-form js-note-text
|
||||
js-gfm-input js-autosize markdown-area js-vue-textarea qa-comment-input"
|
||||
data-supports-quick-actions="true"
|
||||
aria-label="Description"
|
||||
placeholder="Write a comment or drag your files here…"
|
||||
@keydown.up="editCurrentUserLastNote();"
|
||||
@keydown.meta.enter="handleSave();"
|
||||
@keydown.ctrl.enter="handleSave();"
|
||||
>
|
||||
</textarea>
|
||||
</markdown-field>
|
||||
<div class="note-form-actions">
|
||||
<div
|
||||
class="float-left btn-group
|
||||
append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
|
||||
>
|
||||
<button
|
||||
:disabled="isSubmitButtonDisabled"
|
||||
class="btn btn-create comment-btn js-comment-button js-comment-submit-button
|
||||
qa-comment-button"
|
||||
type="submit"
|
||||
@click.prevent="handleSave();"
|
||||
>
|
||||
{{ __(commentButtonTitle) }}
|
||||
</button>
|
||||
<button
|
||||
:disabled="isSubmitButtonDisabled"
|
||||
name="button"
|
||||
type="button"
|
||||
class="btn comment-btn note-type-toggle js-note-new-discussion dropdown-toggle qa-note-dropdown"
|
||||
data-display="static"
|
||||
data-toggle="dropdown"
|
||||
aria-label="Open comment type dropdown"
|
||||
>
|
||||
<i aria-hidden="true" class="fa fa-caret-down toggle-icon"> </i>
|
||||
</button>
|
||||
|
||||
<ul class="note-type-dropdown dropdown-open-top dropdown-menu">
|
||||
<li :class="{ 'droplab-item-selected': noteType === 'comment' }">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent"
|
||||
@click.prevent="setNoteType('comment');"
|
||||
>
|
||||
<i aria-hidden="true" class="fa fa-check icon"> </i>
|
||||
<div class="description">
|
||||
<strong>Comment</strong>
|
||||
<p>Add a general comment to this {{ noteableDisplayName }}.</p>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
<li class="divider droplab-item-ignore"></li>
|
||||
<li :class="{ 'droplab-item-selected': noteType === 'discussion' }">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent qa-discussion-option"
|
||||
@click.prevent="setNoteType('discussion');"
|
||||
>
|
||||
<i aria-hidden="true" class="fa fa-check icon"> </i>
|
||||
<div class="description">
|
||||
<strong>Start discussion</strong>
|
||||
<p>{{ startDiscussionDescription }}</p>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<loading-button
|
||||
v-if="canUpdateIssue"
|
||||
:loading="isToggleStateButtonLoading"
|
||||
:container-class="[
|
||||
actionButtonClassNames,
|
||||
'btn btn-comment btn-comment-and-close js-action-button',
|
||||
]"
|
||||
:disabled="isToggleStateButtonLoading || isSubmitting"
|
||||
:label="issueActionButtonTitle"
|
||||
@click="handleSave(true);"
|
||||
/>
|
||||
|
||||
<button
|
||||
v-if="note.length"
|
||||
type="button"
|
||||
class="btn btn-cancel js-note-discard"
|
||||
@click="discard"
|
||||
>
|
||||
Discard draft
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
Discard draft
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</timeline-entry-item>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { truncateSha } from '~/lib/utils/text_utility';
|
|||
import { s__, __, sprintf } from '~/locale';
|
||||
import systemNote from '~/vue_shared/components/notes/system_note.vue';
|
||||
import icon from '~/vue_shared/components/icon.vue';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
import Flash from '../../flash';
|
||||
import { SYSTEM_NOTE } from '../constants';
|
||||
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
|
||||
|
@ -37,6 +38,7 @@ export default {
|
|||
placeholderNote,
|
||||
placeholderSystemNote,
|
||||
systemNote,
|
||||
TimelineEntryItem,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
|
@ -301,162 +303,156 @@ Please check your network connection and try again.`;
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<li class="note note-discussion timeline-entry" :class="componentClassName">
|
||||
<div class="timeline-entry-inner">
|
||||
<div class="timeline-content">
|
||||
<div :data-discussion-id="discussion.id" class="discussion js-discussion-container">
|
||||
<div v-if="shouldRenderDiffs" class="discussion-header note-wrapper">
|
||||
<div v-once class="timeline-icon">
|
||||
<user-avatar-link
|
||||
v-if="author"
|
||||
:link-href="author.path"
|
||||
:img-src="author.avatar_url"
|
||||
:img-alt="author.name"
|
||||
:img-size="40"
|
||||
/>
|
||||
</div>
|
||||
<note-header
|
||||
:author="author"
|
||||
:created-at="initialDiscussion.created_at"
|
||||
:note-id="initialDiscussion.id"
|
||||
:include-toggle="true"
|
||||
:expanded="discussion.expanded"
|
||||
@toggleHandler="toggleDiscussionHandler"
|
||||
>
|
||||
<span v-html="actionText"></span>
|
||||
</note-header>
|
||||
<note-edited-text
|
||||
v-if="discussion.resolved"
|
||||
:edited-at="discussion.resolved_at"
|
||||
:edited-by="discussion.resolved_by"
|
||||
:action-text="resolvedText"
|
||||
class-name="discussion-headline-light js-discussion-headline"
|
||||
/>
|
||||
<note-edited-text
|
||||
v-else-if="lastUpdatedAt"
|
||||
:edited-at="lastUpdatedAt"
|
||||
:edited-by="lastUpdatedBy"
|
||||
action-text="Last updated"
|
||||
class-name="discussion-headline-light js-discussion-headline"
|
||||
<timeline-entry-item class="note note-discussion" :class="componentClassName">
|
||||
<div class="timeline-content">
|
||||
<div :data-discussion-id="discussion.id" class="discussion js-discussion-container">
|
||||
<div v-if="shouldRenderDiffs" class="discussion-header note-wrapper">
|
||||
<div v-once class="timeline-icon">
|
||||
<user-avatar-link
|
||||
v-if="author"
|
||||
:link-href="author.path"
|
||||
:img-src="author.avatar_url"
|
||||
:img-alt="author.name"
|
||||
:img-size="40"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="shouldShowDiscussions" class="discussion-body">
|
||||
<component
|
||||
:is="wrapperComponent"
|
||||
v-bind="wrapperComponentProps"
|
||||
class="card discussion-wrapper"
|
||||
>
|
||||
<div class="discussion-notes">
|
||||
<ul class="notes">
|
||||
<template v-if="shouldGroupReplies">
|
||||
<component
|
||||
:is="componentName(initialDiscussion)"
|
||||
:note="componentData(initialDiscussion)"
|
||||
@handleDeleteNote="deleteNoteHandler"
|
||||
>
|
||||
<slot slot="avatar-badge" name="avatar-badge"></slot>
|
||||
</component>
|
||||
<toggle-replies-widget
|
||||
v-if="hasReplies"
|
||||
:collapsed="isRepliesCollapsed"
|
||||
:replies="replies"
|
||||
@toggle="toggleReplies"
|
||||
/>
|
||||
<template v-if="!isRepliesCollapsed">
|
||||
<component
|
||||
:is="componentName(note)"
|
||||
v-for="note in replies"
|
||||
:key="note.id"
|
||||
:note="componentData(note)"
|
||||
@handleDeleteNote="deleteNoteHandler"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<note-header
|
||||
:author="author"
|
||||
:created-at="initialDiscussion.created_at"
|
||||
:note-id="initialDiscussion.id"
|
||||
:include-toggle="true"
|
||||
:expanded="discussion.expanded"
|
||||
@toggleHandler="toggleDiscussionHandler"
|
||||
>
|
||||
<span v-html="actionText"></span>
|
||||
</note-header>
|
||||
<note-edited-text
|
||||
v-if="discussion.resolved"
|
||||
:edited-at="discussion.resolved_at"
|
||||
:edited-by="discussion.resolved_by"
|
||||
:action-text="resolvedText"
|
||||
class-name="discussion-headline-light js-discussion-headline"
|
||||
/>
|
||||
<note-edited-text
|
||||
v-else-if="lastUpdatedAt"
|
||||
:edited-at="lastUpdatedAt"
|
||||
:edited-by="lastUpdatedBy"
|
||||
action-text="Last updated"
|
||||
class-name="discussion-headline-light js-discussion-headline"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="shouldShowDiscussions" class="discussion-body">
|
||||
<component
|
||||
:is="wrapperComponent"
|
||||
v-bind="wrapperComponentProps"
|
||||
class="card discussion-wrapper"
|
||||
>
|
||||
<div class="discussion-notes">
|
||||
<ul class="notes">
|
||||
<template v-if="shouldGroupReplies">
|
||||
<component
|
||||
:is="componentName(initialDiscussion)"
|
||||
:note="componentData(initialDiscussion)"
|
||||
@handleDeleteNote="deleteNoteHandler"
|
||||
>
|
||||
<slot slot="avatar-badge" name="avatar-badge"></slot>
|
||||
</component>
|
||||
<toggle-replies-widget
|
||||
v-if="hasReplies"
|
||||
:collapsed="isRepliesCollapsed"
|
||||
:replies="replies"
|
||||
@toggle="toggleReplies"
|
||||
/>
|
||||
<template v-if="!isRepliesCollapsed">
|
||||
<component
|
||||
:is="componentName(note)"
|
||||
v-for="(note, index) in discussion.notes"
|
||||
v-for="note in replies"
|
||||
:key="note.id"
|
||||
:note="componentData(note)"
|
||||
@handleDeleteNote="deleteNoteHandler"
|
||||
>
|
||||
<slot v-if="index === 0" slot="avatar-badge" name="avatar-badge"></slot>
|
||||
</component>
|
||||
/>
|
||||
</template>
|
||||
</ul>
|
||||
<div
|
||||
v-if="!isRepliesCollapsed"
|
||||
:class="{ 'is-replying': isReplying }"
|
||||
class="discussion-reply-holder"
|
||||
>
|
||||
<template v-if="!isReplying && canReply">
|
||||
<div class="discussion-with-resolve-btn">
|
||||
</template>
|
||||
<template v-else>
|
||||
<component
|
||||
:is="componentName(note)"
|
||||
v-for="(note, index) in discussion.notes"
|
||||
:key="note.id"
|
||||
:note="componentData(note)"
|
||||
@handleDeleteNote="deleteNoteHandler"
|
||||
>
|
||||
<slot v-if="index === 0" slot="avatar-badge" name="avatar-badge"></slot>
|
||||
</component>
|
||||
</template>
|
||||
</ul>
|
||||
<div
|
||||
v-if="!isRepliesCollapsed"
|
||||
:class="{ 'is-replying': isReplying }"
|
||||
class="discussion-reply-holder"
|
||||
>
|
||||
<template v-if="!isReplying && canReply">
|
||||
<div class="discussion-with-resolve-btn">
|
||||
<button
|
||||
type="button"
|
||||
class="js-vue-discussion-reply btn btn-text-field mr-sm-2 qa-discussion-reply"
|
||||
title="Add a reply"
|
||||
@click="showReplyForm"
|
||||
>
|
||||
Reply...
|
||||
</button>
|
||||
<div v-if="discussion.resolvable">
|
||||
<button
|
||||
type="button"
|
||||
class="js-vue-discussion-reply btn btn-text-field mr-sm-2 qa-discussion-reply"
|
||||
title="Add a reply"
|
||||
@click="showReplyForm"
|
||||
class="btn btn-default mr-sm-2"
|
||||
@click="resolveHandler();"
|
||||
>
|
||||
Reply...
|
||||
<i v-if="isResolving" aria-hidden="true" class="fa fa-spinner fa-spin"></i>
|
||||
{{ resolveButtonTitle }}
|
||||
</button>
|
||||
<div v-if="discussion.resolvable">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default mr-sm-2"
|
||||
@click="resolveHandler();"
|
||||
</div>
|
||||
<div
|
||||
v-if="discussion.resolvable"
|
||||
class="btn-group discussion-actions ml-sm-2"
|
||||
role="group"
|
||||
>
|
||||
<div v-if="!discussionResolved" class="btn-group" role="group">
|
||||
<a
|
||||
v-gl-tooltip
|
||||
:href="discussion.resolve_with_issue_path"
|
||||
:title="s__('MergeRequests|Resolve this discussion in a new issue')"
|
||||
class="new-issue-for-discussion btn btn-default discussion-create-issue-btn"
|
||||
>
|
||||
<i
|
||||
v-if="isResolving"
|
||||
aria-hidden="true"
|
||||
class="fa fa-spinner fa-spin"
|
||||
></i>
|
||||
{{ resolveButtonTitle }}
|
||||
<icon name="issue-new" />
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="hasUnresolvedDiscussions" class="btn-group" role="group">
|
||||
<button
|
||||
v-gl-tooltip
|
||||
class="btn btn-default discussion-next-btn"
|
||||
title="Jump to next unresolved discussion"
|
||||
@click="jumpToNextDiscussion"
|
||||
>
|
||||
<icon name="comment-next" />
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-if="discussion.resolvable"
|
||||
class="btn-group discussion-actions ml-sm-2"
|
||||
role="group"
|
||||
>
|
||||
<div v-if="!discussionResolved" class="btn-group" role="group">
|
||||
<a
|
||||
v-gl-tooltip
|
||||
:href="discussion.resolve_with_issue_path"
|
||||
:title="s__('MergeRequests|Resolve this discussion in a new issue')"
|
||||
class="new-issue-for-discussion btn btn-default discussion-create-issue-btn"
|
||||
>
|
||||
<icon name="issue-new" />
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="hasUnresolvedDiscussions" class="btn-group" role="group">
|
||||
<button
|
||||
v-gl-tooltip
|
||||
class="btn btn-default discussion-next-btn"
|
||||
title="Jump to next unresolved discussion"
|
||||
@click="jumpToNextDiscussion"
|
||||
>
|
||||
<icon name="comment-next" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<note-form
|
||||
v-if="isReplying"
|
||||
ref="noteForm"
|
||||
:discussion="discussion"
|
||||
:is-editing="false"
|
||||
save-button-title="Comment"
|
||||
@handleFormUpdate="saveReply"
|
||||
@cancelForm="cancelReplyForm"
|
||||
/>
|
||||
<note-signed-out-widget v-if="!canReply" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<note-form
|
||||
v-if="isReplying"
|
||||
ref="noteForm"
|
||||
:discussion="discussion"
|
||||
:is-editing="false"
|
||||
save-button-title="Comment"
|
||||
@handleFormUpdate="saveReply"
|
||||
@cancelForm="cancelReplyForm"
|
||||
/>
|
||||
<note-signed-out-widget v-if="!canReply" />
|
||||
</div>
|
||||
</component>
|
||||
</div>
|
||||
</div>
|
||||
</component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</timeline-entry-item>
|
||||
</template>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import $ from 'jquery';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { escape } from 'underscore';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
import Flash from '../../flash';
|
||||
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
|
||||
import noteHeader from './note_header.vue';
|
||||
|
@ -18,6 +19,7 @@ export default {
|
|||
noteHeader,
|
||||
noteActions,
|
||||
noteBody,
|
||||
TimelineEntryItem,
|
||||
},
|
||||
mixins: [noteable, resolvable],
|
||||
props: {
|
||||
|
@ -169,62 +171,60 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<li
|
||||
<timeline-entry-item
|
||||
:id="noteAnchorId"
|
||||
:class="classNameBindings"
|
||||
:data-award-url="note.toggle_award_path"
|
||||
:data-note-id="note.id"
|
||||
class="note timeline-entry note-wrapper"
|
||||
class="note note-wrapper"
|
||||
>
|
||||
<div class="timeline-entry-inner">
|
||||
<div v-once class="timeline-icon">
|
||||
<user-avatar-link
|
||||
:link-href="author.path"
|
||||
:img-src="author.avatar_url"
|
||||
:img-alt="author.name"
|
||||
:img-size="40"
|
||||
>
|
||||
<slot slot="avatar-badge" name="avatar-badge"> </slot>
|
||||
</user-avatar-link>
|
||||
</div>
|
||||
<div class="timeline-content">
|
||||
<div class="note-header">
|
||||
<note-header
|
||||
v-once
|
||||
:author="author"
|
||||
:created-at="note.created_at"
|
||||
:note-id="note.id"
|
||||
action-text="commented"
|
||||
/>
|
||||
<note-actions
|
||||
:author-id="author.id"
|
||||
:note-id="note.id"
|
||||
:note-url="note.noteable_note_url"
|
||||
:access-level="note.human_access"
|
||||
:can-edit="note.current_user.can_edit"
|
||||
:can-award-emoji="note.current_user.can_award_emoji"
|
||||
:can-delete="note.current_user.can_edit"
|
||||
:can-report-as-abuse="canReportAsAbuse"
|
||||
:can-resolve="note.current_user.can_resolve"
|
||||
:report-abuse-path="note.report_abuse_path"
|
||||
:resolvable="note.resolvable"
|
||||
:is-resolved="note.resolved"
|
||||
:is-resolving="isResolving"
|
||||
:resolved-by="note.resolved_by"
|
||||
@handleEdit="editHandler"
|
||||
@handleDelete="deleteHandler"
|
||||
@handleResolve="resolveHandler"
|
||||
/>
|
||||
</div>
|
||||
<note-body
|
||||
ref="noteBody"
|
||||
:note="note"
|
||||
<div v-once class="timeline-icon">
|
||||
<user-avatar-link
|
||||
:link-href="author.path"
|
||||
:img-src="author.avatar_url"
|
||||
:img-alt="author.name"
|
||||
:img-size="40"
|
||||
>
|
||||
<slot slot="avatar-badge" name="avatar-badge"> </slot>
|
||||
</user-avatar-link>
|
||||
</div>
|
||||
<div class="timeline-content">
|
||||
<div class="note-header">
|
||||
<note-header
|
||||
v-once
|
||||
:author="author"
|
||||
:created-at="note.created_at"
|
||||
:note-id="note.id"
|
||||
action-text="commented"
|
||||
/>
|
||||
<note-actions
|
||||
:author-id="author.id"
|
||||
:note-id="note.id"
|
||||
:note-url="note.noteable_note_url"
|
||||
:access-level="note.human_access"
|
||||
:can-edit="note.current_user.can_edit"
|
||||
:is-editing="isEditing"
|
||||
@handleFormUpdate="formUpdateHandler"
|
||||
@cancelForm="formCancelHandler"
|
||||
:can-award-emoji="note.current_user.can_award_emoji"
|
||||
:can-delete="note.current_user.can_edit"
|
||||
:can-report-as-abuse="canReportAsAbuse"
|
||||
:can-resolve="note.current_user.can_resolve"
|
||||
:report-abuse-path="note.report_abuse_path"
|
||||
:resolvable="note.resolvable"
|
||||
:is-resolved="note.resolved"
|
||||
:is-resolving="isResolving"
|
||||
:resolved-by="note.resolved_by"
|
||||
@handleEdit="editHandler"
|
||||
@handleDelete="deleteHandler"
|
||||
@handleResolve="resolveHandler"
|
||||
/>
|
||||
</div>
|
||||
<note-body
|
||||
ref="noteBody"
|
||||
:note="note"
|
||||
:can-edit="note.current_user.can_edit"
|
||||
:is-editing="isEditing"
|
||||
@handleFormUpdate="formUpdateHandler"
|
||||
@cancelForm="formCancelHandler"
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
</timeline-entry-item>
|
||||
</template>
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
* />
|
||||
*/
|
||||
import { mapGetters } from 'vuex';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
import userAvatarLink from '../user_avatar/user_avatar_link.vue';
|
||||
|
||||
export default {
|
||||
name: 'PlaceholderNote',
|
||||
components: {
|
||||
userAvatarLink,
|
||||
TimelineEntryItem,
|
||||
},
|
||||
props: {
|
||||
note: {
|
||||
|
@ -37,30 +39,28 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<li class="note being-posted fade-in-half timeline-entry">
|
||||
<div class="timeline-entry-inner">
|
||||
<div class="timeline-icon">
|
||||
<user-avatar-link
|
||||
:link-href="getUserData.path"
|
||||
:img-src="getUserData.avatar_url"
|
||||
:img-size="40"
|
||||
/>
|
||||
</div>
|
||||
<div :class="{ discussion: !note.individual_note }" class="timeline-content">
|
||||
<div class="note-header">
|
||||
<div class="note-header-info">
|
||||
<a :href="getUserData.path">
|
||||
<span class="d-none d-sm-inline-block">{{ getUserData.name }}</span>
|
||||
<span class="note-headline-light">@{{ getUserData.username }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<timeline-entry-item class="note being-posted fade-in-half">
|
||||
<div class="timeline-icon">
|
||||
<user-avatar-link
|
||||
:link-href="getUserData.path"
|
||||
:img-src="getUserData.avatar_url"
|
||||
:img-size="40"
|
||||
/>
|
||||
</div>
|
||||
<div :class="{ discussion: !note.individual_note }" class="timeline-content">
|
||||
<div class="note-header">
|
||||
<div class="note-header-info">
|
||||
<a :href="getUserData.path">
|
||||
<span class="d-none d-sm-inline-block">{{ getUserData.name }}</span>
|
||||
<span class="note-headline-light">@{{ getUserData.username }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="note-body">
|
||||
<div class="note-text">
|
||||
<p>{{ note.body }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="note-body">
|
||||
<div class="note-text">
|
||||
<p>{{ note.body }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</timeline-entry-item>
|
||||
</template>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<script>
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
|
||||
/**
|
||||
* Common component to render a placeholder system note.
|
||||
*
|
||||
|
@ -9,6 +11,9 @@
|
|||
*/
|
||||
export default {
|
||||
name: 'PlaceholderSystemNote',
|
||||
components: {
|
||||
TimelineEntryItem,
|
||||
},
|
||||
props: {
|
||||
note: {
|
||||
type: Object,
|
||||
|
@ -19,11 +24,9 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<li class="note system-note timeline-entry being-posted fade-in-half">
|
||||
<div class="timeline-entry-inner">
|
||||
<div class="timeline-content">
|
||||
<em>{{ note.body }}</em>
|
||||
</div>
|
||||
<timeline-entry-item class="note system-note being-posted fade-in-half">
|
||||
<div class="timeline-content">
|
||||
<em>{{ note.body }}</em>
|
||||
</div>
|
||||
</li>
|
||||
</timeline-entry-item>
|
||||
</template>
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
<script>
|
||||
import { GlSkeletonLoading } from '@gitlab/ui';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
|
||||
export default {
|
||||
name: 'SkeletonNote',
|
||||
components: {
|
||||
GlSkeletonLoading,
|
||||
TimelineEntryItem,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<li class="timeline-entry note note-wrapper">
|
||||
<div class="timeline-entry-inner">
|
||||
<div class="timeline-icon"></div>
|
||||
<div class="timeline-content">
|
||||
<div class="note-header"></div>
|
||||
<div class="note-body"><gl-skeleton-loading /></div>
|
||||
</div>
|
||||
<timeline-entry-item class="note note-wrapper">
|
||||
<div class="timeline-icon"></div>
|
||||
<div class="timeline-content">
|
||||
<div class="note-header"></div>
|
||||
<div class="note-body"><gl-skeleton-loading /></div>
|
||||
</div>
|
||||
</li>
|
||||
</timeline-entry-item>
|
||||
</template>
|
||||
|
|
|
@ -20,6 +20,7 @@ import $ from 'jquery';
|
|||
import { mapGetters } from 'vuex';
|
||||
import noteHeader from '~/notes/components/note_header.vue';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
import TimelineEntryItem from './timeline_entry_item.vue';
|
||||
import { spriteIcon } from '../../../lib/utils/common_utils';
|
||||
|
||||
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
|
||||
|
@ -29,6 +30,7 @@ export default {
|
|||
components: {
|
||||
Icon,
|
||||
noteHeader,
|
||||
TimelineEntryItem,
|
||||
},
|
||||
props: {
|
||||
note: {
|
||||
|
@ -73,36 +75,34 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<li
|
||||
<timeline-entry-item
|
||||
:id="noteAnchorId"
|
||||
:class="{ target: isTargetNote }"
|
||||
class="note system-note timeline-entry note-wrapper"
|
||||
class="note system-note note-wrapper"
|
||||
>
|
||||
<div class="timeline-entry-inner">
|
||||
<div class="timeline-icon" v-html="iconHtml"></div>
|
||||
<div class="timeline-content">
|
||||
<div class="note-header">
|
||||
<note-header :author="note.author" :created-at="note.created_at" :note-id="note.id">
|
||||
<span v-html="actionTextHtml"></span>
|
||||
</note-header>
|
||||
</div>
|
||||
<div class="note-body">
|
||||
<div
|
||||
:class="{
|
||||
'system-note-commit-list': hasMoreCommits,
|
||||
'hide-shade': expanded,
|
||||
}"
|
||||
class="note-text"
|
||||
v-html="note.note_html"
|
||||
></div>
|
||||
<div v-if="hasMoreCommits" class="flex-list">
|
||||
<div class="system-note-commit-list-toggler flex-row" @click="expanded = !expanded;">
|
||||
<icon :name="toggleIcon" :size="8" class="append-right-5" />
|
||||
<span>Toggle commit list</span>
|
||||
</div>
|
||||
<div class="timeline-icon" v-html="iconHtml"></div>
|
||||
<div class="timeline-content">
|
||||
<div class="note-header">
|
||||
<note-header :author="note.author" :created-at="note.created_at" :note-id="note.id">
|
||||
<span v-html="actionTextHtml"></span>
|
||||
</note-header>
|
||||
</div>
|
||||
<div class="note-body">
|
||||
<div
|
||||
:class="{
|
||||
'system-note-commit-list': hasMoreCommits,
|
||||
'hide-shade': expanded,
|
||||
}"
|
||||
class="note-text"
|
||||
v-html="note.note_html"
|
||||
></div>
|
||||
<div v-if="hasMoreCommits" class="flex-list">
|
||||
<div class="system-note-commit-list-toggler flex-row" @click="expanded = !expanded;">
|
||||
<icon :name="toggleIcon" :size="8" class="append-right-5" />
|
||||
<span>Toggle commit list</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</timeline-entry-item>
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'TimelineEntry',
|
||||
name: 'TimelineEntryItem',
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import TimelineEntry from '~/vue_shared/components/notes/timeline_entry.vue';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
|
||||
describe(TimelineEntry.name, () => {
|
||||
describe(TimelineEntryItem.name, () => {
|
||||
let wrapper;
|
||||
|
||||
const factory = (options = {}) => {
|
||||
const localVue = createLocalVue();
|
||||
|
||||
wrapper = shallowMount(TimelineEntry, {
|
||||
wrapper = shallowMount(TimelineEntryItem, {
|
||||
localVue,
|
||||
...options,
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue