Skip to content

Commit 4905f3b

Browse files
authored
feat: container delete confirmation modal (#2145)
Update container delete confirmation modal based on #1982 and #1981
1 parent 60cebf7 commit 4905f3b

21 files changed

+803
-257
lines changed

src/course-libraries/data/api.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
44
const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
55

66
export const getEntityLinksByDownstreamContextUrl = () => `${getApiBaseUrl()}/api/contentstore/v2/downstreams/`;
7+
export const getContainerEntityLinksByDownstreamContextUrl = () => `${getApiBaseUrl()}/api/contentstore/v2/downstream-containers/`;
78

89
export const getEntityLinksSummaryByDownstreamContextUrl = (downstreamContextKey: string) => `${getApiBaseUrl()}/api/contentstore/v2/downstreams/${downstreamContextKey}/summary`;
910

@@ -18,9 +19,8 @@ export interface PaginatedData<T> {
1819
results: T,
1920
}
2021

21-
export interface PublishableEntityLink {
22+
export interface BasePublishableEntityLink {
2223
id: number;
23-
upstreamUsageKey: string;
2424
upstreamContextKey: string;
2525
upstreamContextTitle: string;
2626
upstreamVersion: number;
@@ -33,6 +33,14 @@ export interface PublishableEntityLink {
3333
readyToSync: boolean;
3434
}
3535

36+
export interface PublishableEntityLink extends BasePublishableEntityLink {
37+
upstreamUsageKey: string;
38+
}
39+
40+
export interface ContainerPublishableEntityLink extends BasePublishableEntityLink {
41+
upstreamContainerKey: string;
42+
}
43+
3644
export interface PublishableEntityLinkSummary {
3745
upstreamContextKey: string;
3846
upstreamContextTitle: string;
@@ -58,6 +66,23 @@ export const getEntityLinks = async (
5866
return camelCaseObject(data);
5967
};
6068

69+
export const getContainerEntityLinks = async (
70+
downstreamContextKey?: string,
71+
readyToSync?: boolean,
72+
upstreamContainerKey?: string,
73+
): Promise<ContainerPublishableEntityLink[]> => {
74+
const { data } = await getAuthenticatedHttpClient()
75+
.get(getContainerEntityLinksByDownstreamContextUrl(), {
76+
params: {
77+
course_id: downstreamContextKey,
78+
ready_to_sync: readyToSync,
79+
upstream_container_key: upstreamContainerKey,
80+
no_page: true,
81+
},
82+
});
83+
return camelCaseObject(data);
84+
};
85+
6186
export const getEntityLinksSummaryByDownstreamContext = async (
6287
downstreamContextKey: string,
6388
): Promise<PublishableEntityLinkSummary[]> => {

src/course-libraries/data/apiHooks.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import {
22
useQuery,
33
} from '@tanstack/react-query';
4-
import { getEntityLinks, getEntityLinksSummaryByDownstreamContext } from './api';
4+
import { getContainerEntityLinks, getEntityLinks, getEntityLinksSummaryByDownstreamContext } from './api';
55

66
export const courseLibrariesQueryKeys = {
77
all: ['courseLibraries'],
88
courseLibraries: (courseId?: string) => [...courseLibrariesQueryKeys.all, courseId],
9-
courseReadyToSyncLibraries: ({ courseId, readyToSync, upstreamUsageKey }: {
9+
courseReadyToSyncLibraries: ({
10+
courseId, readyToSync, upstreamUsageKey, upstreamContainerKey,
11+
}: {
1012
courseId?: string,
1113
readyToSync?: boolean,
1214
upstreamUsageKey?: string,
15+
upstreamContainerKey?: string,
1316
pageSize?: number,
1417
}) => {
1518
const key: Array<string | boolean | number> = [...courseLibrariesQueryKeys.all];
@@ -22,6 +25,9 @@ export const courseLibrariesQueryKeys = {
2225
if (upstreamUsageKey !== undefined) {
2326
key.push(upstreamUsageKey);
2427
}
28+
if (upstreamContainerKey !== undefined) {
29+
key.push(upstreamContainerKey);
30+
}
2531
return key;
2632
},
2733
courseLibrariesSummary: (courseId?: string) => [...courseLibrariesQueryKeys.courseLibraries(courseId), 'summary'],
@@ -63,3 +69,29 @@ export const useEntityLinksSummaryByDownstreamContext = (courseId?: string) => (
6369
enabled: courseId !== undefined,
6470
})
6571
);
72+
73+
/**
74+
* Hook to fetch list of publishable entity links for containers by course key.
75+
* (That is, get a list of the library containers used in the given course.)
76+
*/
77+
export const useContainerEntityLinks = ({
78+
courseId, readyToSync, upstreamContainerKey,
79+
}: {
80+
courseId?: string,
81+
readyToSync?: boolean,
82+
upstreamContainerKey?: string,
83+
}) => (
84+
useQuery({
85+
queryKey: courseLibrariesQueryKeys.courseReadyToSyncLibraries({
86+
courseId,
87+
readyToSync,
88+
upstreamContainerKey,
89+
}),
90+
queryFn: () => getContainerEntityLinks(
91+
courseId,
92+
readyToSync,
93+
upstreamContainerKey,
94+
),
95+
enabled: courseId !== undefined || upstreamContainerKey !== undefined || readyToSync !== undefined,
96+
})
97+
);

src/generic/delete-modal/DeleteModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ const DeleteModal = ({
6868
</ActionRow>
6969
)}
7070
>
71-
<p>{modalDescription}</p>
71+
<div>{modalDescription}</div>
7272
</AlertModal>
7373
);
7474
};

src/library-authoring/LibraryContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import { useLibraryContext } from './common/context/LibraryContext';
66
import { useSidebarContext } from './common/context/SidebarContext';
77
import CollectionCard from './components/CollectionCard';
88
import ComponentCard from './components/ComponentCard';
9-
import ContainerCard from './components/ContainerCard';
109
import { ContentType } from './routes';
1110
import { useLoadOnScroll } from '../hooks';
1211
import messages from './collections/messages';
12+
import ContainerCard from './containers/ContainerCard';
1313

1414
/**
1515
* Library Content to show content grid

src/library-authoring/components/ComponentMenu.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
import { canEditComponent } from './ComponentEditorModal';
2121
import ComponentDeleter from './ComponentDeleter';
2222
import messages from './messages';
23+
import containerMessages from '../containers/messages';
2324
import { useLibraryRoutes } from '../routes';
2425
import { useRunOnNextRender } from '../../utils';
2526

@@ -58,9 +59,9 @@ export const ComponentMenu = ({ usageKey }: { usageKey: string }) => {
5859
// Close sidebar if current component is open
5960
closeLibrarySidebar();
6061
}
61-
showToast(intl.formatMessage(messages.removeComponentFromCollectionSuccess));
62+
showToast(intl.formatMessage(containerMessages.removeComponentFromCollectionSuccess));
6263
}).catch(() => {
63-
showToast(intl.formatMessage(messages.removeComponentFromCollectionFailure));
64+
showToast(intl.formatMessage(containerMessages.removeComponentFromCollectionFailure));
6465
});
6566
};
6667

@@ -139,11 +140,11 @@ export const ComponentMenu = ({ usageKey }: { usageKey: string }) => {
139140
</Dropdown.Item>
140141
{insideCollection && (
141142
<Dropdown.Item onClick={removeFromCollection}>
142-
<FormattedMessage {...messages.menuRemoveFromCollection} />
143+
<FormattedMessage {...containerMessages.menuRemoveFromCollection} />
143144
</Dropdown.Item>
144145
)}
145146
<Dropdown.Item onClick={showManageCollections}>
146-
<FormattedMessage {...messages.menuAddToCollection} />
147+
<FormattedMessage {...containerMessages.menuAddToCollection} />
147148
</Dropdown.Item>
148149
</Dropdown.Menu>
149150
{isConfirmingDelete && (

src/library-authoring/components/ContainerDeleter.tsx

Lines changed: 0 additions & 96 deletions
This file was deleted.
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
@import "./BaseCard.scss";
2-
@import "./ContainerCard.scss";

src/library-authoring/components/messages.ts

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ const messages = defineMessages({
1111
defaultMessage: 'Collection actions menu',
1212
description: 'Alt/title text for the collection card menu button.',
1313
},
14-
containerCardMenuAlt: {
15-
id: 'course-authoring.library-authoring.container.menu',
16-
defaultMessage: 'Container actions menu',
17-
description: 'Alt/title text for the container card menu button.',
18-
},
1914
menuOpen: {
2015
id: 'course-authoring.library-authoring.menu.open',
2116
defaultMessage: 'Open',
@@ -36,26 +31,6 @@ const messages = defineMessages({
3631
defaultMessage: 'Delete',
3732
description: 'Menu item for deleting a component.',
3833
},
39-
menuAddToCollection: {
40-
id: 'course-authoring.library-authoring.component.menu.add',
41-
defaultMessage: 'Add to collection',
42-
description: 'Menu item for add a component to collection.',
43-
},
44-
menuRemoveFromCollection: {
45-
id: 'course-authoring.library-authoring.component.menu.remove',
46-
defaultMessage: 'Remove from collection',
47-
description: 'Menu item for remove an item from collection.',
48-
},
49-
removeComponentFromCollectionSuccess: {
50-
id: 'course-authoring.library-authoring.component.remove-from-collection-success',
51-
defaultMessage: 'Item successfully removed',
52-
description: 'Message for successful removal of an item from collection.',
53-
},
54-
removeComponentFromCollectionFailure: {
55-
id: 'course-authoring.library-authoring.component.remove-from-collection-failure',
56-
defaultMessage: 'Failed to remove item',
57-
description: 'Message for failure of removal of an item from collection.',
58-
},
5934
deleteComponentWarningTitle: {
6035
id: 'course-authoring.library-authoring.component.delete-confirmation-title',
6136
defaultMessage: 'Delete Component',
@@ -191,61 +166,6 @@ const messages = defineMessages({
191166
defaultMessage: 'This component can be synced in courses after publish.',
192167
description: 'Alert text of the modal to confirm publish a component in a library.',
193168
},
194-
menuDeleteContainer: {
195-
id: 'course-authoring.library-authoring.container.delete-menu-text',
196-
defaultMessage: 'Delete',
197-
description: 'Menu item to delete a container.',
198-
},
199-
deleteUnitWarningTitle: {
200-
id: 'course-authoring.library-authoring.unit.delete-confirmation-title',
201-
defaultMessage: 'Delete Unit',
202-
description: 'Title text for the warning displayed before deleting a Unit',
203-
},
204-
deleteUnitConfirm: {
205-
id: 'course-authoring.library-authoring.unit.delete-confirmation-text',
206-
defaultMessage: 'Delete {unitName}? {message}',
207-
description: 'Confirmation text to display before deleting a unit',
208-
},
209-
deleteUnitConfirmMsg1: {
210-
id: 'course-authoring.library-authoring.unit.delete-confirmation-msg-1',
211-
defaultMessage: 'Any course instances will stop receiving updates.',
212-
description: 'First part of confirmation message to display before deleting a unit',
213-
},
214-
deleteUnitConfirmMsg2: {
215-
id: 'course-authoring.library-authoring.unit.delete-confirmation-msg-2',
216-
defaultMessage: 'Any components will remain in the library.',
217-
description: 'Second part of confirmation message to display before deleting a unit',
218-
},
219-
deleteUnitSuccess: {
220-
id: 'course-authoring.library-authoring.unit.delete.success',
221-
defaultMessage: 'Unit deleted',
222-
description: 'Message to display on delete unit success',
223-
},
224-
deleteUnitFailed: {
225-
id: 'course-authoring.library-authoring.unit.delete-failed-error',
226-
defaultMessage: 'Failed to delete unit',
227-
description: 'Message to display on failure to delete a unit',
228-
},
229-
undoDeleteContainerToastAction: {
230-
id: 'course-authoring.library-authoring.container.undo-delete-container-toast-button',
231-
defaultMessage: 'Undo',
232-
description: 'Toast message to undo deletion of container',
233-
},
234-
undoDeleteContainerToastMessage: {
235-
id: 'course-authoring.library-authoring.container.undo-delete-container-toast-text',
236-
defaultMessage: 'Undo successful',
237-
description: 'Message to display on undo delete container success',
238-
},
239-
undoDeleteUnitToastFailed: {
240-
id: 'course-authoring.library-authoring.unit.undo-delete-unit-failed',
241-
defaultMessage: 'Failed to undo delete Unit operation',
242-
description: 'Message to display on failure to undo delete unit',
243-
},
244-
containerPreviewMoreBlocks: {
245-
id: 'course-authoring.library-authoring.component.container-card-preview.more-blocks',
246-
defaultMessage: '+{count}',
247-
description: 'Count shown when a container has more blocks than will fit on the card preview.',
248-
},
249169
removeComponentFromUnitMenu: {
250170
id: 'course-authoring.library-authoring.unit.component.remove.button',
251171
defaultMessage: 'Remove from unit',
@@ -276,10 +196,5 @@ const messages = defineMessages({
276196
defaultMessage: 'Failed to undo remove component operation',
277197
description: 'Message to display on failure to undo delete component',
278198
},
279-
containerPreviewText: {
280-
id: 'course-authoring.library-authoring.container.preview.text',
281-
defaultMessage: 'Contains {children}.',
282-
description: 'Preview message for section/subsections with the names of children separated by commas',
283-
},
284199
});
285200
export default messages;

0 commit comments

Comments
 (0)