Skip to content

Commit c9896a8

Browse files
authored
[Teak] fix: published name in unit sidebar in container picker & Issues on Inplace Editor (#2140)
Backport of fix: show unit published name in sidebar on content picker [FC-0090] #2100 Backport of fix: Issue on the Inplace editor [FC-0090] #2101
1 parent 4ba8cde commit c9896a8

File tree

10 files changed

+117
-51
lines changed

10 files changed

+117
-51
lines changed

src/generic/inplace-text-editor/InplaceTextEditor.test.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,25 @@ describe('<InplaceTextEditor />', () => {
110110
// Show original text
111111
expect(screen.getByText('Test text')).toBeInTheDocument();
112112
});
113+
114+
it('should disappear edit button while editing', async () => {
115+
render(<InplaceTextEditor text="Test text" onSave={mockOnSave} />);
116+
117+
const title = screen.getByText('Test text');
118+
expect(title).toBeInTheDocument();
119+
120+
const editButton = screen.getByRole('button', { name: /edit/i });
121+
expect(editButton).toBeInTheDocument();
122+
fireEvent.click(editButton);
123+
124+
const textBox = screen.getByRole('textbox');
125+
expect(editButton).not.toBeInTheDocument();
126+
127+
fireEvent.change(textBox, { target: { value: 'New text' } });
128+
fireEvent.keyDown(textBox, { key: 'Enter', code: 'Enter', charCode: 13 });
129+
130+
expect(textBox).not.toBeInTheDocument();
131+
expect(mockOnSave).toHaveBeenCalledWith('New text');
132+
expect(await screen.findByRole('button', { name: /edit/i })).toBeInTheDocument();
133+
});
113134
});

src/generic/inplace-text-editor/index.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,19 @@ export const InplaceTextEditor: React.FC<InplaceTextEditorProps> = ({
9292
/>
9393
)
9494
: (
95-
<Truncate className={textClassName}>
96-
{text}
97-
</Truncate>
95+
<>
96+
<Truncate className={textClassName}>
97+
{text}
98+
</Truncate>
99+
<IconButton
100+
src={Edit}
101+
iconAs={Icon}
102+
alt={intl.formatMessage(messages.editTextButtonAlt)}
103+
onClick={handleEdit}
104+
size="sm"
105+
/>
106+
</>
98107
)}
99-
<IconButton
100-
src={Edit}
101-
iconAs={Icon}
102-
alt={intl.formatMessage(messages.editTextButtonAlt)}
103-
onClick={handleEdit}
104-
size="inline"
105-
/>
106108
</Stack>
107109
);
108110
};

src/library-authoring/LibraryAuthoringPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export const SubHeaderTitle = ({ title }: { title: ReactNode }) => {
113113
const showReadOnlyBadge = readOnly && !componentPickerMode;
114114

115115
return (
116-
<Stack direction="vertical">
116+
<Stack direction="vertical" className="mt-1.5">
117117
{title}
118118
{showReadOnlyBadge && (
119119
<div>

src/library-authoring/__mocks__/library-search.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@
494494
],
495495
"created": 1742221203.895054,
496496
"modified": 1742221203.895054,
497-
"usage_key": "lct:Axim:TEST:unit:test-unit-9284e2",
497+
"usage_key": "lct:org:lib:unit:test-unit-9a207",
498498
"block_type": "unit",
499499
"context_key": "lib:Axim:TEST",
500500
"org": "Axim",
@@ -512,12 +512,18 @@
512512
],
513513
"created": "1742221203.895054",
514514
"modified": "1742221203.895054",
515-
"usage_key": "lct:Axim:TEST:unit:test-unit-9284e2",
515+
"usage_key": "lct:org:lib:unit:test-unit-9a207",
516516
"block_type": "unit",
517517
"context_key": "lib:Axim:TEST",
518518
"org": "Axim",
519519
"access_id": "15",
520-
"num_children": "0"
520+
"num_children": "0",
521+
"published": {
522+
"display_name": "Published Test Unit"
523+
}
524+
},
525+
"published": {
526+
"display_name": "Published Test Unit"
521527
}
522528
}
523529
],

src/library-authoring/component-picker/ComponentPicker.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
mockGetCollectionMetadata,
1515
mockGetContentLibraryV2List,
1616
mockLibraryBlockMetadata,
17+
mockGetContainerMetadata,
1718
} from '../data/api.mocks';
1819

1920
import { ComponentPicker } from './ComponentPicker';
@@ -40,6 +41,7 @@ mockContentSearchConfig.applyMock();
4041
mockGetCollectionMetadata.applyMock();
4142
mockGetContentLibraryV2List.applyMock();
4243
mockLibraryBlockMetadata.applyMock();
44+
mockGetContainerMetadata.applyMock();
4345

4446
let postMessageSpy: jest.SpyInstance;
4547

@@ -99,6 +101,24 @@ describe('<ComponentPicker />', () => {
99101
}, '*');
100102
});
101103

104+
it('should open the unit sidebar', async () => {
105+
render(<ComponentPicker />);
106+
107+
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
108+
fireEvent.click(screen.getByDisplayValue(/lib:sampletaxonomyorg1:tl1/i));
109+
110+
// Wait for the content library to load
111+
await screen.findByText(/Change Library/i);
112+
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
113+
114+
// Click on the unit card to open the sidebar
115+
fireEvent.click((await screen.findByText('Published Test Unit')));
116+
117+
const sidebar = await screen.findByTestId('library-sidebar');
118+
expect(sidebar).toBeInTheDocument();
119+
await waitFor(() => expect(within(sidebar).getByText('Published Test Unit')).toBeInTheDocument());
120+
});
121+
102122
it('should pick component inside a collection using the card', async () => {
103123
render(<ComponentPicker />);
104124

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { useIntl } from '@edx/frontend-platform/i18n';
2+
import { useContext } from 'react';
3+
import { InplaceTextEditor } from '../../generic/inplace-text-editor';
4+
import { ToastContext } from '../../generic/toast-context';
5+
import { useLibraryContext } from '../common/context/LibraryContext';
6+
import { useContainer, useUpdateContainer } from '../data/apiHooks';
7+
import messages from './messages';
8+
9+
interface EditableTitleProps {
10+
containerId: string;
11+
textClassName?: string;
12+
}
13+
14+
export const ContainerEditableTitle = ({ containerId, textClassName }: EditableTitleProps) => {
15+
const intl = useIntl();
16+
17+
const { readOnly, showOnlyPublished } = useLibraryContext();
18+
19+
const { data: container } = useContainer(containerId);
20+
21+
const updateMutation = useUpdateContainer(containerId);
22+
const { showToast } = useContext(ToastContext);
23+
24+
const handleSaveDisplayName = async (newDisplayName: string) => {
25+
try {
26+
await updateMutation.mutateAsync({
27+
displayName: newDisplayName,
28+
});
29+
showToast(intl.formatMessage(messages.updateContainerSuccessMsg));
30+
} catch (err) {
31+
showToast(intl.formatMessage(messages.updateContainerErrorMsg));
32+
}
33+
};
34+
35+
// istanbul ignore if: this should never happen
36+
if (!container) {
37+
return null;
38+
}
39+
40+
return (
41+
<InplaceTextEditor
42+
onSave={handleSaveDisplayName}
43+
text={showOnlyPublished ? (container.publishedDisplayName ?? container.displayName) : container.displayName}
44+
readOnly={readOnly}
45+
textClassName={textClassName}
46+
/>
47+
);
48+
};

src/library-authoring/containers/ContainerInfoHeader.tsx

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
1-
import { useContext } from 'react';
2-
import { useIntl } from '@edx/frontend-platform/i18n';
3-
4-
import { InplaceTextEditor } from '../../generic/inplace-text-editor';
5-
import { ToastContext } from '../../generic/toast-context';
6-
import { useLibraryContext } from '../common/context/LibraryContext';
71
import { useSidebarContext } from '../common/context/SidebarContext';
8-
import { useContainer, useUpdateContainer } from '../data/apiHooks';
9-
import messages from './messages';
2+
import { ContainerEditableTitle } from './ContainerEditableTitle';
103

114
const ContainerInfoHeader = () => {
12-
const intl = useIntl();
13-
14-
const { readOnly } = useLibraryContext();
155
const { sidebarComponentInfo } = useSidebarContext();
166

177
const containerId = sidebarComponentInfo?.id;
@@ -20,32 +10,9 @@ const ContainerInfoHeader = () => {
2010
throw new Error('containerId is required');
2111
}
2212

23-
const { data: container } = useContainer(containerId);
24-
25-
const updateMutation = useUpdateContainer(containerId);
26-
const { showToast } = useContext(ToastContext);
27-
28-
const handleSaveDisplayName = async (newDisplayName: string) => {
29-
try {
30-
await updateMutation.mutateAsync({
31-
displayName: newDisplayName,
32-
});
33-
showToast(intl.formatMessage(messages.updateContainerSuccessMsg));
34-
} catch (err) {
35-
showToast(intl.formatMessage(messages.updateContainerErrorMsg));
36-
throw err;
37-
}
38-
};
39-
40-
if (!container) {
41-
return null;
42-
}
43-
4413
return (
45-
<InplaceTextEditor
46-
onSave={handleSaveDisplayName}
47-
text={container.displayName}
48-
readOnly={readOnly}
14+
<ContainerEditableTitle
15+
containerId={containerId}
4916
textClassName="font-weight-bold m-1.5"
5017
/>
5118
);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ mockGetContainerMetadata.containerData = {
495495
id: 'lct:org:lib:unit:test-unit-9a2072',
496496
containerType: 'unit',
497497
displayName: 'Test Unit',
498+
publishedDisplayName: 'Published Test Unit',
498499
created: '2024-09-19T10:00:00Z',
499500
createdBy: 'test_author',
500501
lastPublished: '2024-09-20T10:00:00Z',

src/library-authoring/data/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ export interface Container {
600600
id: string;
601601
containerType: 'unit';
602602
displayName: string;
603+
publishedDisplayName: string;
603604
lastPublished: string | null;
604605
publishedBy: string | null;
605606
createdBy: string | null;

src/library-authoring/data/apiHooks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ export const useUpdateContainer = (containerId: string) => {
615615
return useMutation({
616616
mutationFn: (data: api.UpdateContainerDataRequest) => api.updateContainerMetadata(containerId, data),
617617
onMutate: (data) => {
618-
const previousData = queryClient.getQueryData(containerQueryKey) as api.CollectionMetadata;
618+
const previousData = queryClient.getQueryData(containerQueryKey) as api.Container;
619619
queryClient.setQueryData(containerQueryKey, {
620620
...previousData,
621621
...data,

0 commit comments

Comments
 (0)