Skip to content

Commit 6dacda4

Browse files
authored
BC-10902 Display loading spinner when duplicating a card (#3957)
1 parent 9bf1bd9 commit 6dacda4

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

src/modules/feature/board/card/CardHost.unit.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { setupAddElementDialogMock } from "../test-utils/AddElementDialogMock";
22
import CardHost from "./CardHost.vue";
3+
import CardSkeleton from "./CardSkeleton.vue";
34
import ContentElementList from "./ContentElementList.vue";
45
import { CardResponse } from "@/serverApi/v3";
56
import { BoardPermissionChecks, defaultPermissions } from "@/types/board/Permissions";
7+
import { mockedPiniaStoreTyping } from "@@/tests/test-utils";
68
import setupDeleteConfirmationComposableMock from "@@/tests/test-utils/composable-mocks/setupDeleteConfirmationComposableMock";
79
import { cardResponseFactory, fileElementResponseFactory } from "@@/tests/test-utils/factory";
810
import { createTestingI18n, createTestingVuetify } from "@@/tests/test-utils/setup";
@@ -204,6 +206,24 @@ describe("CardHost", () => {
204206

205207
expect(useCardStore().duplicateCard).toHaveBeenCalledWith({ cardId });
206208
});
209+
210+
it("should show card skeleton while duplicating", async () => {
211+
mockedBoardPermissions.hasEditPermission.value = true;
212+
const { wrapper } = setup();
213+
const cardStore = mockedPiniaStoreTyping(useCardStore);
214+
cardStore.duplicateCard.mockResolvedValueOnce();
215+
216+
const duplicateButton = wrapper.findComponent(KebabMenuActionDuplicate);
217+
await duplicateButton.trigger("click");
218+
219+
const cardSkeletons = wrapper.findAllComponents(CardSkeleton);
220+
expect(cardSkeletons).toHaveLength(1);
221+
222+
await wrapper.vm.$nextTick();
223+
224+
const cardSkeletonsAfterDuplicationFinished = wrapper.findAllComponents(CardSkeleton);
225+
expect(cardSkeletonsAfterDuplicationFinished).toHaveLength(0);
226+
});
207227
});
208228

209229
describe("when users clicks share link menu", () => {

src/modules/feature/board/card/CardHost.vue

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
:data-scroll-target="getShareLinkId(cardId, BoardMenuScope.CARD)"
2222
>
2323
<template v-if="isLoadingCard">
24-
<CardSkeleton :height="height" />
24+
<CardSkeleton :height />
2525
</template>
2626
<template v-if="card">
2727
<CardTitle
@@ -75,6 +75,10 @@
7575
</template>
7676
</VCard>
7777
</CardHostInteractionHandler>
78+
<VCard v-if="isDuplicating" class="mt-3">
79+
<CardSkeleton :height />
80+
</VCard>
81+
7882
<!-- Detail View -->
7983
<CardHostDetailView
8084
v-if="card"
@@ -103,6 +107,7 @@ import CardHostInteractionHandler from "./CardHostInteractionHandler.vue";
103107
import CardSkeleton from "./CardSkeleton.vue";
104108
import CardTitle from "./CardTitle.vue";
105109
import ContentElementList from "./ContentElementList.vue";
110+
import { useSafeTaskRunner } from "@/composables/async-tasks.composable";
106111
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
107112
import BoardMenu from "@/modules/ui/board/BoardMenu.vue"; // FIX_CIRCULAR_DEPENDENCY
108113
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
@@ -222,11 +227,9 @@ const boardMenuClasses = computed(() => {
222227
return "hidden";
223228
});
224229
225-
const duplicateCard = async () => {
226-
if (!card.value) return;
227-
228-
await cardStore.duplicateCard({ cardId: card.value.id });
229-
};
230+
const { run: duplicateCard, isRunning: isDuplicating } = useSafeTaskRunner(async () => {
231+
await cardStore.duplicateCard({ cardId: props.cardId });
232+
});
230233
231234
onMounted(async () => {
232235
if (card.value === undefined) {

0 commit comments

Comments
 (0)