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:
@@ -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}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user