mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-25 08:50:18 +00:00
* fix(#17016): apply Read-Only Mode to All Custom and Built-In Nodes in Block Editor * test: add unit test * fix playwright test --------- Co-authored-by: Ashish Gupta <ashish@getcollate.io>
This commit is contained in:
parent
7ef90c3628
commit
8434fe2c50
@ -186,7 +186,7 @@ test.describe('Activity feed', () => {
|
||||
test('Update Description Task on Columns', async ({ page }) => {
|
||||
const firstTaskValue: TaskDetails = {
|
||||
term: entity.entity.name,
|
||||
assignee: `${user.data.firstName}.${user.data.lastName}`,
|
||||
assignee: user.responseData.name,
|
||||
description: 'Column Description 1',
|
||||
columnName: entity.entity.columns[0].name,
|
||||
oldDescription: entity.entity.columns[0].description,
|
||||
|
@ -33,7 +33,7 @@ interface BlockMenuProps {
|
||||
export const BlockMenu = (props: BlockMenuProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { editor } = props;
|
||||
const { view } = editor;
|
||||
const { view, isEditable } = editor;
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
const popup = useRef<Instance | null>(null);
|
||||
|
||||
@ -127,7 +127,10 @@ export const BlockMenu = (props: BlockMenuProps) => {
|
||||
}, [editor]);
|
||||
|
||||
useEffect(() => {
|
||||
if (menuRef.current) {
|
||||
/**
|
||||
* Create a new tippy instance for the block menu if the editor is editable
|
||||
*/
|
||||
if (menuRef.current && isEditable) {
|
||||
menuRef.current.remove();
|
||||
menuRef.current.style.visibility = 'visible';
|
||||
|
||||
@ -150,7 +153,7 @@ export const BlockMenu = (props: BlockMenuProps) => {
|
||||
popup.current?.destroy();
|
||||
popup.current = null;
|
||||
};
|
||||
}, []);
|
||||
}, [isEditable]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', handleClickDragHandle);
|
||||
|
@ -111,12 +111,14 @@ const BubbleMenu: FC<BubbleMenuProps> = ({ editor, toggleLink }) => {
|
||||
// - the selection is empty
|
||||
// - the selection is a node selection (for drag handles)
|
||||
// - link is active
|
||||
// - editor is not editable
|
||||
if (
|
||||
editor.isActive('image') ||
|
||||
empty ||
|
||||
isNodeSelection(selection) ||
|
||||
editor.isActive('link') ||
|
||||
editor.isActive('table')
|
||||
editor.isActive('table') ||
|
||||
!editor.isEditable
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
@ -78,6 +78,11 @@ const EditorSlots = forwardRef<EditorSlotsRef, EditorSlotsProps>(
|
||||
const handleLinkPopup = (
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>
|
||||
) => {
|
||||
// if editor is not editable, do not show the link popup
|
||||
if (!editor?.isEditable) {
|
||||
return;
|
||||
}
|
||||
|
||||
let popup: Instance<Props>[] = [];
|
||||
let component: ReactRenderer;
|
||||
const target = e.target as HTMLElement;
|
||||
|
@ -32,6 +32,9 @@ const mockNodeViewProps = {
|
||||
node: mockNode,
|
||||
extension: mockExtension,
|
||||
updateAttributes: mockUpdateAttributes,
|
||||
editor: {
|
||||
isEditable: true,
|
||||
},
|
||||
} as unknown as NodeViewProps;
|
||||
|
||||
describe('CalloutComponent', () => {
|
||||
@ -70,4 +73,29 @@ describe('CalloutComponent', () => {
|
||||
expect(screen.getByTestId('callout-note')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('callout-danger')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render the popover when callout button is clicked and editor is not editable', async () => {
|
||||
const nodeViewProps = {
|
||||
node: mockNode,
|
||||
extension: mockExtension,
|
||||
updateAttributes: mockUpdateAttributes,
|
||||
editor: {
|
||||
isEditable: false,
|
||||
},
|
||||
} as unknown as NodeViewProps;
|
||||
|
||||
await act(async () => {
|
||||
render(<CalloutComponent {...nodeViewProps} />);
|
||||
});
|
||||
|
||||
const calloutButton = screen.getByTestId('callout-info-btn');
|
||||
|
||||
await act(async () => {
|
||||
userEvent.click(calloutButton);
|
||||
});
|
||||
|
||||
const popover = screen.queryByRole('tooltip');
|
||||
|
||||
expect(popover).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -45,12 +45,18 @@ const CalloutComponent: FC<NodeViewProps> = ({
|
||||
node,
|
||||
extension,
|
||||
updateAttributes,
|
||||
editor,
|
||||
}) => {
|
||||
const { calloutType } = node.attrs;
|
||||
const [isPopupVisible, setIsPopupVisible] = useState<boolean>(false);
|
||||
const CallOutIcon =
|
||||
CALLOUT_CONTENT[calloutType as keyof typeof CALLOUT_CONTENT];
|
||||
|
||||
const handlePopoverVisibleChange = (visible: boolean) => {
|
||||
// Only show the popover when the editor is in editable mode
|
||||
setIsPopupVisible(visible && editor.isEditable);
|
||||
};
|
||||
|
||||
return (
|
||||
<NodeViewWrapper as="div" className="om-react-node">
|
||||
<div
|
||||
@ -73,7 +79,7 @@ const CalloutComponent: FC<NodeViewProps> = ({
|
||||
placement="bottomRight"
|
||||
showArrow={false}
|
||||
trigger="click"
|
||||
onOpenChange={setIsPopupVisible}>
|
||||
onOpenChange={handlePopoverVisibleChange}>
|
||||
<Button
|
||||
className="callout-type-btn"
|
||||
data-testid={`callout-${calloutType}-btn`}
|
||||
|
@ -25,6 +25,7 @@ import './math-equation.less';
|
||||
export const MathEquationComponent: FC<NodeViewProps> = ({
|
||||
node,
|
||||
updateAttributes,
|
||||
editor,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const inputRef = React.useRef<TextAreaRef>(null);
|
||||
@ -78,7 +79,8 @@ export const MathEquationComponent: FC<NodeViewProps> = ({
|
||||
) : (
|
||||
<Latex>{equation}</Latex>
|
||||
)}
|
||||
{!isEditing && (
|
||||
{/* Show edit button only when the editor is editable */}
|
||||
{!isEditing && editor.isEditable && (
|
||||
<Tooltip
|
||||
title={t('label.edit-entity', { entity: t('label.equation') })}>
|
||||
<Button
|
||||
|
@ -26,10 +26,15 @@ const mockNode = {
|
||||
const mockDeleteNode = jest.fn();
|
||||
const mockUpdateAttributes = jest.fn();
|
||||
|
||||
const mockEditor = {
|
||||
isEditable: true,
|
||||
};
|
||||
|
||||
const mockNodeViewProps = {
|
||||
node: mockNode,
|
||||
updateAttributes: mockUpdateAttributes,
|
||||
deleteNode: mockDeleteNode,
|
||||
editor: mockEditor,
|
||||
} as unknown as NodeViewProps;
|
||||
|
||||
describe('ImageComponent', () => {
|
||||
@ -68,6 +73,33 @@ describe('ImageComponent', () => {
|
||||
expect(screen.getByText('label.embed-link')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should not render the popover when image node is clicked and the editor isn't editable", async () => {
|
||||
const nonEditableEditor = {
|
||||
isEditable: false,
|
||||
};
|
||||
|
||||
const nonEditableNodeViewProps = {
|
||||
node: mockNode,
|
||||
updateAttributes: mockUpdateAttributes,
|
||||
deleteNode: mockDeleteNode,
|
||||
editor: nonEditableEditor,
|
||||
} as unknown as NodeViewProps;
|
||||
|
||||
await act(async () => {
|
||||
render(<ImageComponent {...nonEditableNodeViewProps} />);
|
||||
});
|
||||
|
||||
const imageNode = screen.getByTestId('uploaded-image-node');
|
||||
|
||||
await act(async () => {
|
||||
userEvent.click(imageNode);
|
||||
});
|
||||
|
||||
const popover = screen.queryByRole('tooltip');
|
||||
|
||||
expect(popover).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the upload tab by default', async () => {
|
||||
await act(async () => {
|
||||
render(<ImageComponent {...mockNodeViewProps} />);
|
||||
|
@ -173,6 +173,7 @@ const ImageComponent: FC<NodeViewProps> = ({
|
||||
node,
|
||||
updateAttributes,
|
||||
deleteNode,
|
||||
editor,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { src, alt } = node.attrs;
|
||||
@ -181,6 +182,11 @@ const ImageComponent: FC<NodeViewProps> = ({
|
||||
const [isUploading, setIsUploading] = useState<boolean>(false);
|
||||
const [isPopupVisible, setIsPopupVisible] = useState<boolean>(!isValidSource);
|
||||
|
||||
const handlePopoverVisibleChange = (visible: boolean) => {
|
||||
// Only show the popover when the editor is in editable mode
|
||||
setIsPopupVisible(visible && editor.isEditable);
|
||||
};
|
||||
|
||||
return (
|
||||
<NodeViewWrapper as="div" className="om-react-node">
|
||||
<div className={classNames({ 'om-image-node-wrapper': isPopupVisible })}>
|
||||
@ -203,7 +209,7 @@ const ImageComponent: FC<NodeViewProps> = ({
|
||||
placement="bottom"
|
||||
showArrow={false}
|
||||
trigger="click"
|
||||
onOpenChange={setIsPopupVisible}>
|
||||
onOpenChange={handlePopoverVisibleChange}>
|
||||
{isValidSource ? (
|
||||
<div className="om-image-node-uploaded">
|
||||
<img
|
||||
|
@ -26,7 +26,7 @@ interface TableMenuProps {
|
||||
|
||||
const TableMenu = (props: TableMenuProps) => {
|
||||
const { editor } = props;
|
||||
const { view } = editor;
|
||||
const { view, isEditable } = editor;
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
const tableMenuPopup = useRef<Instance | null>(null);
|
||||
|
||||
@ -44,7 +44,7 @@ const TableMenu = (props: TableMenuProps) => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (menuRef.current) {
|
||||
if (menuRef.current && isEditable) {
|
||||
menuRef.current.remove();
|
||||
menuRef.current.style.visibility = 'visible';
|
||||
|
||||
@ -67,7 +67,7 @@ const TableMenu = (props: TableMenuProps) => {
|
||||
tableMenuPopup.current?.destroy();
|
||||
tableMenuPopup.current = null;
|
||||
};
|
||||
}, []);
|
||||
}, [isEditable]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('mousedown', handleMouseDown);
|
||||
|
Loading…
x
Reference in New Issue
Block a user