diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-05 18:08:56 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-05 18:08:56 +0300 |
commit | 61265b9f01c7db3d4f6e1266d165b1c85be7b9e7 (patch) | |
tree | b6589df984e18e3b008a155c8d9ffcae75cf7c91 /app/assets/javascripts/notes | |
parent | 5460c19548d3d3d2ff764ceff05c2b72aa2d3a32 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/notes')
12 files changed, 131 insertions, 12 deletions
diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue index 0e7ed854032..e4b191b55a7 100644 --- a/app/assets/javascripts/notes/components/discussion_filter.vue +++ b/app/assets/javascripts/notes/components/discussion_filter.vue @@ -5,6 +5,7 @@ import { getLocationHash, doesHashExistInUrl } from '../../lib/utils/url_utility import { DISCUSSION_FILTERS_DEFAULT_VALUE, HISTORY_ONLY_FILTER_VALUE, + COMMENTS_ONLY_FILTER_VALUE, DISCUSSION_TAB_LABEL, DISCUSSION_FILTER_TYPES, NOTE_UNDERSCORE, @@ -38,7 +39,7 @@ export default { }; }, computed: { - ...mapGetters(['getNotesDataByProp']), + ...mapGetters(['getNotesDataByProp', 'timelineEnabled']), currentFilter() { if (!this.currentValue) return this.filters[0]; return this.filters.find(filter => filter.value === this.currentValue); @@ -63,11 +64,20 @@ export default { window.removeEventListener('hashchange', this.handleLocationHash); }, methods: { - ...mapActions(['filterDiscussion', 'setCommentsDisabled', 'setTargetNoteHash']), + ...mapActions([ + 'filterDiscussion', + 'setCommentsDisabled', + 'setTargetNoteHash', + 'setTimelineView', + ]), selectFilter(value, persistFilter = true) { const filter = parseInt(value, 10); if (filter === this.currentValue) return; + + if (this.timelineEnabled && filter !== COMMENTS_ONLY_FILTER_VALUE) { + this.setTimelineView(false); + } this.currentValue = filter; this.filterDiscussion({ path: this.getNotesDataByProp('discussionsPath'), diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue index fb18be9386e..9eaa4e422d5 100644 --- a/app/assets/javascripts/notes/components/notes_app.vue +++ b/app/assets/javascripts/notes/components/notes_app.vue @@ -73,6 +73,7 @@ export default { 'userCanReply', 'discussionTabCounter', 'sortDirection', + 'timelineEnabled', ]), sortDirDesc() { return this.sortDirection === constants.DESC; @@ -95,7 +96,7 @@ export default { return this.discussions; }, canReply() { - return this.userCanReply && !this.commentsDisabled; + return this.userCanReply && !this.commentsDisabled && !this.timelineEnabled; }, slotKeys() { return this.sortDirDesc ? ['form', 'comments'] : ['comments', 'form']; @@ -252,7 +253,7 @@ export default { <ordered-layout :slot-keys="slotKeys"> <template #form> <comment-form - v-if="!commentsDisabled" + v-if="!(commentsDisabled || timelineEnabled)" class="js-comment-form" :noteable-type="noteableType" /> diff --git a/app/assets/javascripts/notes/components/sort_discussion.vue b/app/assets/javascripts/notes/components/sort_discussion.vue index 113c00ffe8e..c279a7107c7 100644 --- a/app/assets/javascripts/notes/components/sort_discussion.vue +++ b/app/assets/javascripts/notes/components/sort_discussion.vue @@ -20,7 +20,7 @@ export default { }, mixins: [Tracking.mixin()], computed: { - ...mapGetters(['sortDirection', 'noteableType']), + ...mapGetters(['sortDirection', 'persistSortOrder', 'noteableType']), selectedOption() { return SORT_OPTIONS.find(({ key }) => this.sortDirection === key); }, @@ -38,7 +38,7 @@ export default { return; } - this.setDiscussionSortDirection(direction); + this.setDiscussionSortDirection({ direction }); this.track('change_discussion_sort_direction', { property: direction }); }, isDropdownItemActive(sortDir) { @@ -53,7 +53,8 @@ export default { <local-storage-sync :value="sortDirection" :storage-key="storageKey" - @input="setDiscussionSortDirection" + :persist="persistSortOrder" + @input="setDiscussionSortDirection({ direction: $event })" /> <gl-dropdown :text="dropdownText" diff --git a/app/assets/javascripts/notes/components/timeline_toggle.vue b/app/assets/javascripts/notes/components/timeline_toggle.vue new file mode 100644 index 00000000000..735dc5ff2a8 --- /dev/null +++ b/app/assets/javascripts/notes/components/timeline_toggle.vue @@ -0,0 +1,55 @@ +<script> +import { GlButton, GlTooltipDirective } from '@gitlab/ui'; +import { mapActions, mapGetters } from 'vuex'; +import { s__ } from '~/locale'; +import { COMMENTS_ONLY_FILTER_VALUE, DESC } from '../constants'; +import notesEventHub from '../event_hub'; + +export const timelineEnabledTooltip = s__('Timeline|Turn timeline view off'); +export const timelineDisabledTooltip = s__('Timeline|Turn timeline view on'); + +export default { + components: { + GlButton, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + computed: { + ...mapGetters(['timelineEnabled', 'sortDirection']), + tooltip() { + return this.timelineEnabled ? timelineEnabledTooltip : timelineDisabledTooltip; + }, + }, + methods: { + ...mapActions(['setTimelineView', 'setDiscussionSortDirection']), + setSort() { + if (this.timelineEnabled && this.sortDirection !== DESC) { + this.setDiscussionSortDirection({ direction: DESC, persist: false }); + } + }, + setFilter() { + notesEventHub.$emit('dropdownSelect', COMMENTS_ONLY_FILTER_VALUE, false); + }, + toggleTimeline(event) { + event.currentTarget.blur(); + this.setTimelineView(!this.timelineEnabled); + this.setSort(); + this.setFilter(); + }, + }, +}; +</script> + +<template> + <gl-button + v-gl-tooltip + icon="comments" + size="small" + :selected="timelineEnabled" + :title="tooltip" + :aria-label="tooltip" + class="gl-mr-3" + @click="toggleTimeline" + /> +</template> diff --git a/app/assets/javascripts/notes/constants.js b/app/assets/javascripts/notes/constants.js index b81aae7c257..7acf2ad57c8 100644 --- a/app/assets/javascripts/notes/constants.js +++ b/app/assets/javascripts/notes/constants.js @@ -14,8 +14,9 @@ export const MERGE_REQUEST_NOTEABLE_TYPE = 'MergeRequest'; export const UNRESOLVE_NOTE_METHOD_NAME = 'delete'; export const RESOLVE_NOTE_METHOD_NAME = 'post'; export const DESCRIPTION_TYPE = 'changed the description'; -export const HISTORY_ONLY_FILTER_VALUE = 2; export const DISCUSSION_FILTERS_DEFAULT_VALUE = 0; +export const COMMENTS_ONLY_FILTER_VALUE = 1; +export const HISTORY_ONLY_FILTER_VALUE = 2; export const DISCUSSION_TAB_LABEL = 'show'; export const NOTE_UNDERSCORE = 'note_'; export const TIME_DIFFERENCE_VALUE = 10; diff --git a/app/assets/javascripts/notes/index.js b/app/assets/javascripts/notes/index.js index ca186123a83..3247a93f0a0 100644 --- a/app/assets/javascripts/notes/index.js +++ b/app/assets/javascripts/notes/index.js @@ -2,6 +2,7 @@ import Vue from 'vue'; import notesApp from './components/notes_app.vue'; import initDiscussionFilters from './discussion_filters'; import initSortDiscussions from './sort_discussions'; +import initTimelineToggle from './timeline'; import { store } from './stores'; document.addEventListener('DOMContentLoaded', () => { @@ -59,4 +60,5 @@ document.addEventListener('DOMContentLoaded', () => { initDiscussionFilters(store); initSortDiscussions(store); + initTimelineToggle(store); }); diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index 9c63a7e3cd4..37986c8a02d 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -99,8 +99,12 @@ export const updateDiscussion = ({ commit, state }, discussion) => { return utils.findNoteObjectById(state.discussions, discussion.id); }; -export const setDiscussionSortDirection = ({ commit }, direction) => { - commit(types.SET_DISCUSSIONS_SORT, direction); +export const setDiscussionSortDirection = ({ commit }, { direction, persist = true }) => { + commit(types.SET_DISCUSSIONS_SORT, { direction, persist }); +}; + +export const setTimelineView = ({ commit }, enabled) => { + commit(types.SET_TIMELINE_VIEW, enabled); }; export const setSelectedCommentPosition = ({ commit }, position) => { diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js index fbdb71925ea..5b3ffa425a0 100644 --- a/app/assets/javascripts/notes/stores/getters.js +++ b/app/assets/javascripts/notes/stores/getters.js @@ -5,6 +5,23 @@ import { collapseSystemNotes } from './collapse_utils'; export const discussions = state => { let discussionsInState = clone(state.discussions); // NOTE: not testing bc will be removed when backend is finished. + + if (state.isTimelineEnabled) { + discussionsInState = discussionsInState + .reduce((acc, discussion) => { + const transformedToIndividualNotes = discussion.notes.map(note => ({ + ...discussion, + id: note.id, + created_at: note.created_at, + individual_note: true, + notes: [note], + })); + + return acc.concat(transformedToIndividualNotes); + }, []) + .sort((a, b) => new Date(a.created_at) - new Date(b.created_at)); + } + if (state.discussionSortOrder === constants.DESC) { discussionsInState = discussionsInState.reverse(); } @@ -27,6 +44,10 @@ export const isNotesFetched = state => state.isNotesFetched; export const sortDirection = state => state.discussionSortOrder; +export const persistSortOrder = state => state.persistSortOrder; + +export const timelineEnabled = state => state.isTimelineEnabled; + export const isLoading = state => state.isLoading; export const getNotesDataByProp = state => prop => state.notesData[prop]; diff --git a/app/assets/javascripts/notes/stores/modules/index.js b/app/assets/javascripts/notes/stores/modules/index.js index 161c9b8b1b5..a8738fa7c5f 100644 --- a/app/assets/javascripts/notes/stores/modules/index.js +++ b/app/assets/javascripts/notes/stores/modules/index.js @@ -7,6 +7,7 @@ export default () => ({ state: { discussions: [], discussionSortOrder: ASC, + persistSortOrder: true, convertedDisscussionIds: [], targetNoteHash: null, lastFetchedAt: null, @@ -45,6 +46,7 @@ export default () => ({ resolvableDiscussionsCount: 0, unresolvedDiscussionsCount: 0, descriptionVersions: {}, + isTimelineEnabled: false, }, actions, getters, diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js index 23515cdd9e3..7496dd630f6 100644 --- a/app/assets/javascripts/notes/stores/mutation_types.js +++ b/app/assets/javascripts/notes/stores/mutation_types.js @@ -34,6 +34,7 @@ export const SET_EXPAND_DISCUSSIONS = 'SET_EXPAND_DISCUSSIONS'; export const UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS = 'UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS'; export const SET_CURRENT_DISCUSSION_ID = 'SET_CURRENT_DISCUSSION_ID'; export const SET_DISCUSSIONS_SORT = 'SET_DISCUSSIONS_SORT'; +export const SET_TIMELINE_VIEW = 'SET_TIMELINE_VIEW'; export const SET_SELECTED_COMMENT_POSITION = 'SET_SELECTED_COMMENT_POSITION'; export const SET_SELECTED_COMMENT_POSITION_HOVER = 'SET_SELECTED_COMMENT_POSITION_HOVER'; export const SET_FETCHING_DISCUSSIONS = 'SET_FETCHING_DISCUSSIONS'; diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index a8bd94cc763..6c11d53dba3 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -313,8 +313,13 @@ export default { discussion.truncated_diff_lines = utils.prepareDiffLines(diffLines); }, - [types.SET_DISCUSSIONS_SORT](state, sort) { - state.discussionSortOrder = sort; + [types.SET_DISCUSSIONS_SORT](state, { direction, persist }) { + state.discussionSortOrder = direction; + state.persistSortOrder = persist; + }, + + [types.SET_TIMELINE_VIEW](state, value) { + state.isTimelineEnabled = value; }, [types.SET_SELECTED_COMMENT_POSITION](state, position) { diff --git a/app/assets/javascripts/notes/timeline.js b/app/assets/javascripts/notes/timeline.js new file mode 100644 index 00000000000..df6d1b21400 --- /dev/null +++ b/app/assets/javascripts/notes/timeline.js @@ -0,0 +1,16 @@ +import Vue from 'vue'; +import TimelineToggle from './components/timeline_toggle.vue'; + +export default function initTimelineToggle(store) { + const el = document.getElementById('js-incidents-timeline-toggle'); + + if (!el) return null; + + return new Vue({ + el, + store, + render(createElement) { + return createElement(TimelineToggle); + }, + }); +} |