fix: set unit preview readonly on sidebar (#2008)

Make the unit preview on the sidebar read-only and add `Truncate` to the `InplaceTextEditor`
This commit is contained in:
Rômulo Penido
2025-05-29 15:33:23 -03:00
committed by GitHub
parent 3fc0f27d67
commit f18274533e
4 changed files with 44 additions and 21 deletions

View File

@@ -6,6 +6,7 @@ import {
Form,
Icon,
IconButton,
Truncate,
Stack,
} from '@openedx/paragon';
import { Edit } from '@openedx/paragon/icons';
@@ -68,9 +69,9 @@ export const InplaceTextEditor: React.FC<InplaceTextEditorProps> = ({
// In that case, we show the new text instead of the original in read-only mode as an optimistic update.
if (readOnly || pendingSaveText) {
return (
<span className={textClassName}>
<Truncate className={textClassName}>
{pendingSaveText || text}
</span>
</Truncate>
);
}
@@ -91,9 +92,9 @@ export const InplaceTextEditor: React.FC<InplaceTextEditorProps> = ({
/>
)
: (
<span className={textClassName}>
<Truncate className={textClassName}>
{text}
</span>
</Truncate>
)}
<IconButton
src={Edit}

View File

@@ -108,4 +108,20 @@ describe('<UnitInfo />', () => {
expect(await screen.findByTestId('unit-info-menu-toggle')).toBeInTheDocument();
expect(screen.getByText(/text block published 1/i)).toBeInTheDocument();
});
it('shows the preview tab by default and the component are readonly', async () => {
render();
const previewTab = await screen.findByText('Preview');
expect(previewTab).toBeInTheDocument();
expect(previewTab).toHaveAttribute('aria-selected', 'true');
// Check that there are no edit buttons for components titles
expect(screen.queryAllByRole('button', { name: /edit/i }).length).toBe(0);
// Check that there are no drag handle for components
expect(screen.queryAllByRole('button', { name: 'Drag to reorder' }).length).toBe(0);
// Check that there are no menu buttons for components
expect(screen.queryAllByRole('button', { name: /component actions menu/i }).length).toBe(0);
});
});

View File

@@ -162,7 +162,11 @@ const UnitInfo = () => {
activeKey={tab}
onSelect={handleTabChange}
>
{renderTab(UNIT_INFO_TABS.Preview, <LibraryUnitBlocks preview />, intl.formatMessage(messages.previewTabTitle))}
{renderTab(
UNIT_INFO_TABS.Preview,
<LibraryUnitBlocks readOnly />,
intl.formatMessage(messages.previewTabTitle),
)}
{renderTab(UNIT_INFO_TABS.Manage, <ContainerOrganize />, intl.formatMessage(messages.manageTabTitle))}
{renderTab(UNIT_INFO_TABS.Settings, 'Unit Settings', intl.formatMessage(messages.settingsTabTitle))}
</Tabs>

View File

@@ -49,12 +49,12 @@ interface LibraryBlockMetadataWithUniqueId extends LibraryBlockMetadata {
interface ComponentBlockProps {
block: LibraryBlockMetadataWithUniqueId;
preview?: boolean;
readOnly?: boolean;
isDragging?: boolean;
}
/** Component header */
const BlockHeader = ({ block }: ComponentBlockProps) => {
const BlockHeader = ({ block, readOnly }: ComponentBlockProps) => {
const intl = useIntl();
const { showOnlyPublished } = useLibraryContext();
const { showToast } = useContext(ToastContext);
@@ -98,13 +98,13 @@ const BlockHeader = ({ block }: ComponentBlockProps) => {
gap={2}
className="font-weight-bold"
// Prevent parent card from being clicked.
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
onClick={(e) => e.stopPropagation()}
>
<Icon src={getItemIcon(block.blockType)} />
<InplaceTextEditor
onSave={handleSaveDisplayName}
text={showOnlyPublished ? (block.publishedDisplayName ?? block.displayName) : block.displayName}
readOnly={readOnly}
/>
</Stack>
<ActionRow.Spacer />
@@ -112,7 +112,6 @@ const BlockHeader = ({ block }: ComponentBlockProps) => {
direction="horizontal"
gap={3}
// Prevent parent card from being clicked.
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
onClick={(e) => e.stopPropagation()}
>
{!showOnlyPublished && block.hasUnpublishedChanges && (
@@ -126,15 +125,15 @@ const BlockHeader = ({ block }: ComponentBlockProps) => {
</Stack>
</Badge>
)}
<TagCount size="sm" count={block.tagsCount} onClick={jumpToManageTags} />
<ComponentMenu usageKey={block.originalId} />
<TagCount size="sm" count={block.tagsCount} onClick={readOnly ? undefined : jumpToManageTags} />
{!readOnly && <ComponentMenu usageKey={block.originalId} />}
</Stack>
</>
);
};
/** ComponentBlock to render preview of given component under Unit */
const ComponentBlock = ({ block, preview, isDragging }: ComponentBlockProps) => {
const ComponentBlock = ({ block, readOnly, isDragging }: ComponentBlockProps) => {
const { showOnlyPublished } = useLibraryContext();
const { navigateTo } = useLibraryRoutes();
@@ -193,16 +192,16 @@ const ComponentBlock = ({ block, preview, isDragging }: ComponentBlockProps) =>
<SortableItem
id={block.id}
componentStyle={getComponentStyle()}
actions={<BlockHeader block={block} />}
actions={<BlockHeader block={block} readOnly={readOnly} />}
actionStyle={{
borderRadius: '8px 8px 0px 0px',
padding: '0.5rem 1rem',
background: '#FBFAF9',
borderBottom: 'solid 1px #E1DDDB',
}}
isClickable
onClick={(e: { detail: number; }) => handleComponentSelection(e.detail)}
disabled={preview}
isClickable={!readOnly}
onClick={!readOnly ? (e: { detail: number; }) => handleComponentSelection(e.detail) : undefined}
disabled={readOnly}
cardClassName={selected ? 'selected' : undefined}
>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
@@ -227,12 +226,12 @@ const ComponentBlock = ({ block, preview, isDragging }: ComponentBlockProps) =>
interface LibraryUnitBlocksProps {
/** set to true if it is rendered as preview
* This disables drag and drop
* This disables drag and drop, title edit and menus
*/
preview?: boolean;
readOnly?: boolean;
}
export const LibraryUnitBlocks = ({ preview }: LibraryUnitBlocksProps) => {
export const LibraryUnitBlocks = ({ readOnly: componentReadOnly }: LibraryUnitBlocksProps) => {
const intl = useIntl();
const [orderedBlocks, setOrderedBlocks] = useState<LibraryBlockMetadataWithUniqueId[]>([]);
const [isAddLibraryContentModalOpen, showAddLibraryContentModal, closeAddLibraryContentModal] = useToggle();
@@ -240,7 +239,9 @@ export const LibraryUnitBlocks = ({ preview }: LibraryUnitBlocksProps) => {
const [hidePreviewFor, setHidePreviewFor] = useState<string | null>(null);
const { showToast } = useContext(ToastContext);
const { unitId, readOnly, showOnlyPublished } = useLibraryContext();
const { unitId, readOnly: libraryReadOnly, showOnlyPublished } = useLibraryContext();
const readOnly = componentReadOnly || libraryReadOnly;
const { openAddContentSidebar } = useSidebarContext();
@@ -305,10 +306,11 @@ export const LibraryUnitBlocks = ({ preview }: LibraryUnitBlocksProps) => {
key={`${block.originalId}-${idx}-${block.modified}`}
block={block}
isDragging={hidePreviewFor === block.id}
readOnly={readOnly}
/>
))}
</DraggableList>
{!preview && (
{!readOnly && (
<div className="d-flex">
<div className="w-100 mr-2">
<Button