diff options
Diffstat (limited to 'app/assets/javascripts/admin/abuse_report/components')
12 files changed, 337 insertions, 39 deletions
diff --git a/app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue b/app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue index 3c46de7c2be..f0540ffa71e 100644 --- a/app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue +++ b/app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue @@ -7,6 +7,7 @@ import ReportDetails from './report_details.vue'; import ReportedContent from './reported_content.vue'; import ActivityEventsList from './activity_events_list.vue'; import ActivityHistoryItem from './activity_history_item.vue'; +import AbuseReportNotes from './abuse_report_notes.vue'; const alertDefaults = { visible: false, @@ -24,6 +25,7 @@ export default { ReportedContent, ActivityEventsList, ActivityHistoryItem, + AbuseReportNotes, }, mixins: [glFeatureFlagsMixin()], props: { @@ -96,5 +98,10 @@ export default { /> </template> </activity-events-list> + + <abuse-report-notes + v-if="glFeatures.abuseReportNotes" + :abuse-report-id="abuseReport.report.globalId" + /> </section> </template> diff --git a/app/assets/javascripts/admin/abuse_report/components/abuse_report_notes.vue b/app/assets/javascripts/admin/abuse_report/components/abuse_report_notes.vue new file mode 100644 index 00000000000..80af7d7400a --- /dev/null +++ b/app/assets/javascripts/admin/abuse_report/components/abuse_report_notes.vue @@ -0,0 +1,92 @@ +<script> +import { uniqueId } from 'lodash'; +import { __ } from '~/locale'; +import { createAlert } from '~/alert'; +import SkeletonLoadingContainer from '~/vue_shared/components/notes/skeleton_note.vue'; +import { SKELETON_NOTES_COUNT } from '~/admin/abuse_report/constants'; +import abuseReportNotesQuery from '../graphql/notes/abuse_report_notes.query.graphql'; +import AbuseReportDiscussion from './notes/abuse_report_discussion.vue'; + +export default { + name: 'AbuseReportNotes', + SKELETON_NOTES_COUNT, + i18n: { + fetchError: __('An error occurred while fetching comments, please try again.'), + }, + components: { + SkeletonLoadingContainer, + AbuseReportDiscussion, + }, + props: { + abuseReportId: { + type: String, + required: true, + }, + }, + data() { + return { + addNoteKey: uniqueId(`abuse-report-add-note-${this.abuseReportId}`), + }; + }, + apollo: { + abuseReportNotes: { + query: abuseReportNotesQuery, + variables() { + return { + id: this.abuseReportId, + }; + }, + update(data) { + return data.abuseReport?.discussions || []; + }, + skip() { + return !this.abuseReportId; + }, + error() { + createAlert({ message: this.$options.i18n.fetchError }); + }, + }, + }, + computed: { + initialLoading() { + return this.$apollo.queries.abuseReportNotes.loading; + }, + notesArray() { + return this.abuseReportNotes?.nodes || []; + }, + }, + methods: { + getDiscussionKey(discussion) { + const discussionId = discussion.notes.nodes[0].id; + return discussionId.split('/')[discussionId.split('/').length - 1]; + }, + }, +}; +</script> + +<template> + <div> + <div class="issuable-discussion gl-mb-5 gl-clearfix!"> + <template v-if="initialLoading"> + <ul class="notes main-notes-list timeline"> + <skeleton-loading-container + v-for="index in $options.SKELETON_NOTES_COUNT" + :key="index" + class="note-skeleton" + /> + </ul> + </template> + + <template v-else> + <ul class="notes main-notes-list timeline"> + <abuse-report-discussion + v-for="discussion in notesArray" + :key="getDiscussionKey(discussion)" + :discussion="discussion.notes.nodes" + :abuse-report-id="abuseReportId" + /> + </ul> + </template> + </div> + </div> +</template> diff --git a/app/assets/javascripts/admin/abuse_report/components/activity_events_list.vue b/app/assets/javascripts/admin/abuse_report/components/activity_events_list.vue index 8c4c1da28b8..2206e600543 100644 --- a/app/assets/javascripts/admin/abuse_report/components/activity_events_list.vue +++ b/app/assets/javascripts/admin/abuse_report/components/activity_events_list.vue @@ -11,7 +11,7 @@ export default { <!-- The styles `issuable-discussion`, `timeline`, `main-notes-list` and `notes` used below are declared in app/assets/stylesheets/pages/notes.scss --> <section class="gl-pt-6 issuable-discussion"> - <h2 class="gl-font-lg gl-mt-0 gl-mb-2">{{ $options.i18n.activity }}</h2> + <h2 class="gl-font-size-h1 gl-mt-0 gl-mb-4">{{ $options.i18n.activity }}</h2> <ul class="timeline main-notes-list notes"> <slot name="history-items"></slot> </ul> diff --git a/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report.query.graphql b/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report.query.graphql deleted file mode 100644 index f5b075cb9af..00000000000 --- a/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report.query.graphql +++ /dev/null @@ -1,13 +0,0 @@ -query abuseReportQuery($id: AbuseReportID!) { - abuseReport(id: $id) { - labels { - nodes { - id - title - description - color - textColor - } - } - } -} diff --git a/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql b/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql deleted file mode 100644 index 4e724b4db2c..00000000000 --- a/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql +++ /dev/null @@ -1,11 +0,0 @@ -query abuseReportLabelsQuery($searchTerm: String) { - labels: abuseReportLabels(searchTerm: $searchTerm) { - nodes { - id - title - description - color - textColor - } - } -} diff --git a/app/assets/javascripts/admin/abuse_report/components/graphql/create_abuse_report_label.mutation.graphql b/app/assets/javascripts/admin/abuse_report/components/graphql/create_abuse_report_label.mutation.graphql deleted file mode 100644 index 0781b8e634b..00000000000 --- a/app/assets/javascripts/admin/abuse_report/components/graphql/create_abuse_report_label.mutation.graphql +++ /dev/null @@ -1,10 +0,0 @@ -#import "~/graphql_shared/fragments/label.fragment.graphql" - -mutation createAbuseReportLabel($title: String!, $color: String) { - labelCreate: abuseReportLabelCreate(input: { title: $title, color: $color }) { - label { - ...Label - } - errors - } -} diff --git a/app/assets/javascripts/admin/abuse_report/components/labels_select.vue b/app/assets/javascripts/admin/abuse_report/components/labels_select.vue index 747c9a1a947..d2d143f0460 100644 --- a/app/assets/javascripts/admin/abuse_report/components/labels_select.vue +++ b/app/assets/javascripts/admin/abuse_report/components/labels_select.vue @@ -11,7 +11,7 @@ import DropdownContentsCreateView from '~/sidebar/components/labels/labels_selec import DropdownHeader from '~/sidebar/components/labels/labels_select_widget/dropdown_header.vue'; import DropdownFooter from '~/sidebar/components/labels/labels_select_widget/dropdown_footer.vue'; import DropdownWidget from '~/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue'; -import abuseReportLabelsQuery from './graphql/abuse_report_labels.query.graphql'; +import abuseReportLabelsQuery from '../graphql/abuse_report_labels.query.graphql'; export default { components: { diff --git a/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_discussion.vue b/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_discussion.vue new file mode 100644 index 00000000000..4d24471fa43 --- /dev/null +++ b/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_discussion.vue @@ -0,0 +1,104 @@ +<script> +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; +import DiscussionNotesRepliesWrapper from '~/notes/components/discussion_notes_replies_wrapper.vue'; +import ToggleRepliesWidget from '~/notes/components/toggle_replies_widget.vue'; +import AbuseReportNote from './abuse_report_note.vue'; + +export default { + name: 'AbuseReportDiscussion', + components: { + TimelineEntryItem, + DiscussionNotesRepliesWrapper, + ToggleRepliesWidget, + AbuseReportNote, + }, + props: { + abuseReportId: { + type: String, + required: true, + }, + discussion: { + type: Array, + required: true, + }, + }, + data() { + return { + isExpanded: true, + }; + }, + computed: { + note() { + return this.discussion[0]; + }, + noteId() { + return getIdFromGraphQLId(this.note.id); + }, + replies() { + if (this.discussion?.length > 1) { + return this.discussion.slice(1); + } + return null; + }, + hasReplies() { + return Boolean(this.replies?.length); + }, + discussionId() { + return this.discussion[0]?.discussion?.id || ''; + }, + }, + methods: { + toggleDiscussion() { + this.isExpanded = !this.isExpanded; + }, + }, +}; +</script> + +<template> + <abuse-report-note + v-if="!hasReplies" + :note="note" + :abuse-report-id="abuseReportId" + class="gl-mb-4" + /> + <timeline-entry-item v-else :data-note-id="noteId" class="note note-discussion gl-px-0"> + <div class="timeline-content"> + <div class="discussion"> + <div class="discussion-body"> + <div class="discussion-wrapper"> + <div class="discussion-notes"> + <ul class="notes"> + <abuse-report-note + :note="note" + :discussion-id="discussionId" + :abuse-report-id="abuseReportId" + class="gl-mb-4" + /> + <discussion-notes-replies-wrapper> + <toggle-replies-widget + v-if="hasReplies" + :collapsed="!isExpanded" + :replies="replies" + @toggle="toggleDiscussion({ discussionId })" + /> + <template v-if="isExpanded"> + <template v-for="reply in replies"> + <abuse-report-note + :key="reply.id" + :discussion-id="discussionId" + :note="reply" + :abuse-report-id="abuseReportId" + /> + </template> + </template> + </discussion-notes-replies-wrapper> + </ul> + </div> + </div> + </div> + </div> + </div> + </timeline-entry-item> +</template> diff --git a/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_note.vue b/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_note.vue new file mode 100644 index 00000000000..6da3017e11e --- /dev/null +++ b/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_note.vue @@ -0,0 +1,81 @@ +<script> +import { GlAvatarLink, GlAvatar } from '@gitlab/ui'; +import SafeHtml from '~/vue_shared/directives/safe_html'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; +import NoteHeader from '~/notes/components/note_header.vue'; +import NoteBody from './abuse_report_note_body.vue'; + +export default { + name: 'AbuseReportNote', + directives: { + SafeHtml, + }, + components: { + GlAvatarLink, + GlAvatar, + TimelineEntryItem, + NoteHeader, + NoteBody, + }, + props: { + abuseReportId: { + type: String, + required: true, + }, + note: { + type: Object, + required: true, + }, + }, + computed: { + noteAnchorId() { + return `note_${getIdFromGraphQLId(this.note.id)}`; + }, + author() { + return this.note.author; + }, + authorId() { + return getIdFromGraphQLId(this.author.id); + }, + }, +}; +</script> + +<template> + <timeline-entry-item :id="noteAnchorId" class="note note-wrapper note-comment"> + <div :key="note.id" class="timeline-avatar gl-float-left"> + <gl-avatar-link + :href="author.webUrl" + :data-user-id="authorId" + :data-username="author.username" + class="js-user-link" + > + <gl-avatar + :src="author.avatarUrl" + :entity-name="author.username" + :alt="author.name" + :size="32" + /> + </gl-avatar-link> + </div> + <div class="timeline-content"> + <div data-testid="note-wrapper"> + <div class="note-header"> + <note-header + :author="author" + :created-at="note.createdAt" + :note-id="note.id" + :note-url="note.url" + > + <span v-if="note.createdAt" class="d-none d-sm-inline">·</span> + </note-header> + </div> + + <div class="timeline-discussion-body"> + <note-body ref="noteBody" :note="note" /> + </div> + </div> + </div> + </timeline-entry-item> +</template> diff --git a/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_note_body.vue b/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_note_body.vue new file mode 100644 index 00000000000..ab3d7f5fa6c --- /dev/null +++ b/app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_note_body.vue @@ -0,0 +1,48 @@ +<script> +import SafeHtml from '~/vue_shared/directives/safe_html'; +import { renderGFM } from '~/behaviors/markdown/render_gfm'; + +export default { + name: 'AbuseReportNoteBody', + directives: { + SafeHtml, + }, + props: { + note: { + type: Object, + required: true, + }, + }, + watch: { + 'note.bodyHtml': { + immediate: true, + async handler(newVal, oldVal) { + if (newVal === oldVal) { + return; + } + await this.$nextTick(); + this.renderGFM(); + }, + }, + }, + methods: { + renderGFM() { + renderGFM(this.$refs['note-body']); + gl?.lazyLoader?.searchLazyImages(); + }, + }, + safeHtmlConfig: { + ADD_TAGS: ['use', 'gl-emoji', 'copy-code'], + }, +}; +</script> + +<template> + <div ref="note-body" class="note-body"> + <div + v-safe-html:[$options.safeHtmlConfig]="note.bodyHtml" + class="note-text md" + data-testid="abuse-report-note-body" + ></div> + </div> +</template> diff --git a/app/assets/javascripts/admin/abuse_report/components/report_details.vue b/app/assets/javascripts/admin/abuse_report/components/report_details.vue index 10e1dca7f91..89017e6cbd4 100644 --- a/app/assets/javascripts/admin/abuse_report/components/report_details.vue +++ b/app/assets/javascripts/admin/abuse_report/components/report_details.vue @@ -1,8 +1,8 @@ <script> import { __ } from '~/locale'; import { createAlert } from '~/alert'; +import abuseReportQuery from '../graphql/abuse_report.query.graphql'; import LabelsSelect from './labels_select.vue'; -import abuseReportQuery from './graphql/abuse_report.query.graphql'; export default { name: 'ReportDetails', diff --git a/app/assets/javascripts/admin/abuse_report/components/reported_content.vue b/app/assets/javascripts/admin/abuse_report/components/reported_content.vue index 84d6f25ac05..99c8b3ece10 100644 --- a/app/assets/javascripts/admin/abuse_report/components/reported_content.vue +++ b/app/assets/javascripts/admin/abuse_report/components/reported_content.vue @@ -67,7 +67,7 @@ export default { <div class="gl-pb-3 gl-display-flex gl-justify-content-space-between gl-xs-flex-direction-column gl-align-items-center" > - <h2 class="gl-font-lg gl-mt-2 gl-mb-2"> + <h2 class="gl-font-size-h1 gl-mt-2 gl-mb-2"> {{ $options.i18n.reportTypes[reportType] }} </h2> @@ -128,7 +128,7 @@ export default { </gl-link> <time-ago-tooltip :time="report.reportedAt" - class="gl-ml-3 gl-text-secondary gl-xs-w-full" + class="gl-ml-3 gl-text-secondary gl-w-full gl-sm-w-auto" /> </div> </div> |