-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Menu option to delete a component + small fixes (#1408)
* feat: menu option to delete a component * feat: close component sidebar if it's open when that component id deleted * feat: hide unsupported block types from the "Add Content" menu * fix: expand and internationalize the "component usage" text
- Loading branch information
1 parent
d49fc85
commit 6ae68bd
Showing
13 changed files
with
261 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
src/library-authoring/components/ComponentDeleter.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { getLibraryId } from '../../generic/key-utils'; | ||
import { | ||
fireEvent, | ||
render, | ||
screen, | ||
initializeMocks, | ||
waitFor, | ||
} from '../../testUtils'; | ||
import { LibraryProvider } from '../common/context'; | ||
import { mockContentLibrary, mockDeleteLibraryBlock, mockLibraryBlockMetadata } from '../data/api.mocks'; | ||
import ComponentDeleter from './ComponentDeleter'; | ||
|
||
mockContentLibrary.applyMock(); // Not required, but avoids 404 errors in the logs when <LibraryProvider> loads data | ||
mockLibraryBlockMetadata.applyMock(); | ||
const mockDelete = mockDeleteLibraryBlock.applyMock(); | ||
|
||
const usageKey = mockLibraryBlockMetadata.usageKeyPublished; | ||
|
||
const renderArgs = { | ||
extraWrapper: ({ children }: { children: React.ReactNode }) => ( | ||
<LibraryProvider libraryId={getLibraryId(usageKey)}>{children}</LibraryProvider> | ||
), | ||
}; | ||
|
||
describe('<ComponentDeleter />', () => { | ||
beforeEach(() => { | ||
initializeMocks(); | ||
}); | ||
|
||
it('is invisible when isConfirmingDelete is false', async () => { | ||
const mockCancel = jest.fn(); | ||
render(<ComponentDeleter usageKey={usageKey} isConfirmingDelete={false} cancelDelete={mockCancel} />, renderArgs); | ||
|
||
const modal = screen.queryByRole('dialog', { name: 'Delete Component' }); | ||
expect(modal).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('should shows a confirmation prompt the card with title and description', async () => { | ||
const mockCancel = jest.fn(); | ||
render(<ComponentDeleter usageKey={usageKey} isConfirmingDelete cancelDelete={mockCancel} />, renderArgs); | ||
|
||
const modal = screen.getByRole('dialog', { name: 'Delete Component' }); | ||
expect(modal).toBeVisible(); | ||
|
||
// It should mention the component's name in the confirm dialog: | ||
await screen.findByText('Introduction to Testing 2'); | ||
|
||
// Clicking cancel will cancel: | ||
const cancelButton = screen.getByRole('button', { name: 'Cancel' }); | ||
fireEvent.click(cancelButton); | ||
expect(mockCancel).toHaveBeenCalled(); | ||
}); | ||
|
||
it('deletes the block when confirmed', async () => { | ||
const mockCancel = jest.fn(); | ||
render(<ComponentDeleter usageKey={usageKey} isConfirmingDelete cancelDelete={mockCancel} />, renderArgs); | ||
|
||
const modal = screen.getByRole('dialog', { name: 'Delete Component' }); | ||
expect(modal).toBeVisible(); | ||
|
||
const deleteButton = screen.getByRole('button', { name: 'Delete' }); | ||
fireEvent.click(deleteButton); | ||
await waitFor(() => { | ||
expect(mockDelete).toHaveBeenCalled(); | ||
}); | ||
expect(mockCancel).toHaveBeenCalled(); // In order to close the modal, this also gets called. | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import React from 'react'; | ||
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; | ||
import { | ||
ActionRow, | ||
AlertModal, | ||
Button, | ||
} from '@openedx/paragon'; | ||
import { Warning } from '@openedx/paragon/icons'; | ||
|
||
import { useLibraryContext } from '../common/context'; | ||
import { useDeleteLibraryBlock, useLibraryBlockMetadata } from '../data/apiHooks'; | ||
import messages from './messages'; | ||
|
||
/** | ||
* Helper component to load and display the name of the block. | ||
* | ||
* This needs to be a separate component so that we only query the metadata of | ||
* the block when needed (when this is displayed), not on every card shown in | ||
* the search results. | ||
*/ | ||
const BlockName = (props: { usageKey: string }) => { | ||
const { data: blockMetadata } = useLibraryBlockMetadata(props.usageKey); | ||
|
||
// eslint-disable-next-line react/jsx-no-useless-fragment | ||
return <>{blockMetadata?.displayName}</> ?? <FormattedMessage {...messages.deleteComponentNamePlaceholder} />; | ||
}; | ||
|
||
interface Props { | ||
usageKey: string; | ||
/** If true, show a confirmation modal that asks the user if they want to delete this component. */ | ||
isConfirmingDelete: boolean; | ||
cancelDelete: () => void; | ||
} | ||
|
||
const ComponentDeleter = ({ usageKey, ...props }: Props) => { | ||
const intl = useIntl(); | ||
const { | ||
sidebarComponentUsageKey, | ||
closeLibrarySidebar, | ||
} = useLibraryContext(); | ||
|
||
const deleteComponentMutation = useDeleteLibraryBlock(); | ||
const doDelete = React.useCallback(() => { | ||
deleteComponentMutation.mutateAsync({ usageKey }); | ||
props.cancelDelete(); | ||
// Close the sidebar if it's still open showing the deleted component: | ||
if (usageKey === sidebarComponentUsageKey) { | ||
closeLibrarySidebar(); | ||
} | ||
}, [usageKey, sidebarComponentUsageKey, closeLibrarySidebar]); | ||
|
||
if (!props.isConfirmingDelete) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<AlertModal | ||
title={intl.formatMessage(messages.deleteComponentWarningTitle)} | ||
isOpen | ||
onClose={props.cancelDelete} | ||
variant="warning" | ||
icon={Warning} | ||
footerNode={( | ||
<ActionRow> | ||
<Button variant="tertiary" onClick={props.cancelDelete}><FormattedMessage {...messages.deleteComponentCancelButton} /></Button> | ||
<Button variant="danger" onClick={doDelete}><FormattedMessage {...messages.deleteComponentButton} /></Button> | ||
</ActionRow> | ||
)} | ||
> | ||
<p> | ||
<FormattedMessage | ||
{...messages.deleteComponentConfirm} | ||
values={{ | ||
componentName: ( | ||
<strong><BlockName usageKey={usageKey} /></strong> | ||
), | ||
}} | ||
/> | ||
</p> | ||
</AlertModal> | ||
); | ||
}; | ||
|
||
export default ComponentDeleter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.