Skip to content

Commit 4ddb8c3

Browse files
authored
feat: edit components in unit page [FC-0083] (#1821)
Allows authors to edit components from unit page. It makes sure that the component preview is updated on save, allows user to double click and open editor in modal etc.
1 parent 3b2adc2 commit 4ddb8c3

8 files changed

Lines changed: 48 additions & 20 deletions

File tree

src/content-tags-drawer/data/api.mocks.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export async function mockContentTaxonomyTagsData(contentId: string): Promise<an
1313
case thisMock.languageWithTagsId: return thisMock.languageWithTags;
1414
case thisMock.languageWithoutTagsId: return thisMock.languageWithoutTags;
1515
case thisMock.largeTagsId: return thisMock.largeTags;
16+
case thisMock.containerTagsId: return thisMock.largeTags;
1617
case thisMock.emptyTagsId: return thisMock.emptyTags;
1718
default: throw new Error(`No mock has been set up for contentId "${contentId}"`);
1819
}
@@ -204,6 +205,7 @@ mockContentTaxonomyTagsData.emptyTagsId = 'block-v1:EmptyTagsOrg+STC1+2023_1+typ
204205
mockContentTaxonomyTagsData.emptyTags = {
205206
taxonomies: [],
206207
};
208+
mockContentTaxonomyTagsData.containerTagsId = 'lct:org:lib:unit:container_tags';
207209
mockContentTaxonomyTagsData.applyMock = () => jest.spyOn(api, 'getContentTaxonomyTagsData').mockImplementation(mockContentTaxonomyTagsData);
208210

209211
/**

src/library-authoring/add-content/PickLibraryContentModal.test.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const mockAddItemsToCollection = jest.fn();
3232
const mockAddComponentsToContainer = jest.fn();
3333
jest.spyOn(api, 'addItemsToCollection').mockImplementation(mockAddItemsToCollection);
3434
jest.spyOn(api, 'addComponentsToContainer').mockImplementation(mockAddComponentsToContainer);
35+
const unitId = 'lct:Axim:TEST:unit:test-unit-1';
3536

3637
const render = (context: 'collection' | 'unit') => baseRender(<PickLibraryContentModal isOpen onClose={onClose} />, {
3738
path: context === 'collection'
@@ -40,7 +41,7 @@ const render = (context: 'collection' | 'unit') => baseRender(<PickLibraryConten
4041
params: {
4142
libraryId,
4243
...(context === 'collection' && { collectionId: 'collectionId' }),
43-
...(context === 'unit' && { unitId: 'unitId' }),
44+
...(context === 'unit' && { unitId }),
4445
},
4546
extraWrapper: ({ children }) => (
4647
<LibraryProvider
@@ -85,7 +86,7 @@ describe('<PickLibraryContentModal />', () => {
8586
);
8687
} else {
8788
expect(mockAddComponentsToContainer).toHaveBeenCalledWith(
88-
'unitId',
89+
unitId,
8990
['lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd'],
9091
);
9192
}
@@ -123,7 +124,7 @@ describe('<PickLibraryContentModal />', () => {
123124
);
124125
} else {
125126
expect(mockAddComponentsToContainer).toHaveBeenCalledWith(
126-
'unitId',
127+
unitId,
127128
['lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd'],
128129
);
129130
}

src/library-authoring/data/api.mocks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ export async function mockGetContainerMetadata(containerId: string): Promise<api
482482
mockGetContainerMetadata.containerId = 'lct:org:lib:unit:test-unit-9a207';
483483
mockGetContainerMetadata.containerIdError = 'lct:org:lib:unit:container_error';
484484
mockGetContainerMetadata.containerIdLoading = 'lct:org:lib:unit:container_loading';
485-
mockGetContainerMetadata.containerIdForTags = mockContentTaxonomyTagsData.largeTagsId;
485+
mockGetContainerMetadata.containerIdForTags = mockContentTaxonomyTagsData.containerTagsId;
486486
mockGetContainerMetadata.containerIdWithCollections = 'lct:org:lib:unit:container_collections';
487487
mockGetContainerMetadata.containerData = {
488488
id: 'lct:org:lib:unit:test-unit-9a2072',

src/library-authoring/data/api.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ describe('library data API', () => {
118118
it('should add components to unit', async () => {
119119
const { axiosMock } = initializeMocks();
120120
const componentId = 'lb:org:lib:html:1';
121-
const containerId = 'ltc:org:lib:unit:1';
121+
const containerId = 'lct:org:lib:unit:1';
122122
const url = api.getLibraryContainerChildrenApiUrl(containerId);
123123

124124
axiosMock.onPost(url).reply(200);

src/library-authoring/data/apiHooks.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ describe('library api hooks', () => {
257257

258258
it('should add components to container', async () => {
259259
const componentId = 'lb:org:lib:html:1';
260-
const containerId = 'ltc:org:lib:unit:1';
260+
const containerId = 'lct:org:lib:unit:1';
261261

262262
const url = getLibraryContainerChildrenApiUrl(containerId);
263263

src/library-authoring/data/apiHooks.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,27 @@ export const libraryAuthoringQueryKeys = {
101101
'blockTypes',
102102
libraryId,
103103
],
104-
container: (containerId?: string) => [
105-
...libraryAuthoringQueryKeys.all,
106-
'container',
107-
containerId,
108-
],
109-
containerChildren: (containerId?: string) => [
110-
...libraryAuthoringQueryKeys.all,
111-
'container',
112-
containerId,
113-
'children',
114-
],
104+
container: (containerId?: string) => {
105+
const baseKey = containerId
106+
? libraryAuthoringQueryKeys.contentLibrary(getLibraryId(containerId))
107+
: libraryAuthoringQueryKeys.all;
108+
return [
109+
...baseKey,
110+
'container',
111+
containerId,
112+
];
113+
},
114+
containerChildren: (containerId?: string) => {
115+
const baseKey = containerId
116+
? libraryAuthoringQueryKeys.contentLibrary(getLibraryId(containerId))
117+
: libraryAuthoringQueryKeys.all;
118+
return [
119+
...baseKey,
120+
'container',
121+
containerId,
122+
'children',
123+
];
124+
},
115125
};
116126

117127
export const xblockQueryKeys = {

src/library-authoring/units/LibraryUnitBlocks.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { useLibraryRoutes } from '../routes';
2626
import messages from './messages';
2727
import { useSidebarContext } from '../common/context/SidebarContext';
2828
import { ToastContext } from '../../generic/toast-context';
29+
import { canEditComponent } from '../components/ComponentEditorModal';
2930

3031
/** Components that need large min height in preview */
3132
const LARGE_COMPONENTS = [
@@ -90,6 +91,7 @@ export const LibraryUnitBlocks = ({ preview }: LibraryUnitBlocksProps) => {
9091
componentId,
9192
readOnly,
9293
setComponentId,
94+
openComponentEditor,
9395
} = useLibraryContext();
9496

9597
const {
@@ -131,9 +133,14 @@ export const LibraryUnitBlocks = ({ preview }: LibraryUnitBlocksProps) => {
131133
closeManageTagsDrawer();
132134
};
133135

134-
const handleComponentSelection = (block: LibraryBlockMetadata) => {
136+
const handleComponentSelection = (block: LibraryBlockMetadata, numberOfClicks: number) => {
135137
setComponentId(block.id);
136138
navigateTo({ componentId: block.id });
139+
const canEdit = canEditComponent(block.id);
140+
if (numberOfClicks > 1 && canEdit) {
141+
// Open editor on double click.
142+
openComponentEditor(block.id);
143+
}
137144
};
138145

139146
/* istanbul ignore next */
@@ -166,7 +173,7 @@ export const LibraryUnitBlocks = ({ preview }: LibraryUnitBlocksProps) => {
166173
};
167174

168175
const renderedBlocks = orderedBlocks?.map((block) => (
169-
<IframeProvider key={block.id}>
176+
<IframeProvider key={block.id + block.modified}>
170177
<SortableItem
171178
id={block.id}
172179
componentStyle={null}
@@ -179,7 +186,7 @@ export const LibraryUnitBlocks = ({ preview }: LibraryUnitBlocksProps) => {
179186
outline: hidePreviewFor === block.id && '2px dashed gray',
180187
}}
181188
isClickable
182-
onClick={() => handleComponentSelection(block)}
189+
onClick={(e: { detail: number; }) => handleComponentSelection(block, e.detail)}
183190
disabled={preview}
184191
>
185192
{hidePreviewFor !== block.id && (

src/library-authoring/units/LibraryUnitPage.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,12 @@ describe('<LibraryUnitPage />', () => {
231231
});
232232
await waitFor(() => expect(mockShowToast).toHaveBeenLastCalledWith('Failed to update components order'));
233233
});
234+
235+
it('should show editor on double click', async () => {
236+
renderLibraryUnitPage();
237+
const component = await screen.findByText('text block 0');
238+
// trigger double click
239+
userEvent.click(component, undefined, { clickCount: 2 });
240+
expect(await screen.findByRole('dialog', { name: 'Editor Dialog' })).toBeInTheDocument();
241+
});
234242
});

0 commit comments

Comments
 (0)