diff --git a/app/assets/javascripts/batch_comments/components/diff_file_drafts.vue b/app/assets/javascripts/batch_comments/components/diff_file_drafts.vue index 671cb8f7f47916dafa6408e59200b7a8dcf3e3ea..b16f903f8514aa3ca17ab64d8c1d0915639a5c79 100644 --- a/app/assets/javascripts/batch_comments/components/diff_file_drafts.vue +++ b/app/assets/javascripts/batch_comments/components/diff_file_drafts.vue @@ -1,8 +1,8 @@ <script> -// eslint-disable-next-line no-restricted-imports -import { mapGetters } from 'vuex'; +import { mapState } from 'pinia'; import imageDiff from '~/diffs/mixins/image_diff'; import DesignNotePin from '~/vue_shared/components/design_management/design_note_pin.vue'; +import { useBatchComments } from '~/batch_comments/store'; import DraftNote from './draft_note.vue'; export default { @@ -33,7 +33,7 @@ export default { }, }, computed: { - ...mapGetters('batchComments', ['draftsForFile']), + ...mapState(useBatchComments, ['draftsForFile']), drafts() { return this.draftsForFile(this.fileHash).filter( (f) => f.position?.position_type === this.positionType, diff --git a/app/assets/javascripts/batch_comments/components/draft_note.vue b/app/assets/javascripts/batch_comments/components/draft_note.vue index c015aa0affce4954940775f64a6a5325ac416b3d..051ea16459936f4662823d7bac914dd8d0eb30df 100644 --- a/app/assets/javascripts/batch_comments/components/draft_note.vue +++ b/app/assets/javascripts/batch_comments/components/draft_note.vue @@ -1,11 +1,13 @@ <script> import { GlBadge, GlTooltipDirective } from '@gitlab/ui'; // eslint-disable-next-line no-restricted-imports -import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'; +import { mapActions as mapVuexActions } from 'vuex'; +import { mapActions, mapState } from 'pinia'; import SafeHtml from '~/vue_shared/directives/safe_html'; import NoteableNote from '~/notes/components/noteable_note.vue'; import * as types from '~/batch_comments/stores/modules/batch_comments/mutation_types'; import { clearDraft } from '~/lib/utils/autosave'; +import { useBatchComments } from '~/batch_comments/store'; export default { components: { @@ -43,8 +45,7 @@ export default { }; }, computed: { - ...mapState('batchComments', ['isPublishing']), - ...mapGetters('batchComments', ['isPublishingDraft']), + ...mapState(useBatchComments, ['isPublishing', 'isPublishingDraft']), draftCommands() { return this.draft.references.commands; }, @@ -59,17 +60,17 @@ export default { } }, methods: { - ...mapActions('batchComments', [ + ...mapActions(useBatchComments, [ 'deleteDraft', 'updateDraft', 'publishSingleDraft', 'scrollToDraft', 'toggleResolveDiscussion', ]), - ...mapMutations('batchComments', { + ...mapActions(useBatchComments, { setDraftEditing: types.SET_DRAFT_EDITING, }), - ...mapActions(['setSelectedCommentPositionHover']), + ...mapVuexActions(['setSelectedCommentPositionHover']), update(data) { this.updateDraft(data); }, diff --git a/app/assets/javascripts/batch_comments/components/drafts_count.vue b/app/assets/javascripts/batch_comments/components/drafts_count.vue index 2430b5e5a5a652338a1a64b92d6540bc7bb7c0a8..d857b89f0fc844f167bc9b1b52ecfc997a38106b 100644 --- a/app/assets/javascripts/batch_comments/components/drafts_count.vue +++ b/app/assets/javascripts/batch_comments/components/drafts_count.vue @@ -1,7 +1,7 @@ <script> import { GlBadge } from '@gitlab/ui'; -// eslint-disable-next-line no-restricted-imports -import { mapGetters } from 'vuex'; +import { mapState } from 'pinia'; +import { useBatchComments } from '~/batch_comments/store'; export default { components: { @@ -15,7 +15,7 @@ export default { }, }, computed: { - ...mapGetters('batchComments', ['draftsCount']), + ...mapState(useBatchComments, ['draftsCount']), }, }; </script> diff --git a/app/assets/javascripts/batch_comments/components/preview_dropdown.vue b/app/assets/javascripts/batch_comments/components/preview_dropdown.vue index 63b536a76047f2756cdd065cef81da08c56e1114..93c394943befd3b1a18d535f92d74dcee43039a3 100644 --- a/app/assets/javascripts/batch_comments/components/preview_dropdown.vue +++ b/app/assets/javascripts/batch_comments/components/preview_dropdown.vue @@ -1,8 +1,14 @@ <script> import { GlIcon, GlDisclosureDropdown, GlButton } from '@gitlab/ui'; +import { mapState, mapActions } from 'pinia'; // eslint-disable-next-line no-restricted-imports -import { mapActions, mapGetters, mapState } from 'vuex'; +import { + mapActions as mapVuexActions, + mapGetters as mapVuexGetters, + mapState as mapVuexState, +} from 'vuex'; import { setUrlParams, visitUrl } from '~/lib/utils/url_utility'; +import { useBatchComments } from '~/batch_comments/store'; import PreviewItem from './preview_item.vue'; import DraftsCount from './drafts_count.vue'; @@ -15,9 +21,9 @@ export default { GlButton, }, computed: { - ...mapState('diffs', ['viewDiffsFileByFile']), - ...mapGetters('batchComments', ['draftsCount', 'sortedDrafts']), - ...mapGetters(['getNoteableData']), + ...mapVuexState('diffs', ['viewDiffsFileByFile']), + ...mapState(useBatchComments, ['draftsCount', 'sortedDrafts']), + ...mapVuexGetters(['getNoteableData']), listItems() { const sortedDraftCount = this.sortedDrafts.length - 1; return this.sortedDrafts.map((item, index) => ({ @@ -31,8 +37,8 @@ export default { }, }, methods: { - ...mapActions('diffs', ['goToFile']), - ...mapActions('batchComments', ['scrollToDraft']), + ...mapVuexActions('diffs', ['goToFile']), + ...mapActions(useBatchComments, ['scrollToDraft']), isOnLatestDiff(draft) { return draft.position?.head_sha === this.getNoteableData.diff_head_sha; }, diff --git a/app/assets/javascripts/batch_comments/components/review_bar.vue b/app/assets/javascripts/batch_comments/components/review_bar.vue index 46906a5a2a89b7689f9b40916ea9df11f218e794..9406090cede6c952686a647633f23dd85ccfecd6 100644 --- a/app/assets/javascripts/batch_comments/components/review_bar.vue +++ b/app/assets/javascripts/batch_comments/components/review_bar.vue @@ -1,10 +1,12 @@ <script> +import { mapActions } from 'pinia'; // eslint-disable-next-line no-restricted-imports -import { mapActions, mapGetters } from 'vuex'; +import { mapGetters as mapVuexGetters } from 'vuex'; import { GlButton, GlTooltipDirective as GlTooltip, GlModal } from '@gitlab/ui'; import { __ } from '~/locale'; import toast from '~/vue_shared/plugins/global_toast'; import { SET_REVIEW_BAR_RENDERED } from '~/batch_comments/stores/modules/batch_comments/mutation_types'; +import { useBatchComments } from '~/batch_comments/store'; import { REVIEW_BAR_VISIBLE_CLASS_NAME } from '../constants'; import PreviewDropdown from './preview_dropdown.vue'; import SubmitDropdown from './submit_dropdown.vue'; @@ -26,7 +28,7 @@ export default { }; }, computed: { - ...mapGetters(['isNotesFetched']), + ...mapVuexGetters(['isNotesFetched']), }, watch: { isNotesFetched() { @@ -37,13 +39,13 @@ export default { }, mounted() { document.body.classList.add(REVIEW_BAR_VISIBLE_CLASS_NAME); - this.$store.commit(`batchComments/${SET_REVIEW_BAR_RENDERED}`); + useBatchComments()[SET_REVIEW_BAR_RENDERED](); }, beforeDestroy() { document.body.classList.remove(REVIEW_BAR_VISIBLE_CLASS_NAME); }, methods: { - ...mapActions('batchComments', ['expandAllDiscussions', 'discardDrafts']), + ...mapActions(useBatchComments, ['expandAllDiscussions', 'discardDrafts']), async discardReviews() { this.discarding = true; diff --git a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue index d4d623c4fc8cb773830d077f9d5fdfbf760c1c22..7912d8e4fc997d4a70078697c32fb45c62ddf305 100644 --- a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue +++ b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue @@ -7,8 +7,9 @@ import { GlFormRadioGroup, GlLoadingIcon, } from '@gitlab/ui'; +import { mapActions, mapState } from 'pinia'; // eslint-disable-next-line no-restricted-imports -import { mapGetters, mapActions, mapState } from 'vuex'; +import { mapGetters as mapVuexGetters, mapState as mapVuexState } from 'vuex'; import { __ } from '~/locale'; import { createAlert } from '~/alert'; import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue'; @@ -19,6 +20,7 @@ import { CLEAR_AUTOSAVE_ENTRY_EVENT, CONTENT_EDITOR_PASTE } from '~/vue_shared/c import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub'; import { trackSavedUsingEditor } from '~/vue_shared/components/markdown/tracking'; import { updateText } from '~/lib/utils/text_markdown'; +import { useBatchComments } from '~/batch_comments/store'; import userCanApproveQuery from '../queries/can_approve.query.graphql'; export default { @@ -78,9 +80,14 @@ export default { }; }, computed: { - ...mapGetters(['getNotesData', 'getNoteableData', 'noteableType', 'getCurrentUserLastNote']), - ...mapState('batchComments', ['shouldAnimateReviewButton']), - ...mapState('diffs', ['projectPath']), + ...mapVuexGetters([ + 'getNotesData', + 'getNoteableData', + 'noteableType', + 'getCurrentUserLastNote', + ]), + ...mapState(useBatchComments, ['shouldAnimateReviewButton']), + ...mapVuexState('diffs', ['projectPath']), autocompleteDataSources() { return gl.GfmAutoComplete?.dataSources; }, @@ -138,7 +145,7 @@ export default { this.noteData.noteable_id = this.getNoteableData.id; }, methods: { - ...mapActions('batchComments', ['publishReview', 'clearDrafts']), + ...mapActions(useBatchComments, ['publishReview', 'clearDrafts']), repositionDropdown() { this.$refs.submitDropdown?.$refs.dropdown?.updatePopper(); }, @@ -151,7 +158,7 @@ export default { try { const { note, reviewer_state: reviewerState } = this.noteData; - await this.publishReview(this.noteData); + await this.publishReview({ ...this.noteData }); markdownEditorEventHub.$emit(CLEAR_AUTOSAVE_ENTRY_EVENT, this.autosaveKey); diff --git a/app/assets/javascripts/batch_comments/index.js b/app/assets/javascripts/batch_comments/index.js index daed6906a09e486fa97b8af71011358bb779414d..a07093139c174bd799a6264f771f6e3f7ca3e45c 100644 --- a/app/assets/javascripts/batch_comments/index.js +++ b/app/assets/javascripts/batch_comments/index.js @@ -1,11 +1,11 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; -// eslint-disable-next-line no-restricted-imports -import { mapActions, mapGetters } from 'vuex'; +import { mapActions, mapState } from 'pinia'; import { parseBoolean } from '~/lib/utils/common_utils'; import { apolloProvider } from '~/graphql_shared/issuable_client'; import store from '~/mr_notes/stores'; import { pinia } from '~/pinia/instance'; +import { useBatchComments } from '~/batch_comments/store'; export const initReviewBar = () => { const el = document.getElementById('js-review-bar'); @@ -28,13 +28,13 @@ export const initReviewBar = () => { canSummarize: parseBoolean(el.dataset.canSummarize), }, computed: { - ...mapGetters('batchComments', ['draftsCount']), + ...mapState(useBatchComments, ['draftsCount']), }, mounted() { this.fetchDrafts(); }, methods: { - ...mapActions('batchComments', ['fetchDrafts']), + ...mapActions(useBatchComments, ['fetchDrafts']), }, render(createElement) { if (this.draftsCount === 0) return null; diff --git a/app/assets/javascripts/batch_comments/store/index.js b/app/assets/javascripts/batch_comments/store/index.js index 67eb044679a6dd5b2209ff1eafabe454cfcf07ef..1522056476bfc57870513b627f9b46a5a7af891e 100644 --- a/app/assets/javascripts/batch_comments/store/index.js +++ b/app/assets/javascripts/batch_comments/store/index.js @@ -11,13 +11,13 @@ export const useBatchComments = defineStore('batchComments', { }, state() { return { - withBatchComments: true, isDraftsFetched: false, drafts: [], isPublishing: false, currentlyPublishingDrafts: [], shouldAnimateReviewButton: false, reviewBarRendered: false, + isMergeRequest: false, }; }, actions: { diff --git a/app/assets/javascripts/batch_comments/store/state.js b/app/assets/javascripts/batch_comments/store/state.js deleted file mode 100644 index 1efc00059d0828d61da5574d9574b07d5c6b626b..0000000000000000000000000000000000000000 --- a/app/assets/javascripts/batch_comments/store/state.js +++ /dev/null @@ -1,9 +0,0 @@ -export default () => ({ - withBatchComments: true, - isDraftsFetched: false, - drafts: [], - isPublishing: false, - currentlyPublishingDrafts: [], - shouldAnimateReviewButton: false, - reviewBarRendered: false, -}); diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js index 1efc00059d0828d61da5574d9574b07d5c6b626b..ed9dfb7f053356327c5788787f89948b5b3de661 100644 --- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js +++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js @@ -1,9 +1,9 @@ export default () => ({ - withBatchComments: true, isDraftsFetched: false, drafts: [], isPublishing: false, currentlyPublishingDrafts: [], shouldAnimateReviewButton: false, reviewBarRendered: false, + isMergeRequest: false, }); diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 0897c3184519f749230fc99bbfadd101c936dd54..c6aadaee3efe08e1beba15bba99a3c44fb99c7a9 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -27,10 +27,6 @@ import { __ } from '~/locale'; import notesEventHub from '~/notes/event_hub'; import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller'; import getMRCodequalityAndSecurityReports from 'ee_else_ce/diffs/components/graphql/get_mr_codequality_and_security_reports.query.graphql'; -import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; -import { useNotes } from '~/notes/store/legacy_notes'; -import { useBatchComments } from '~/batch_comments/store'; -import { useMrNotes } from '~/mr_notes/store/legacy_mr_notes'; import { sortFindingsByFile } from '../utils/sort_findings_by_file'; import { MR_TREE_SHOW_KEY, @@ -416,12 +412,6 @@ export default { diffsApp.instrument(); }, created() { - // Pinia stores must be initialized manually during migration, otherwise they won't sync with Vuex - useNotes(); - useLegacyDiffs(); - useBatchComments(); - useMrNotes(); - this.adjustView(); this.subscribeToEvents(); diff --git a/app/assets/javascripts/diffs/components/tree_list_height.vue b/app/assets/javascripts/diffs/components/tree_list_height.vue index 816dbf56e76e9f93c91140c8f494ce7e233b6bd4..c5fc225d7dcf38bb726c72cf66805cda8911162f 100644 --- a/app/assets/javascripts/diffs/components/tree_list_height.vue +++ b/app/assets/javascripts/diffs/components/tree_list_height.vue @@ -1,8 +1,8 @@ <script> import { debounce } from 'lodash'; -// eslint-disable-next-line no-restricted-imports -import { mapState, mapGetters } from 'vuex'; +import { mapState } from 'pinia'; import { contentTop } from '~/lib/utils/common_utils'; +import { useBatchComments } from '~/batch_comments/store'; const MAX_ITEMS_ON_NARROW_SCREEN = 8; // Should be enough for the very long titles (10+ lines) on the max smallest screen @@ -28,8 +28,7 @@ export default { }; }, computed: { - ...mapState('batchComments', ['reviewBarRendered']), - ...mapGetters('batchComments', ['draftsCount']), + ...mapState(useBatchComments, ['reviewBarRendered', 'draftsCount']), reviewBarEnabled() { return this.draftsCount > 0; }, diff --git a/app/assets/javascripts/diffs/mixins/draft_comments.js b/app/assets/javascripts/diffs/mixins/draft_comments.js index 4d54dcfa765dc973afbf55dceb50ce89a5b47333..44c4aa1533da826d3d3fdf9bd4d8d47b0e0b54ac 100644 --- a/app/assets/javascripts/diffs/mixins/draft_comments.js +++ b/app/assets/javascripts/diffs/mixins/draft_comments.js @@ -1,10 +1,10 @@ -// eslint-disable-next-line no-restricted-imports -import { mapGetters } from 'vuex'; +import { mapState } from 'pinia'; +import { useBatchComments } from '~/batch_comments/store'; import { IMAGE_DIFF_POSITION_TYPE } from '../constants'; export default { computed: { - ...mapGetters('batchComments', [ + ...mapState(useBatchComments, [ 'shouldRenderDraftRow', 'shouldRenderParallelDraftRow', 'draftsForLine', diff --git a/app/assets/javascripts/mr_notes/init.js b/app/assets/javascripts/mr_notes/init.js index ef621f4d98803301cb6b6bf9a54fc1b1803b1e81..5fa6e35a0273dfdca4325b3d18e9715536262776 100644 --- a/app/assets/javascripts/mr_notes/init.js +++ b/app/assets/javascripts/mr_notes/init.js @@ -8,6 +8,11 @@ import { initOverviewTabCounter } from '~/mr_notes/init_count'; import { getDerivedMergeRequestInformation } from '~/diffs/utils/merge_request'; import { getReviewsForMergeRequest } from '~/diffs/utils/file_reviews'; import { DIFF_VIEW_COOKIE_NAME, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useBatchComments } from '~/batch_comments/store'; +import { useMrNotes } from '~/mr_notes/store/legacy_mr_notes'; +import { pinia } from '~/pinia/instance'; function setupMrNotesState(store, notesDataset, diffsDataset) { const noteableData = JSON.parse(notesDataset.noteableData); @@ -45,6 +50,12 @@ function setupMrNotesState(store, notesDataset, diffsDataset) { } export function initMrStateLazyLoad(store = mrNotes) { + // Pinia stores must be initialized manually during migration, otherwise they won't sync with Vuex + useNotes(pinia); + useLegacyDiffs(pinia); + useBatchComments(pinia).$patch({ isMergeRequest: true }); + useMrNotes(pinia); + store.dispatch('setActiveTab', window.mrTabs.getCurrentAction()); window.mrTabs.eventHub.$on('MergeRequestTabChange', (value) => store.dispatch('setActiveTab', value), diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 0a7603887970f8af1e709e02b8fd23f57cd02d25..34589fab688873239bd22ec9dc55bb845c2e06c8 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -1,12 +1,14 @@ <script> import { GlButton, GlSprintf, GlLink, GlFormCheckbox } from '@gitlab/ui'; +import { mapState } from 'pinia'; // eslint-disable-next-line no-restricted-imports -import { mapGetters, mapActions, mapState } from 'vuex'; +import { mapGetters as mapVuexGetters, mapActions as mapVuexActions } from 'vuex'; import { mergeUrlParams } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import glAbilitiesMixin from '~/vue_shared/mixins/gl_abilities_mixin'; import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue'; import { trackSavedUsingEditor } from '~/vue_shared/components/markdown/tracking'; +import { useBatchComments } from '~/batch_comments/store'; import eventHub from '../event_hub'; import issuableStateMixin from '../mixins/issuable_state'; import resolvable from '../mixins/resolvable'; @@ -134,22 +136,19 @@ export default { }; }, computed: { - ...mapGetters([ + ...mapVuexGetters([ 'getDiscussionLastNote', 'getNoteableData', 'getNoteableDataByProp', 'getNotesDataByProp', 'getUserDataByProp', ]), - ...mapState({ - withBatchComments: (state) => state.batchComments?.withBatchComments, - }), - ...mapGetters('batchComments', ['hasDrafts']), + ...mapState(useBatchComments, ['hasDrafts', 'withBatchComments', 'isMergeRequest']), autocompleteDataSources() { return gl.GfmAutoComplete?.dataSources; }, showBatchCommentsActions() { - return this.withBatchComments && this.noteId === '' && !this.discussion.for_commit; + return this.isMergeRequest && this.noteId === '' && !this.discussion.for_commit; }, showResolveDiscussionToggle() { if (!this.discussion?.notes) return false; @@ -268,7 +267,7 @@ export default { this.updatePlaceholder(); }, methods: { - ...mapActions(['toggleResolveNote']), + ...mapVuexActions(['toggleResolveNote']), shouldToggleResolved(beforeSubmitDiscussionState) { return ( this.showResolveDiscussionToggle && beforeSubmitDiscussionState !== this.newResolvedState() diff --git a/app/assets/javascripts/notes/index.js b/app/assets/javascripts/notes/index.js index 0931d404be06cb5b0ee39e568309b07cbfbf00d9..035673ffec993ff78b611b67f6173ab1a8ed6c98 100644 --- a/app/assets/javascripts/notes/index.js +++ b/app/assets/javascripts/notes/index.js @@ -4,6 +4,7 @@ import { apolloProvider } from '~/graphql_shared/issuable_client'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { parseBoolean } from '~/lib/utils/common_utils'; import { getLocationHash } from '~/lib/utils/url_utility'; +import { pinia } from '~/pinia/instance'; import NotesApp from './components/notes_app.vue'; import { store } from './stores'; import { getNotesFilterData } from './utils/get_notes_filter_data'; @@ -55,6 +56,7 @@ export default ({ editorAiActions = [] } = {}) => { NotesApp, }, store, + pinia, apolloProvider, provide: { showTimelineViewToggle, diff --git a/app/assets/javascripts/notes/mixins/diff_line_note_form.js b/app/assets/javascripts/notes/mixins/diff_line_note_form.js index c0d6536a07b7347efc341388328add21931d5851..26d575825d6241f34f4f5ab91588579554778427 100644 --- a/app/assets/javascripts/notes/mixins/diff_line_note_form.js +++ b/app/assets/javascripts/notes/mixins/diff_line_note_form.js @@ -1,5 +1,10 @@ +import { mapState, mapActions } from 'pinia'; // eslint-disable-next-line no-restricted-imports -import { mapActions, mapGetters, mapState } from 'vuex'; +import { + mapActions as mapVuexActions, + mapGetters as mapVuexGetters, + mapState as mapVuexState, +} from 'vuex'; import { getDraftReplyFormData, getDraftFormData } from '~/batch_comments/utils'; import { TEXT_DIFF_POSITION_TYPE, @@ -11,21 +16,25 @@ import { clearDraft } from '~/lib/utils/autosave'; import { sprintf } from '~/locale'; import { formatLineRange } from '~/notes/components/multiline_comment_utils'; import { SAVING_THE_COMMENT_FAILED, SOMETHING_WENT_WRONG } from '~/diffs/i18n'; +import { useBatchComments } from '~/batch_comments/store'; export default { computed: { - ...mapState({ + ...mapVuexState({ noteableData: (state) => state.notes.noteableData, notesData: (state) => state.notes.notesData, - withBatchComments: (state) => state.batchComments?.withBatchComments, }), - ...mapGetters('diffs', ['getDiffFileByHash']), - ...mapGetters('batchComments', ['shouldRenderDraftRowInDiscussion', 'draftForDiscussion']), - ...mapState('diffs', ['commit', 'showWhitespace']), + ...mapVuexGetters('diffs', ['getDiffFileByHash']), + ...mapState(useBatchComments, [ + 'shouldRenderDraftRowInDiscussion', + 'draftForDiscussion', + 'isMergeRequest', + ]), + ...mapVuexState('diffs', ['commit', 'showWhitespace']), }, methods: { - ...mapActions('diffs', ['cancelCommentForm', 'toggleFileCommentForm']), - ...mapActions('batchComments', ['addDraftToReview', 'saveDraft', 'insertDraftIntoDrafts']), + ...mapVuexActions('diffs', ['cancelCommentForm', 'toggleFileCommentForm']), + ...mapActions(useBatchComments, ['addDraftToReview', 'saveDraft', 'insertDraftIntoDrafts']), // eslint-disable-next-line max-params addReplyToReview(noteText, isResolving, parentElement, errorCallback) { const postData = getDraftReplyFormData({ @@ -129,7 +138,7 @@ export default { }); }, showDraft(replyId) { - return this.withBatchComments && this.shouldRenderDraftRowInDiscussion(replyId); + return this.isMergeRequest && this.shouldRenderDraftRowInDiscussion(replyId); }, }, }; diff --git a/app/assets/javascripts/pinia/instance.js b/app/assets/javascripts/pinia/instance.js index 0a167472926d9b341f3a813c7c6766e58df37d85..74178e54bb885fea40e2de81fefc998062fd9304 100644 --- a/app/assets/javascripts/pinia/instance.js +++ b/app/assets/javascripts/pinia/instance.js @@ -1,11 +1,12 @@ import Vue from 'vue'; import { createPinia, PiniaVuePlugin } from 'pinia'; -import { syncWithVuex } from '~/pinia/plugins'; +import { globalAccessorPlugin, syncWithVuex } from '~/pinia/plugins'; Vue.use(PiniaVuePlugin); const pinia = createPinia(); pinia.use(syncWithVuex); +pinia.use(globalAccessorPlugin); export { pinia }; diff --git a/ee/spec/frontend/batch_comments/components/submit_dropdown_spec.js b/ee/spec/frontend/batch_comments/components/submit_dropdown_spec.js index f395c1d6c257a2e78145690d2fb8a90f1c0eff9d..df40e9c5db85f69366da9c7cf0d54d11178389c9 100644 --- a/ee/spec/frontend/batch_comments/components/submit_dropdown_spec.js +++ b/ee/spec/frontend/batch_comments/components/submit_dropdown_spec.js @@ -3,6 +3,8 @@ import VueApollo from 'vue-apollo'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; import { GlDisclosureDropdown } from '@gitlab/ui'; +import { createTestingPinia } from '@pinia/testing'; +import { PiniaVuePlugin } from 'pinia'; import createMockApollo from 'helpers/mock_apollo_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; @@ -10,13 +12,19 @@ import SubmitDropdown from '~/batch_comments/components/submit_dropdown.vue'; import userCanApproveQuery from '~/batch_comments/queries/can_approve.query.graphql'; import { updateText } from '~/lib/utils/text_markdown'; import SummarizeMyReview from 'ee/batch_comments/components/summarize_my_review.vue'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; jest.mock('~/lib/utils/text_markdown'); Vue.use(Vuex); Vue.use(VueApollo); +Vue.use(PiniaVuePlugin); let wrapper; +let pinia; let publishReview; function factory({ @@ -76,6 +84,7 @@ function factory({ }); wrapper = mountExtended(SubmitDropdown, { store, + pinia, apolloProvider, stubs: { SummarizeMyReview }, provide: { canSummarize }, @@ -83,6 +92,13 @@ function factory({ } describe('Batch comments submit dropdown', () => { + beforeEach(() => { + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + useBatchComments(); + }); + it.each` requirePasswordToApprove | exists | existsText ${true} | ${true} | ${'shows'} diff --git a/ee/spec/frontend/diffs/components/diff_line_note_form_spec.js b/ee/spec/frontend/diffs/components/diff_line_note_form_spec.js index 03d1d05ca094af226479f66693d601e80f17018b..c9cce1c8f2ae7c659a2b55ccad8acc330a3f269e 100644 --- a/ee/spec/frontend/diffs/components/diff_line_note_form_spec.js +++ b/ee/spec/frontend/diffs/components/diff_line_note_form_spec.js @@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; +import { createTestingPinia } from '@pinia/testing'; import waitForPromises from 'helpers/wait_for_promises'; import { sprintf } from '~/locale'; import { createAlert } from '~/alert'; @@ -10,6 +11,10 @@ import note from 'jest/notes/mock_data'; import DiffLineNoteForm from '~/diffs/components/diff_line_note_form.vue'; import NoteForm from '~/notes/components/note_form.vue'; import { SOMETHING_WENT_WRONG, SAVING_THE_COMMENT_FAILED } from '~/diffs/i18n'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; Vue.use(Vuex); jest.mock('~/alert'); @@ -17,7 +22,7 @@ jest.mock('~/alert'); describe('EE DiffLineNoteForm', () => { let wrapper; - const saveDraft = jest.fn(); + let saveDraft; const createStoreOptions = (headSha) => { const state = { @@ -52,10 +57,6 @@ describe('EE DiffLineNoteForm', () => { cancelCommentForm: jest.fn(), }, }, - batchComments: { - namespaced: true, - actions: { saveDraft }, - }, }, }; }; @@ -84,7 +85,14 @@ describe('EE DiffLineNoteForm', () => { const submitNoteAddToReview = () => wrapper.findComponent(NoteForm).vm.$emit('handleFormUpdateAddToReview', note); - const saveDraftCommitId = () => saveDraft.mock.calls[0][1].data.note.commit_id; + const saveDraftCommitId = () => saveDraft.mock.calls[0][0].data.note.commit_id; + + beforeEach(() => { + createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + saveDraft = useBatchComments().saveDraft.mockImplementation(() => Promise.resolve()); + }); describe('when user submits note to review', () => { it('should call saveDraft action with commit_id === null when store has no commit', () => { diff --git a/ee/spec/frontend/notes/components/note_form_spec.js b/ee/spec/frontend/notes/components/note_form_spec.js index a6d49e16b7192eabf8e595c90ceece0d63628732..61d92b73dc1d510c08426e1184c4bcdbbb2892fc 100644 --- a/ee/spec/frontend/notes/components/note_form_spec.js +++ b/ee/spec/frontend/notes/components/note_form_spec.js @@ -1,10 +1,18 @@ -import { nextTick } from 'vue'; +import Vue, { nextTick } from 'vue'; +import { createTestingPinia } from '@pinia/testing'; +import { PiniaVuePlugin } from 'pinia'; +// eslint-disable-next-line no-restricted-imports +import Vuex from 'vuex'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import CommentTemperature from 'ee_component/ai/components/comment_temperature.vue'; -import batchComments from '~/batch_comments/stores/modules/batch_comments'; import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue'; import NoteForm from '~/notes/components/note_form.vue'; import createStore from '~/notes/stores'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useBatchComments } from '~/batch_comments/store'; +import mrNotesStore from '~/mr_notes/stores/modules'; import { notesDataMock, noteableDataMock, @@ -15,8 +23,11 @@ jest.mock('~/lib/utils/autosave'); const badNote = 'very bad note'; +Vue.use(PiniaVuePlugin); + describe('issue_comment_form component', () => { let wrapper; + let pinia; const findMarkdownEditor = () => wrapper.findComponent(MarkdownEditor); const findMarkdownEditorTextarea = () => findMarkdownEditor().find('textarea'); @@ -32,6 +43,9 @@ describe('issue_comment_form component', () => { stubs = {}, store = createStore(), } = {}) => { + store.registerModule('page', new Vuex.Store(mrNotesStore)); + // eslint-disable-next-line no-param-reassign + store.state.page.activeTab = 'diffs'; store.dispatch('setNoteableData', { ...noteableDataMock, noteableType, @@ -41,6 +55,7 @@ describe('issue_comment_form component', () => { wrapper = mountExtended(NoteForm, { store, + pinia, propsData: { isEditing: false, noteBody: 'Magni suscipit eius consectetur enim et ex et commodi.', @@ -59,6 +74,13 @@ describe('issue_comment_form component', () => { }); }; + beforeEach(() => { + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + useBatchComments().$patch({ isMergeRequest: true }); + }); + describe('markdown editor', () => { it('shows markdown editor', () => { createComponentWrapper(); @@ -193,7 +215,6 @@ describe('issue_comment_form component', () => { beforeEach(() => { bootstrapFn = (updatedNoteBody = badNote) => { const store = createStore(); - store.registerModule('batchComments', batchComments()); createComponentWrapper({ noteableType, initialData: { updatedNoteBody }, diff --git a/spec/frontend/batch_comments/components/diff_file_drafts_spec.js b/spec/frontend/batch_comments/components/diff_file_drafts_spec.js index d1ce8be6c4273acb70beafdc13ac31d28f1edd22..c62cc9f24ff5e7983ffe8b3e2e9d153c2ba7f64f 100644 --- a/spec/frontend/batch_comments/components/diff_file_drafts_spec.js +++ b/spec/frontend/batch_comments/components/diff_file_drafts_spec.js @@ -1,37 +1,42 @@ -import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; -// eslint-disable-next-line no-restricted-imports -import Vuex from 'vuex'; +import { shallowMount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { PiniaVuePlugin } from 'pinia'; import DiffFileDrafts from '~/batch_comments/components/diff_file_drafts.vue'; import DraftNote from '~/batch_comments/components/draft_note.vue'; import DesignNotePin from '~/vue_shared/components/design_management/design_note_pin.vue'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; +import * as mockData from '../../notes/mock_data'; -Vue.use(Vuex); +Vue.use(PiniaVuePlugin); describe('Batch comments diff file drafts component', () => { let wrapper; + let pinia; function factory(propsData = {}) { - const store = new Vuex.Store({ - modules: { - batchComments: { - namespaced: true, - getters: { - draftsForFile: () => () => [ - { id: 1, position: { position_type: 'file' } }, - { id: 2, position: { position_type: 'file' } }, - ], - }, - }, - }, - }); - wrapper = shallowMount(DiffFileDrafts, { - store, + pinia, propsData: { fileHash: 'filehash', positionType: 'file', ...propsData }, }); } + beforeEach(() => { + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + useBatchComments().drafts = [ + ...mockData.draftComments.map((draft) => ({ + ...draft, + file_hash: 'filehash', + position: { position_type: 'file' }, + })), + ]; + }); + it('renders list of draft notes', () => { factory(); diff --git a/spec/frontend/batch_comments/components/draft_note_spec.js b/spec/frontend/batch_comments/components/draft_note_spec.js index e5e3ae373fe3ccd47f6373e86ba320ccc6f15e08..d859f557b608f3f073e93c81ea9207d43d9b540b 100644 --- a/spec/frontend/batch_comments/components/draft_note_spec.js +++ b/spec/frontend/batch_comments/components/draft_note_spec.js @@ -1,5 +1,6 @@ import { nextTick } from 'vue'; import { GlBadge } from '@gitlab/ui'; +import { createTestingPinia } from '@pinia/testing'; import { shallowMount } from '@vue/test-utils'; import { stubComponent } from 'helpers/stub_component'; import DraftNote from '~/batch_comments/components/draft_note.vue'; @@ -7,6 +8,10 @@ import { createStore } from '~/batch_comments/stores'; import NoteableNote from '~/notes/components/noteable_note.vue'; import { clearDraft } from '~/lib/utils/autosave'; import * as types from '~/batch_comments/stores/modules/batch_comments/mutation_types'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useBatchComments } from '~/batch_comments/store'; import { createDraft } from '../mock_data'; jest.mock('~/behaviors/markdown/render_gfm'); @@ -51,6 +56,9 @@ describe('Batch comments draft note component', () => { const findNoteableNote = () => wrapper.findComponent(NoteableNote); beforeEach(() => { + createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); store = createStore(); draft = createDraft(); }); @@ -84,7 +92,7 @@ describe('Batch comments draft note component', () => { findNoteableNote().vm.$emit('handleUpdateNote', formData); - expect(store.dispatch).toHaveBeenCalledWith('batchComments/updateDraft', formData); + expect(useBatchComments().updateDraft).toHaveBeenCalledWith(formData); }); }); @@ -95,7 +103,7 @@ describe('Batch comments draft note component', () => { findNoteableNote().vm.$emit('handleDeleteNote', draft); - expect(store.dispatch).toHaveBeenCalledWith('batchComments/deleteDraft', draft); + expect(useBatchComments().deleteDraft).toHaveBeenCalledWith(draft); }); }); @@ -153,14 +161,10 @@ describe('Batch comments draft note component', () => { it(`sets opened state`, async () => { createComponent({ draft }); await findNoteableNote().vm.$emit('handleEdit'); - expect(store.commit).toHaveBeenCalledWith( - `batchComments/${types.SET_DRAFT_EDITING}`, - { - draftId: draft.id, - isEditing: true, - }, - undefined, - ); + expect(useBatchComments()[types.SET_DRAFT_EDITING]).toHaveBeenCalledWith({ + draftId: draft.id, + isEditing: true, + }); }); it(`resets opened state on form close`, async () => { @@ -168,14 +172,10 @@ describe('Batch comments draft note component', () => { createComponent({ draft }); await findNoteableNote().vm.$emit('cancelForm'); expect(findNoteableNote().props('restoreFromAutosave')).toBe(false); - expect(store.commit).toHaveBeenCalledWith( - `batchComments/${types.SET_DRAFT_EDITING}`, - { - draftId: draft.id, - isEditing: false, - }, - undefined, - ); + expect(useBatchComments()[types.SET_DRAFT_EDITING]).toHaveBeenCalledWith({ + draftId: draft.id, + isEditing: false, + }); }); it(`clears autosave key on form cancel`, () => { diff --git a/spec/frontend/batch_comments/components/drafts_count_spec.js b/spec/frontend/batch_comments/components/drafts_count_spec.js index 850a7efb4ed39c17b5f96b3b4df821546286d521..dcbd9e0af4127da6e664fe032bc5b2d9f9aa9d7e 100644 --- a/spec/frontend/batch_comments/components/drafts_count_spec.js +++ b/spec/frontend/batch_comments/components/drafts_count_spec.js @@ -1,18 +1,27 @@ -import { nextTick } from 'vue'; +import Vue, { nextTick } from 'vue'; import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { PiniaVuePlugin } from 'pinia'; import DraftsCount from '~/batch_comments/components/drafts_count.vue'; -import { createStore } from '~/batch_comments/stores'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; + +Vue.use(PiniaVuePlugin); describe('Batch comments drafts count component', () => { - let store; let wrapper; + let pinia; beforeEach(() => { - store = createStore(); + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); - store.state.batchComments.drafts.push('comment'); + useBatchComments().drafts.push('comment'); - wrapper = mount(DraftsCount, { store }); + wrapper = mount(DraftsCount, { pinia }); }); it('renders count', () => { @@ -24,7 +33,7 @@ describe('Batch comments drafts count component', () => { expect(el.text()).toContain('draft'); - store.state.batchComments.drafts.push('comment 2'); + useBatchComments().drafts.push('comment 2'); await nextTick(); expect(el.text()).toContain('drafts'); diff --git a/spec/frontend/batch_comments/components/preview_dropdown_spec.js b/spec/frontend/batch_comments/components/preview_dropdown_spec.js index c0ad40b75adb0a64c7daa97de97e80fdbd5177d1..b4b97a2d29fb6aaf80c34b33abba3875ab18745a 100644 --- a/spec/frontend/batch_comments/components/preview_dropdown_spec.js +++ b/spec/frontend/batch_comments/components/preview_dropdown_spec.js @@ -2,59 +2,86 @@ import Vue, { nextTick } from 'vue'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { PiniaVuePlugin } from 'pinia'; import { TEST_HOST } from 'helpers/test_constants'; import { visitUrl } from '~/lib/utils/url_utility'; import PreviewDropdown from '~/batch_comments/components/preview_dropdown.vue'; import PreviewItem from '~/batch_comments/components/preview_item.vue'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { createCustomGetters } from 'helpers/pinia_helpers'; +import { useBatchComments } from '~/batch_comments/store'; jest.mock('~/lib/utils/url_utility', () => ({ visitUrl: jest.fn(), setUrlParams: jest.requireActual('~/lib/utils/url_utility').setUrlParams, + joinPaths: jest.fn(), + doesHashExistInUrl: jest.fn(), })); Vue.use(Vuex); +Vue.use(PiniaVuePlugin); -let wrapper; - -const goToFile = jest.fn(); -const scrollToDraft = jest.fn(); - -const findPreviewItem = () => wrapper.findComponent(PreviewItem); - -function factory({ viewDiffsFileByFile = false, draftsCount = 1, sortedDrafts = [] } = {}) { - const store = new Vuex.Store({ - modules: { - diffs: { - namespaced: true, - actions: { - goToFile, - }, - state: { - viewDiffsFileByFile, +describe('Batch comments preview dropdown', () => { + let wrapper; + let pinia; + let batchCommentsGetters; + + const goToFile = jest.fn(); + + const findPreviewItem = () => wrapper.findComponent(PreviewItem); + + function factory({ viewDiffsFileByFile = false, draftsCount = 1, sortedDrafts = [] } = {}) { + batchCommentsGetters = { + draftsCount, + sortedDrafts, + }; + const store = new Vuex.Store({ + modules: { + diffs: { + namespaced: true, + actions: { + goToFile, + }, + state: { + viewDiffsFileByFile, + }, }, - }, - batchComments: { - namespaced: true, - actions: { scrollToDraft }, - getters: { draftsCount: () => draftsCount, sortedDrafts: () => sortedDrafts }, - }, - notes: { - getters: { - getNoteableData: () => ({ diff_head_sha: '123' }), + notes: { + getters: { + getNoteableData: () => ({ diff_head_sha: '123' }), + }, }, }, - }, - }); + }); - wrapper = mount(PreviewDropdown, { - store, - stubs: { - PreviewItem: true, - }, + wrapper = mount(PreviewDropdown, { + store, + pinia, + stubs: { + PreviewItem: true, + }, + }); + } + + beforeEach(() => { + batchCommentsGetters = {}; + pinia = createTestingPinia({ + plugins: [ + globalAccessorPlugin, + createCustomGetters(() => ({ + batchComments: batchCommentsGetters, + legacyNotes: {}, + legacyDiffs: {}, + })), + ], + }); + useLegacyDiffs(); + useNotes(); }); -} -describe('Batch comments preview dropdown', () => { describe('clicking draft', () => { it('toggles active file when viewDiffsFileByFile is true', async () => { factory({ @@ -67,8 +94,7 @@ describe('Batch comments preview dropdown', () => { expect(goToFile).toHaveBeenCalledWith(expect.anything(), { path: 'foo' }); await nextTick(); - expect(scrollToDraft).toHaveBeenCalledWith( - expect.anything(), + expect(useBatchComments().scrollToDraft).toHaveBeenCalledWith( expect.objectContaining({ id: 1, file_hash: 'hash' }), ); }); @@ -83,8 +109,7 @@ describe('Batch comments preview dropdown', () => { await nextTick(); - expect(scrollToDraft).toHaveBeenCalledWith( - expect.anything(), + expect(useBatchComments().scrollToDraft).toHaveBeenCalledWith( expect.objectContaining({ id: 1 }), ); }); @@ -99,7 +124,7 @@ describe('Batch comments preview dropdown', () => { await nextTick(); - expect(scrollToDraft).not.toHaveBeenCalled(); + expect(useBatchComments().scrollToDraft).not.toHaveBeenCalled(); expect(visitUrl).toHaveBeenCalledWith(`${TEST_HOST}/?commit_id=1234#note_1`); }); }); diff --git a/spec/frontend/batch_comments/components/publish_dropdown_spec.js b/spec/frontend/batch_comments/components/publish_dropdown_spec.js index 2fe73f30a4ca0599290d5be353efacfb353a9768..47c17ed64b33724d85762a13f29295c4490c173b 100644 --- a/spec/frontend/batch_comments/components/publish_dropdown_spec.js +++ b/spec/frontend/batch_comments/components/publish_dropdown_spec.js @@ -1,30 +1,45 @@ import { GlDisclosureDropdown } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; import Vue from 'vue'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; +import { PiniaVuePlugin } from 'pinia'; import PreviewDropdown from '~/batch_comments/components/preview_dropdown.vue'; import { createStore } from '~/mr_notes/stores'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; import { createDraft } from '../mock_data'; jest.mock('~/behaviors/markdown/render_gfm'); Vue.use(Vuex); +Vue.use(PiniaVuePlugin); describe('Batch comments publish dropdown component', () => { let wrapper; + let pinia; const draft = createDraft(); function createComponent() { const store = createStore(); - store.state.batchComments.drafts.push(draft, { ...draft, id: 2 }); wrapper = shallowMount(PreviewDropdown, { store, + pinia, stubs: { GlDisclosureDropdown }, }); } + beforeEach(() => { + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + useBatchComments().drafts = [draft, { ...draft, id: 2 }]; + }); + it('renders list of drafts', () => { createComponent(); diff --git a/spec/frontend/batch_comments/components/review_bar_spec.js b/spec/frontend/batch_comments/components/review_bar_spec.js index 2cf56d0d6732349c7bd6d05bdc815c427526cd5e..2ea42686067615cb3b4605e7dac78bf043bc824f 100644 --- a/spec/frontend/batch_comments/components/review_bar_spec.js +++ b/spec/frontend/batch_comments/components/review_bar_spec.js @@ -1,8 +1,13 @@ import { nextTick } from 'vue'; +import { createTestingPinia } from '@pinia/testing'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ReviewBar from '~/batch_comments/components/review_bar.vue'; import { REVIEW_BAR_VISIBLE_CLASS_NAME } from '~/batch_comments/constants'; import toast from '~/vue_shared/plugins/global_toast'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; import createStore from '../create_batch_comments_store'; jest.mock('~/vue_shared/plugins/global_toast'); @@ -24,6 +29,9 @@ describe('Batch comments review bar component', () => { }; beforeEach(() => { + createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); document.body.className = ''; }); @@ -59,11 +67,9 @@ describe('Batch comments review bar component', () => { it('calls discardReviews when primary action on modal is triggered', () => { createComponent(); - const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); - findDiscardReviewModal().vm.$emit('primary'); - expect(dispatchSpy).toHaveBeenCalledWith('batchComments/discardDrafts', undefined); + expect(useBatchComments().discardDrafts).toHaveBeenCalled(); }); it('creates a toast message when finished', async () => { diff --git a/spec/frontend/batch_comments/components/submit_dropdown_spec.js b/spec/frontend/batch_comments/components/submit_dropdown_spec.js index 125242c4119d52fcbaf488a52eca2f42d8ce1624..0e1984b83b1b9215e5254c2319319825c6111248 100644 --- a/spec/frontend/batch_comments/components/submit_dropdown_spec.js +++ b/spec/frontend/batch_comments/components/submit_dropdown_spec.js @@ -1,8 +1,10 @@ import { GlDisclosureDropdown } from '@gitlab/ui'; +import { createTestingPinia } from '@pinia/testing'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; +import { PiniaVuePlugin } from 'pinia'; import createMockApollo from 'helpers/mock_apollo_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; @@ -11,20 +13,24 @@ import { mockTracking } from 'helpers/tracking_helper'; import userCanApproveQuery from '~/batch_comments/queries/can_approve.query.graphql'; import { CLEAR_AUTOSAVE_ENTRY_EVENT } from '~/vue_shared/constants'; import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; jest.mock('~/autosave'); jest.mock('~/vue_shared/components/markdown/eventhub'); Vue.use(VueApollo); Vue.use(Vuex); +Vue.use(PiniaVuePlugin); let wrapper; -let publishReview; +let pinia; let trackingSpy; let getCurrentUserLastNote; function factory({ canApprove = true, shouldAnimateReviewButton = false } = {}) { - publishReview = jest.fn().mockResolvedValue(); trackingSpy = mockTracking(undefined, null, jest.spyOn); const requestHandlers = [ [ @@ -48,6 +54,8 @@ function factory({ canApprove = true, shouldAnimateReviewButton = false } = {}) const apolloProvider = createMockApollo(requestHandlers); getCurrentUserLastNote = Vue.observable({ id: 1 }); + useBatchComments().shouldAnimateReviewButton = shouldAnimateReviewButton; + const store = new Vuex.Store({ getters: { getNotesData: () => ({ @@ -68,18 +76,11 @@ function factory({ canApprove = true, shouldAnimateReviewButton = false } = {}) projectPath: 'gitlab-org/gitlab', }, }, - batchComments: { - namespaced: true, - state: { shouldAnimateReviewButton }, - actions: { - publishReview, - clearDrafts: jest.fn(), - }, - }, }, }); wrapper = mountExtended(SubmitDropdown, { store, + pinia, apolloProvider, }); } @@ -90,6 +91,12 @@ const findForm = () => wrapper.findByTestId('submit-gl-form'); const findSubmitDropdown = () => wrapper.findComponent(GlDisclosureDropdown); describe('Batch comments submit dropdown', () => { + beforeEach(() => { + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + }); + afterEach(() => { window.mrTabs = null; }); @@ -97,11 +104,11 @@ describe('Batch comments submit dropdown', () => { it('calls publishReview with note data', async () => { factory(); - findCommentTextarea().setValue('Hello world'); + await findCommentTextarea().setValue('Hello world'); await findForm().vm.$emit('submit', { preventDefault: jest.fn() }); - expect(publishReview).toHaveBeenCalledWith(expect.anything(), { + expect(useBatchComments().publishReview).toHaveBeenCalledWith({ noteable_type: 'merge_request', noteable_id: 1, note: 'Hello world', @@ -249,7 +256,7 @@ describe('Batch comments submit dropdown', () => { findForm().vm.$emit('submit', { preventDefault: jest.fn() }); - expect(publishReview).toHaveBeenCalledWith(expect.anything(), { + expect(useBatchComments().publishReview).toHaveBeenCalledWith({ noteable_type: 'merge_request', noteable_id: 1, note: 'Hello world', diff --git a/spec/frontend/diffs/components/diff_content_spec.js b/spec/frontend/diffs/components/diff_content_spec.js index 076459dec2234c068810249b069c7b2948433387..8992a258f7e0920ad3f259f9b6a72650fd498e72 100644 --- a/spec/frontend/diffs/components/diff_content_spec.js +++ b/spec/frontend/diffs/components/diff_content_spec.js @@ -1,8 +1,10 @@ import { GlLoadingIcon } from '@gitlab/ui'; +import { createTestingPinia } from '@pinia/testing'; import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; +import { PiniaVuePlugin } from 'pinia'; import waitForPromises from 'helpers/wait_for_promises'; import { sprintf } from '~/locale'; import { createAlert } from '~/alert'; @@ -16,13 +18,19 @@ import NoteForm from '~/notes/components/note_form.vue'; import NoPreviewViewer from '~/vue_shared/components/diff_viewer/viewers/no_preview.vue'; import NotDiffableViewer from '~/vue_shared/components/diff_viewer/viewers/not_diffable.vue'; import { SOMETHING_WENT_WRONG, SAVING_THE_COMMENT_FAILED } from '~/diffs/i18n'; +import { createCustomGetters } from 'helpers/pinia_helpers'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; import { getDiffFileMock } from '../mock_data/diff_file'; Vue.use(Vuex); +Vue.use(PiniaVuePlugin); jest.mock('~/alert'); describe('DiffContent', () => { let wrapper; + let pinia; const saveDiffDiscussionMock = jest.fn(); const closeDiffFileCommentFormMock = jest.fn(); @@ -52,20 +60,6 @@ describe('DiffContent', () => { getUserData: getUserDataGetterMock, }, modules: { - /* - we need extra batchComments since vue-test-utils does not - stub async components properly - */ - batchComments: { - namespaced: true, - getters: { - draftsForFile: () => () => true, - draftsForLine: () => () => true, - shouldRenderDraftRow: () => () => true, - hasParallelDraftLeft: () => () => true, - hasParallelDraftRight: () => () => true, - }, - }, diffs: { namespaced: true, state: { @@ -94,11 +88,33 @@ describe('DiffContent', () => { ...defaultProps, ...props, }, + pinia, store: fakeStore, provide: { glFeatures }, }); }; + beforeEach(() => { + pinia = createTestingPinia({ + plugins: [ + globalAccessorPlugin, + createCustomGetters(() => ({ + legacyNotes: {}, + legacyDiffs: {}, + batchComments: { + draftsForFile: () => () => true, + draftsForLine: () => () => true, + shouldRenderDraftRow: () => () => true, + hasParallelDraftLeft: () => () => true, + hasParallelDraftRight: () => () => true, + }, + })), + ], + }); + useLegacyDiffs(); + useNotes(); + }); + describe('with text based files', () => { afterEach(() => { [isParallelViewGetterMock, isInlineViewGetterMock].forEach((m) => m.mockRestore()); diff --git a/spec/frontend/diffs/components/diff_discussions_spec.js b/spec/frontend/diffs/components/diff_discussions_spec.js index 25081535b377714d153e0aa7b4e6fa67b3fa41bf..c6939dd23be4754626797b2cb105e4887868bf2e 100644 --- a/spec/frontend/diffs/components/diff_discussions_spec.js +++ b/spec/frontend/diffs/components/diff_discussions_spec.js @@ -1,16 +1,25 @@ +import Vue from 'vue'; import { GlIcon } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { PiniaVuePlugin } from 'pinia'; import DiffDiscussions from '~/diffs/components/diff_discussions.vue'; import { createStore } from '~/mr_notes/stores'; import DiscussionNotes from '~/notes/components/discussion_notes.vue'; import NoteableDiscussion from '~/notes/components/noteable_discussion.vue'; import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; import discussionsMockData from '../mock_data/diff_discussions'; jest.mock('~/behaviors/markdown/render_gfm'); +Vue.use(PiniaVuePlugin); + describe('DiffDiscussions', () => { let store; + let pinia; let wrapper; const getDiscussionsMockData = () => [{ ...discussionsMockData }]; @@ -18,6 +27,7 @@ describe('DiffDiscussions', () => { store = createStore(); wrapper = mount(DiffDiscussions, { store, + pinia, propsData: { discussions, ...props, @@ -27,6 +37,12 @@ describe('DiffDiscussions', () => { const findNoteableDiscussion = () => wrapper.findComponent(NoteableDiscussion); + beforeEach(() => { + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + }); + describe('template', () => { it('should have notes list', () => { createComponent(); diff --git a/spec/frontend/diffs/components/diff_view_spec.js b/spec/frontend/diffs/components/diff_view_spec.js index bb8320ec4730db2bbcd1ccb42e2e796dfe958885..9ce0452ca296d5a91b1ed44fe432b9741e634d70 100644 --- a/spec/frontend/diffs/components/diff_view_spec.js +++ b/spec/frontend/diffs/components/diff_view_spec.js @@ -1,15 +1,26 @@ import { shallowMount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; import Vue from 'vue'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; import { throttle } from 'lodash'; +import { PiniaVuePlugin } from 'pinia'; import DiffView from '~/diffs/components/diff_view.vue'; import DraftNote from '~/batch_comments/components/draft_note.vue'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { createCustomGetters } from 'helpers/pinia_helpers'; + +Vue.use(Vuex); +Vue.use(PiniaVuePlugin); jest.mock('lodash/throttle', () => jest.fn((fn) => fn)); const lodash = jest.requireActual('lodash'); describe('DiffView', () => { + let pinia; + const DiffExpansionCell = { template: `<div/>` }; const DiffRow = { template: `<div/>` }; const DiffCommentCell = { template: `<div/>` }; @@ -18,19 +29,6 @@ describe('DiffView', () => { const getDiffRow = (wrapper) => wrapper.findComponent(DiffRow).vm; const createWrapper = ({ props } = {}) => { - Vue.use(Vuex); - - const batchComments = { - getters: { - shouldRenderDraftRow: () => false, - shouldRenderParallelDraftRow: () => () => true, - draftsForLine: () => false, - draftsForFile: () => false, - hasParallelDraftLeft: () => false, - hasParallelDraftRight: () => false, - }, - namespaced: true, - }; const diffs = { actions: { showCommentForm }, getters: { commitId: () => 'abc123', fileLineCoverage: () => ({}) }, @@ -42,7 +40,7 @@ describe('DiffView', () => { }; const store = new Vuex.Store({ - modules: { diffs, notes, batchComments }, + modules: { diffs, notes }, }); const propsData = { @@ -53,11 +51,30 @@ describe('DiffView', () => { }; const stubs = { DiffExpansionCell, DiffRow, DiffCommentCell }; - return shallowMount(DiffView, { propsData, store, stubs }); + return shallowMount(DiffView, { propsData, pinia, store, stubs }); }; beforeEach(() => { throttle.mockImplementation(lodash.throttle); + pinia = createTestingPinia({ + plugins: [ + globalAccessorPlugin, + createCustomGetters(() => ({ + legacyNotes: {}, + legacyDiffs: {}, + batchComments: { + shouldRenderDraftRow: () => false, + shouldRenderParallelDraftRow: () => () => true, + draftsForLine: () => false, + draftsForFile: () => false, + hasParallelDraftLeft: () => false, + hasParallelDraftRight: () => false, + }, + })), + ], + }); + useLegacyDiffs(); + useNotes(); }); afterEach(() => { diff --git a/spec/frontend/notes/components/note_form_spec.js b/spec/frontend/notes/components/note_form_spec.js index 6fc9ae78ca7c7cdc51bdca9c0b91ceb727710170..c0d4ac814261a459005dc75188e30e00186cb446 100644 --- a/spec/frontend/notes/components/note_form_spec.js +++ b/spec/frontend/notes/components/note_form_spec.js @@ -1,6 +1,7 @@ import { GlLink, GlFormCheckbox } from '@gitlab/ui'; -import { nextTick } from 'vue'; -import batchComments from '~/batch_comments/stores/modules/batch_comments'; +import Vue, { nextTick } from 'vue'; +import { createTestingPinia } from '@pinia/testing'; +import { PiniaVuePlugin } from 'pinia'; import NoteForm from '~/notes/components/note_form.vue'; import createStore from '~/notes/stores'; import MarkdownField from '~/vue_shared/components/markdown/field.vue'; @@ -11,12 +12,19 @@ import notesEventHub from '~/notes/event_hub'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import { mockTracking } from 'helpers/tracking_helper'; import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue'; +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; import { noteableDataMock, notesDataMock, discussionMock, note } from '../mock_data'; jest.mock('~/lib/utils/autosave'); +Vue.use(PiniaVuePlugin); + describe('issue_note_form component', () => { let store; + let pinia; let wrapper; let textarea; let props; @@ -25,6 +33,7 @@ describe('issue_note_form component', () => { const createComponentWrapper = (propsData = {}, provide = {}, stubs = {}) => { wrapper = mountExtended(NoteForm, { store, + pinia, propsData: { ...props, ...propsData, @@ -53,6 +62,11 @@ describe('issue_note_form component', () => { const findMarkdownField = () => wrapper.findComponent(MarkdownField); beforeEach(() => { + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + useBatchComments().$patch({ isMergeRequest: true }); + store = createStore(); store.dispatch('setNoteableData', noteableDataMock); store.dispatch('setNotesData', notesDataMock); @@ -287,8 +301,6 @@ describe('issue_note_form component', () => { describe('with batch comments', () => { beforeEach(() => { - store.registerModule('batchComments', batchComments()); - createComponentWrapper({ isDraft: true, noteId: '', @@ -338,7 +350,7 @@ describe('issue_note_form component', () => { }); it('sends the event to indicate that a draft has been added to the review', () => { - store.state.batchComments.drafts = [{ note: 'A' }]; + useBatchComments().drafts = [{ note: 'A' }]; createComponentWrapper({ isDraft: true, noteId: '', diff --git a/spec/frontend/notes/components/noteable_discussion_spec.js b/spec/frontend/notes/components/noteable_discussion_spec.js index eff88c26d7e0260db773e11ba61ec789a569f9be..e79757c56b9488b84dca5b289f77d0f693482c38 100644 --- a/spec/frontend/notes/components/noteable_discussion_spec.js +++ b/spec/frontend/notes/components/noteable_discussion_spec.js @@ -3,6 +3,8 @@ import Vue, { nextTick } from 'vue'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; import MockAdapter from 'axios-mock-adapter'; +import { PiniaVuePlugin } from 'pinia'; +import { createTestingPinia } from '@pinia/testing'; import discussionWithTwoUnresolvedNotes from 'test_fixtures/merge_requests/resolved_diff_discussion.json'; import waitForPromises from 'helpers/wait_for_promises'; import axios from '~/lib/utils/axios_utils'; @@ -19,7 +21,10 @@ import { COMMENT_FORM } from '~/notes/i18n'; import notesModule from '~/notes/stores/modules'; import { sprintf } from '~/locale'; import { createAlert } from '~/alert'; - +import { globalAccessorPlugin } from '~/pinia/plugins'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useBatchComments } from '~/batch_comments/store'; import { noteableDataMock, discussionMock, @@ -30,12 +35,14 @@ import { import { useLocalStorageSpy } from '../../__helpers__/local_storage_helper'; Vue.use(Vuex); +Vue.use(PiniaVuePlugin); jest.mock('~/behaviors/markdown/render_gfm'); jest.mock('~/alert'); describe('noteable_discussion component', () => { let store; + let pinia; let wrapper; let axiosMock; @@ -58,11 +65,16 @@ describe('noteable_discussion component', () => { wrapper = mountExtended(NoteableDiscussion, { store, + pinia, propsData: { discussion }, }); }; beforeEach(() => { + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + useBatchComments(); axiosMock = new MockAdapter(axios); createComponent(); }); @@ -127,6 +139,7 @@ describe('noteable_discussion component', () => { store.dispatch('setUserData', userDataMock); wrapper = mount(NoteableDiscussion, { store, + pinia, propsData: { discussion: discussionMock }, }); expect(wrapper.find('.note-edit-form').exists()).toBe(hasDraft); @@ -290,6 +303,7 @@ describe('noteable_discussion component', () => { wrapper = mount(NoteableDiscussion, { store, + pinia, propsData: { discussion: discussionMock }, }); }); @@ -308,6 +322,7 @@ describe('noteable_discussion component', () => { wrapper = mount(NoteableDiscussion, { store, + pinia, propsData: { discussion: discussionMock }, }); }); @@ -324,6 +339,7 @@ describe('noteable_discussion component', () => { const mock = jest.fn(); wrapper = mount(NoteableDiscussion, { store, + pinia, propsData: { discussion: discussionMock }, stubs: { NoteForm: { methods: { append: mock }, render() {} } }, }); diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js index a10f4d1cefee3dccf289ebc39d2350bdf1885048..32aacecfcaa950e70402a5ff0a1eadc238501e5c 100644 --- a/spec/frontend/notes/components/notes_app_spec.js +++ b/spec/frontend/notes/components/notes_app_spec.js @@ -1,7 +1,9 @@ import { mount, shallowMount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; import AxiosMockAdapter from 'axios-mock-adapter'; import $ from 'jquery'; import Vue, { nextTick } from 'vue'; +import { PiniaVuePlugin } from 'pinia'; import VueApollo from 'vue-apollo'; import setWindowLocation from 'helpers/set_window_location_helper'; import { mockTracking } from 'helpers/tracking_helper'; @@ -25,6 +27,9 @@ import { CopyAsGFM } from '~/behaviors/markdown/copy_as_gfm'; import { Mousetrap } from '~/lib/mousetrap'; import { ISSUABLE_COMMENT_OR_REPLY, keysFor } from '~/behaviors/shortcuts/keybindings'; import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_frame'; +import { useNotes } from '~/notes/store/legacy_notes'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; +import { globalAccessorPlugin } from '~/pinia/plugins'; import createMockApollo from 'helpers/mock_apollo_helper'; import noteQuery from '~/notes/graphql/note.query.graphql'; import * as mockData from '../mock_data'; @@ -45,11 +50,14 @@ const propsData = { notesFilterValue: TEST_NOTES_FILTER_VALUE, }; +Vue.use(PiniaVuePlugin); + describe('note_app', () => { let axiosMock; let mountComponent; let wrapper; let store; + let pinia; const initStore = (notesData = propsData.notesData) => { store.dispatch('setNotesData', notesData); @@ -78,6 +86,10 @@ describe('note_app', () => { axiosMock = new AxiosMockAdapter(axios); Vue.use(VueApollo); + pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); + useLegacyDiffs(); + useNotes(); + store = createStore(); mountComponent = ({ props = {} } = {}) => { @@ -98,6 +110,7 @@ describe('note_app', () => { ...props, }, store, + pinia, }, ); };