mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-22 16:08:13 +00:00
This commit is contained in:
parent
bd4071bd64
commit
a1e2b27f39
@ -10,7 +10,7 @@
|
|||||||
"updatedAt": 1647046363996,
|
"updatedAt": 1647046363996,
|
||||||
"updatedBy": "anonymous",
|
"updatedBy": "anonymous",
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
"message": "Added **tags**: `Tier.Tier2`",
|
"message": "Updated **columns** : <span class=\"diff-added\">account_category_code, </span>account_type_code, account_type_desc, <span class=\"diff-removed\">account_category_code</span><span class=\"diff-added\">account_type_desc_eng</span>, <span class=\"diff-removed\">eca_ind</span><span class=\"diff-added\">ban_type_desc</span>, <span class=\"diff-removed\">bill_production_ind</span><span class=\"diff-added\">ban_type_key</span>, <span class=\"diff-removed\">collection_waive_ind</span><span class=\"diff-added\">bill_production_ind</span>, <span class=\"diff-removed\">vip_status</span><span class=\"diff-added\">business_type</span>, <span class=\"diff-removed\">ban_type_desc</span><span class=\"diff-added\">check_in_crm</span>, <span class=\"diff-removed\">non_commercial_ind</span><span class=\"diff-added\">collection_waive_ind</span>, <span class=\"diff-removed\">legacy_account_category, </span>corporate_category, <span class=\"diff-removed\">ban_type_key</span><span class=\"diff-added\">currency_key</span>, <span class=\"diff-removed\">segment_key</span><span class=\"diff-added\">eca_ind</span>, <span class=\"diff-removed\">check_in_crm</span><span class=\"diff-added\">legacy_account_category</span>, <span class=\"diff-removed\">currency_key</span><span class=\"diff-added\">legal_person_ind</span>, <span class=\"diff-removed\">legal_person_ind</span><span class=\"diff-added\">non_commercial_ind</span>, <span class=\"diff-removed\">account_type_desc_eng</span><span class=\"diff-added\">segment_key</span>, <span class=\"diff-removed\">business_type</span><span class=\"diff-added\">vip_status</span>",
|
||||||
"postsCount": 0,
|
"postsCount": 0,
|
||||||
"posts": []
|
"posts": []
|
||||||
},
|
},
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
"immutable": "^4.0.0-rc.14",
|
"immutable": "^4.0.0-rc.14",
|
||||||
"jquery": "^3.5.0",
|
"jquery": "^3.5.0",
|
||||||
"markdown-draft-js": "^2.3.0",
|
"markdown-draft-js": "^2.3.0",
|
||||||
"markdown-to-jsx": "^7.1.6",
|
|
||||||
"mobx": "6.0.1",
|
"mobx": "6.0.1",
|
||||||
"mobx-react": "6.1.4",
|
"mobx-react": "6.1.4",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
@ -65,6 +64,7 @@
|
|||||||
"react-flow-renderer": "^9.6.8",
|
"react-flow-renderer": "^9.6.8",
|
||||||
"react-google-login": "^5.2.2",
|
"react-google-login": "^5.2.2",
|
||||||
"react-js-pagination": "^3.0.3",
|
"react-js-pagination": "^3.0.3",
|
||||||
|
"react-markdown": "^8.0.2",
|
||||||
"react-oidc": "^1.0.3",
|
"react-oidc": "^1.0.3",
|
||||||
"react-quill": "^1.3.5",
|
"react-quill": "^1.3.5",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
@ -74,6 +74,8 @@
|
|||||||
"react-tippy": "^1.4.0",
|
"react-tippy": "^1.4.0",
|
||||||
"reactjs-localstorage": "^1.0.1",
|
"reactjs-localstorage": "^1.0.1",
|
||||||
"recharts": "^1.8.5",
|
"recharts": "^1.8.5",
|
||||||
|
"rehype-raw": "^6.1.1",
|
||||||
|
"remark-gfm": "^3.0.1",
|
||||||
"resolve": "1.15.0",
|
"resolve": "1.15.0",
|
||||||
"resolve-url-loader": "3.1.1",
|
"resolve-url-loader": "3.1.1",
|
||||||
"slick-carousel": "^1.8.1",
|
"slick-carousel": "^1.8.1",
|
||||||
|
@ -28,6 +28,10 @@ jest.mock('../../auth-provider/AuthProvider', () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
|
});
|
||||||
|
|
||||||
jest.mock('../../axiosAPIs/glossaryAPI', () => ({
|
jest.mock('../../axiosAPIs/glossaryAPI', () => ({
|
||||||
addGlossaries: jest.fn().mockImplementation(() => Promise.resolve()),
|
addGlossaries: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
}));
|
}));
|
||||||
|
@ -36,6 +36,10 @@ jest.mock('../../axiosAPIs/glossaryAPI', () => ({
|
|||||||
addGlossaries: jest.fn().mockImplementation(() => Promise.resolve()),
|
addGlossaries: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
|
});
|
||||||
|
|
||||||
const mockOnCancel = jest.fn();
|
const mockOnCancel = jest.fn();
|
||||||
const mockOnSave = jest.fn();
|
const mockOnSave = jest.fn();
|
||||||
|
|
||||||
|
@ -46,6 +46,10 @@ jest.mock('../../auth-provider/AuthProvider', () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
|
});
|
||||||
|
|
||||||
const mockUserTeam = [
|
const mockUserTeam = [
|
||||||
{
|
{
|
||||||
description: 'description',
|
description: 'description',
|
||||||
|
@ -30,6 +30,10 @@ window.ResizeObserver = jest.fn().mockImplementation(() => ({
|
|||||||
disconnect: jest.fn(),
|
disconnect: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
|
});
|
||||||
|
|
||||||
const mockLineageData = {
|
const mockLineageData = {
|
||||||
entity: {
|
entity: {
|
||||||
id: 'efcc334a-41c8-483e-b779-464a88a7ece3',
|
id: 'efcc334a-41c8-483e-b779-464a88a7ece3',
|
||||||
|
@ -627,8 +627,7 @@
|
|||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
}
|
}
|
||||||
.ql-snow .ql-editor pre.ql-syntax {
|
.ql-snow .ql-editor pre.ql-syntax {
|
||||||
background-color: #23241f;
|
background-color: #ebeef1;
|
||||||
color: #f8f8f2;
|
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
.ql-snow .ql-editor img {
|
.ql-snow .ql-editor img {
|
||||||
|
@ -51,6 +51,10 @@ jest.mock('../../components/common/non-admin-action/NonAdminAction', () => {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
|
});
|
||||||
|
|
||||||
const mockProps = {
|
const mockProps = {
|
||||||
glossary: mockedGlossaries[0],
|
glossary: mockedGlossaries[0],
|
||||||
isHasAccess: true,
|
isHasAccess: true,
|
||||||
|
@ -54,6 +54,10 @@ jest.mock('../../components/common/non-admin-action/NonAdminAction', () => {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
|
});
|
||||||
|
|
||||||
const mockProps = {
|
const mockProps = {
|
||||||
assetData: mockedAssetData,
|
assetData: mockedAssetData,
|
||||||
isHasAccess: true,
|
isHasAccess: true,
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
findByTestId,
|
||||||
|
fireEvent,
|
||||||
|
queryByTestId,
|
||||||
|
render,
|
||||||
|
} from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import { BlurLayout } from './BlurLayout';
|
||||||
|
|
||||||
|
const markdown =
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
'Updated **columns** : <span class="diff-added">account_category_code, </span>account_type_code, account_type_desc, <span class="diff-removed">account_category_code</span><span class="diff-added">account_type_desc_eng</span>, <span class="diff-removed">eca_ind</span><span class="diff-added">ban_type_desc</span>, <span class="diff-removed">bill_production_ind</span><span class="diff-added">ban_type_key</span>, <span class="diff-removed">collection_waive_ind</span><span class="diff-added">bill_production_ind</span>, <span class="diff-removed">vip_status</span><span class="diff-added">business_type</span>, <span class="diff-removed">ban_type_desc</span><span class="diff-added">check_in_crm</span>, <span class="diff-removed">non_commercial_ind</span><span class="diff-added">collection_waive_ind</span>, <span class="diff-removed">legacy_account_category, </span>corporate_category, <span class="diff-removed">ban_type_key</span><span class="diff-added">currency_key</span>, <span class="diff-removed">segment_key</span><span class="diff-added">eca_ind</span>, <span class="diff-removed">check_in_crm</span><span class="diff-added">legacy_account_category</span>, <span class="diff-removed">currency_key</span><span class="diff-added">legal_person_ind</span>, <span class="diff-removed">legal_person_ind</span><span class="diff-added">non_commercial_ind</span>, <span class="diff-removed">account_type_desc_eng</span><span class="diff-added">segment_key</span>, <span class="diff-removed">business_type</span><span class="diff-added">vip_status</span>';
|
||||||
|
|
||||||
|
const displayMoreHandler = jest.fn();
|
||||||
|
|
||||||
|
const mockProp = {
|
||||||
|
enableSeeMoreVariant: true,
|
||||||
|
markdown,
|
||||||
|
displayMoreText: true,
|
||||||
|
blurClasses: '',
|
||||||
|
displayMoreHandler,
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('./RichTextEditorPreviewer', () => ({
|
||||||
|
MAX_LENGTH: 300,
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('Test BlurLayout Component', () => {
|
||||||
|
it('Should render the Layout Component', async () => {
|
||||||
|
const { container } = render(<BlurLayout {...mockProp} />, {
|
||||||
|
wrapper: MemoryRouter,
|
||||||
|
});
|
||||||
|
|
||||||
|
const blurLayout = await findByTestId(container, 'blur-layout');
|
||||||
|
|
||||||
|
const displayButton = await findByTestId(container, 'display-button');
|
||||||
|
|
||||||
|
expect(blurLayout).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(displayButton).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not render the Layout Component if markdown length is less that MAX_LENGTH', async () => {
|
||||||
|
const { container } = render(<BlurLayout {...mockProp} markdown="" />, {
|
||||||
|
wrapper: MemoryRouter,
|
||||||
|
});
|
||||||
|
|
||||||
|
const blurLayout = queryByTestId(container, 'blur-layout');
|
||||||
|
|
||||||
|
const displayButton = queryByTestId(container, 'display-button');
|
||||||
|
|
||||||
|
expect(blurLayout).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(displayButton).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not render the Layout Component if enableSeeMoreVariant is false', async () => {
|
||||||
|
const { container } = render(
|
||||||
|
<BlurLayout {...mockProp} enableSeeMoreVariant={false} />,
|
||||||
|
{
|
||||||
|
wrapper: MemoryRouter,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const blurLayout = queryByTestId(container, 'blur-layout');
|
||||||
|
|
||||||
|
const displayButton = queryByTestId(container, 'display-button');
|
||||||
|
|
||||||
|
expect(blurLayout).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(displayButton).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should call displayMoreHandler on display button click', async () => {
|
||||||
|
const { container } = render(<BlurLayout {...mockProp} />, {
|
||||||
|
wrapper: MemoryRouter,
|
||||||
|
});
|
||||||
|
|
||||||
|
const blurLayout = await findByTestId(container, 'blur-layout');
|
||||||
|
|
||||||
|
const displayButton = await findByTestId(container, 'display-button');
|
||||||
|
|
||||||
|
expect(blurLayout).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(displayButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(displayButton);
|
||||||
|
|
||||||
|
expect(displayMoreHandler).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||||
|
import { MAX_LENGTH } from './RichTextEditorPreviewer';
|
||||||
|
|
||||||
|
interface BlurLayoutProp {
|
||||||
|
markdown: string;
|
||||||
|
enableSeeMoreVariant: boolean;
|
||||||
|
displayMoreText: boolean;
|
||||||
|
blurClasses: string;
|
||||||
|
displayMoreHandler: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BlurLayout: FC<BlurLayoutProp> = ({
|
||||||
|
enableSeeMoreVariant,
|
||||||
|
markdown,
|
||||||
|
displayMoreText,
|
||||||
|
blurClasses,
|
||||||
|
displayMoreHandler,
|
||||||
|
}: BlurLayoutProp) => {
|
||||||
|
const getBlurClass = () => {
|
||||||
|
return !displayMoreText ? blurClasses : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
return enableSeeMoreVariant && markdown.length > MAX_LENGTH ? (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'tw-absolute tw-flex tw-h-full tw-w-full tw-inset-x-0 tw-pointer-events-none',
|
||||||
|
getBlurClass(),
|
||||||
|
{
|
||||||
|
'tw-top-0 tw-bottom-0': !displayMoreText,
|
||||||
|
' tw--bottom-4': displayMoreText,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
data-testid="blur-layout">
|
||||||
|
<p
|
||||||
|
className="tw-cursor-pointer tw-self-end tw-pointer-events-auto tw-text-primary tw-mx-auto"
|
||||||
|
data-testid="display-button"
|
||||||
|
onClick={displayMoreHandler}>
|
||||||
|
<span className="tw-flex tw-items-center tw-gap-2">
|
||||||
|
<SVGIcons
|
||||||
|
alt="expand-collapse"
|
||||||
|
className={classNames({ 'rotate-inverse': displayMoreText })}
|
||||||
|
icon={Icons.CHEVRON_DOWN}
|
||||||
|
width="32"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
|
};
|
@ -11,7 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Attributes, HtmlHTMLAttributes, ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
export type editorRef = ReactNode | HTMLElement | string;
|
export type editorRef = ReactNode | HTMLElement | string;
|
||||||
export enum Format {
|
export enum Format {
|
||||||
@ -27,8 +27,11 @@ export type EditorProp = {
|
|||||||
customOptions?: ReactNode[];
|
customOptions?: ReactNode[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
export interface PreviewerProp {
|
||||||
export interface ElementProp extends HtmlHTMLAttributes<any>, Attributes {
|
markdown: string;
|
||||||
class: string;
|
className?: string;
|
||||||
className: string;
|
blurClasses?: string;
|
||||||
|
maxHtClass?: string;
|
||||||
|
maxLen?: number;
|
||||||
|
enableSeeMoreVariant?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { findByTestId, render } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import RichTextEditorPreviewer from './RichTextEditorPreviewer';
|
||||||
|
|
||||||
|
const mockProp = {
|
||||||
|
markdown: '',
|
||||||
|
className: '',
|
||||||
|
blurClasses: 'see-more-blur',
|
||||||
|
maxHtClass: 'tw-h-24',
|
||||||
|
maxLen: 300,
|
||||||
|
enableSeeMoreVariant: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('react-markdown', () => {
|
||||||
|
return jest.fn().mockImplementation(() => {
|
||||||
|
return <p data-testid="markdown-parser">markdown parser</p>;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.mock('rehype-raw', () => {
|
||||||
|
return jest.fn();
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.mock('remark-gfm', () => {
|
||||||
|
return jest.fn();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test RichTextEditor Previewer Component', () => {
|
||||||
|
it('Should render RichTextEditorViewer Component', async () => {
|
||||||
|
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
|
||||||
|
wrapper: MemoryRouter,
|
||||||
|
});
|
||||||
|
|
||||||
|
const viewerContainer = await findByTestId(container, 'viewer-container');
|
||||||
|
|
||||||
|
expect(viewerContainer).toBeInTheDocument();
|
||||||
|
|
||||||
|
const markdownParser = await findByTestId(container, 'markdown-parser');
|
||||||
|
|
||||||
|
expect(markdownParser).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
@ -12,13 +12,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Markdown from 'markdown-to-jsx';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Paragraph, UnOrderedList } from '../../../utils/MarkdownUtils';
|
// Markdown Parser and plugin imports
|
||||||
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
import MarkdownParser from 'react-markdown';
|
||||||
import { ElementProp } from './RichTextEditor.interface';
|
import rehypeRaw from 'rehype-raw';
|
||||||
|
import remarkGfm from 'remark-gfm';
|
||||||
|
import { BlurLayout } from './BlurLayout';
|
||||||
|
import { PreviewerProp } from './RichTextEditor.interface';
|
||||||
|
|
||||||
const MAX_LENGTH = 300;
|
export const MAX_LENGTH = 300;
|
||||||
|
|
||||||
const RichTextEditorPreviewer = ({
|
const RichTextEditorPreviewer = ({
|
||||||
markdown = '',
|
markdown = '',
|
||||||
@ -27,21 +29,23 @@ const RichTextEditorPreviewer = ({
|
|||||||
maxHtClass = 'tw-h-24',
|
maxHtClass = 'tw-h-24',
|
||||||
maxLen = MAX_LENGTH,
|
maxLen = MAX_LENGTH,
|
||||||
enableSeeMoreVariant = true,
|
enableSeeMoreVariant = true,
|
||||||
}: {
|
}: PreviewerProp) => {
|
||||||
markdown: string;
|
|
||||||
className?: string;
|
|
||||||
blurClasses?: string;
|
|
||||||
maxHtClass?: string;
|
|
||||||
maxLen?: number;
|
|
||||||
enableSeeMoreVariant?: boolean;
|
|
||||||
}) => {
|
|
||||||
const [content, setContent] = useState<string>('');
|
const [content, setContent] = useState<string>('');
|
||||||
const [displayMoreText, setDisplayMoreText] = useState(false);
|
const [displayMoreText, setDisplayMoreText] = useState(false);
|
||||||
useEffect(() => {
|
|
||||||
const modifiedContent = markdown
|
const setModifiedContent = (markdownValue: string) => {
|
||||||
.replaceAll('<', '<')
|
const modifiedContent = markdownValue
|
||||||
.replaceAll('>', '>');
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
setContent(modifiedContent);
|
setContent(modifiedContent);
|
||||||
|
};
|
||||||
|
|
||||||
|
const displayMoreHandler = () => {
|
||||||
|
setDisplayMoreText((pre) => !pre);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setModifiedContent(markdown);
|
||||||
}, [markdown]);
|
}, [markdown]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -55,90 +59,55 @@ const RichTextEditorPreviewer = ({
|
|||||||
{
|
{
|
||||||
'tw-mb-5': displayMoreText,
|
'tw-mb-5': displayMoreText,
|
||||||
}
|
}
|
||||||
)}>
|
|
||||||
<Markdown
|
|
||||||
options={{
|
|
||||||
overrides: {
|
|
||||||
h1: {
|
|
||||||
component: Paragraph,
|
|
||||||
},
|
|
||||||
h2: {
|
|
||||||
component: Paragraph,
|
|
||||||
},
|
|
||||||
h3: {
|
|
||||||
component: Paragraph,
|
|
||||||
},
|
|
||||||
h4: {
|
|
||||||
component: Paragraph,
|
|
||||||
},
|
|
||||||
h5: {
|
|
||||||
component: Paragraph,
|
|
||||||
},
|
|
||||||
h6: {
|
|
||||||
component: Paragraph,
|
|
||||||
},
|
|
||||||
ul: {
|
|
||||||
component: UnOrderedList,
|
|
||||||
props: {
|
|
||||||
className: 'tw-ml-3',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Custom React CreateElement Implementation
|
|
||||||
* @param type - Element type
|
|
||||||
* @param props - Element Props
|
|
||||||
* @param children - Elemeny children
|
|
||||||
* @returns React element of {type} with {props} and {children}
|
|
||||||
*/
|
|
||||||
createElement(type, props, children) {
|
|
||||||
const {
|
|
||||||
className,
|
|
||||||
/** disabling eslint rule because class is reserverd keyword
|
|
||||||
* and here we have to give alias that is classes */
|
|
||||||
// eslint-disable-next-line react/prop-types
|
|
||||||
class: classes,
|
|
||||||
...restProps
|
|
||||||
} = props as ElementProp;
|
|
||||||
const modifiedProps = {
|
|
||||||
...restProps,
|
|
||||||
/** react does not accept class attribute,
|
|
||||||
* hence we need to escape class and pass className attribute
|
|
||||||
*/
|
|
||||||
className: `${className ? className : ''} ${
|
|
||||||
classes ? classes : ''
|
|
||||||
}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
return React.createElement(type, modifiedProps, children);
|
|
||||||
},
|
|
||||||
}}>
|
|
||||||
{content}
|
|
||||||
</Markdown>
|
|
||||||
{enableSeeMoreVariant && markdown.length > MAX_LENGTH && (
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'tw-absolute tw-flex tw-h-full tw-w-full tw-inset-x-0 tw-pointer-events-none',
|
|
||||||
!displayMoreText ? blurClasses : null,
|
|
||||||
{
|
|
||||||
'tw-top-0 tw-bottom-0': !displayMoreText,
|
|
||||||
' tw--bottom-4': displayMoreText,
|
|
||||||
}
|
|
||||||
)}>
|
|
||||||
<p
|
|
||||||
className="tw-cursor-pointer tw-self-end tw-pointer-events-auto tw-text-primary tw-mx-auto"
|
|
||||||
onClick={() => setDisplayMoreText((pre) => !pre)}>
|
|
||||||
<span className="tw-flex tw-items-center tw-gap-2">
|
|
||||||
<SVGIcons
|
|
||||||
alt="expand-collapse"
|
|
||||||
className={classNames({ 'rotate-inverse': displayMoreText })}
|
|
||||||
icon={Icons.CHEVRON_DOWN}
|
|
||||||
width="32"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
data-testid="viewer-container">
|
||||||
|
<MarkdownParser
|
||||||
|
sourcePos
|
||||||
|
components={{
|
||||||
|
h1: 'p',
|
||||||
|
h2: 'p',
|
||||||
|
ul: ({ children, ...props }) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { ordered, ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul className="tw-ml-3" {...rest}>
|
||||||
|
{children}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ol: ({ children, ...props }) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { ordered, ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ol className="tw-ml-3" {...rest} style={{ listStyle: 'auto' }}>
|
||||||
|
{children}
|
||||||
|
</ol>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
code: ({ children, ...props }) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { inline, ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<code {...rest} className="tw-my">
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
rehypePlugins={[rehypeRaw]}
|
||||||
|
remarkPlugins={[remarkGfm]}>
|
||||||
|
{content}
|
||||||
|
</MarkdownParser>
|
||||||
|
<BlurLayout
|
||||||
|
blurClasses={blurClasses}
|
||||||
|
displayMoreHandler={displayMoreHandler}
|
||||||
|
displayMoreText={displayMoreText}
|
||||||
|
enableSeeMoreVariant={enableSeeMoreVariant}
|
||||||
|
markdown={content}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -31,6 +31,10 @@ const tagsWithTerm = [
|
|||||||
{ tagFQN: `tags:term`, source: 'Glossary' },
|
{ tagFQN: `tags:term`, source: 'Glossary' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
|
});
|
||||||
|
|
||||||
describe('Test TagsViewer Component', () => {
|
describe('Test TagsViewer Component', () => {
|
||||||
it('Component should render', () => {
|
it('Component should render', () => {
|
||||||
const { container } = render(<TagsViewer sizeCap={-1} tags={tags} />);
|
const { container } = render(<TagsViewer sizeCap={-1} tags={tags} />);
|
||||||
|
@ -898,7 +898,8 @@ body .profiler-graph .recharts-active-dot circle {
|
|||||||
.entity-feed-list {
|
.entity-feed-list {
|
||||||
grid-template-columns: 200px auto 200px;
|
grid-template-columns: 200px auto 200px;
|
||||||
}
|
}
|
||||||
.activity-feed-card-text code {
|
|
||||||
|
code {
|
||||||
padding: 2px 3px;
|
padding: 2px 3px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: #ebeef1;
|
background: #ebeef1;
|
||||||
|
@ -14,10 +14,13 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { diffArrays, diffWordsWithSpace } from 'diff';
|
import { diffArrays, diffWordsWithSpace } from 'diff';
|
||||||
import { isEmpty, isUndefined, uniqueId } from 'lodash';
|
import { isEmpty, isUndefined, uniqueId } from 'lodash';
|
||||||
import Markdown from 'markdown-to-jsx';
|
|
||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import ReactDOMServer from 'react-dom/server';
|
import ReactDOMServer from 'react-dom/server';
|
||||||
|
// Markdown Parser and plugin imports
|
||||||
|
import MarkdownParser from 'react-markdown';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import rehypeRaw from 'rehype-raw';
|
||||||
|
import remarkGfm from 'remark-gfm';
|
||||||
import { FQN_SEPARATOR_CHAR } from '../constants/char.constants';
|
import { FQN_SEPARATOR_CHAR } from '../constants/char.constants';
|
||||||
import { DESCRIPTIONLENGTH, getTeamDetailsPath } from '../constants/constants';
|
import { DESCRIPTIONLENGTH, getTeamDetailsPath } from '../constants/constants';
|
||||||
import { ChangeType } from '../enums/entity.enum';
|
import { ChangeType } from '../enums/entity.enum';
|
||||||
@ -27,7 +30,6 @@ import {
|
|||||||
FieldChange,
|
FieldChange,
|
||||||
} from '../generated/entity/services/databaseService';
|
} from '../generated/entity/services/databaseService';
|
||||||
import { TagLabel } from '../generated/type/tagLabel';
|
import { TagLabel } from '../generated/type/tagLabel';
|
||||||
import { Paragraph, Span, UnOrderedList } from './MarkdownUtils';
|
|
||||||
import { isValidJSONString } from './StringsUtils';
|
import { isValidJSONString } from './StringsUtils';
|
||||||
import { getEntityLink, getOwnerFromId } from './TableUtils';
|
import { getEntityLink, getOwnerFromId } from './TableUtils';
|
||||||
|
|
||||||
@ -38,49 +40,62 @@ const parseMarkdown = (
|
|||||||
_isNewLine: boolean
|
_isNewLine: boolean
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
<Markdown
|
<Fragment>
|
||||||
options={{
|
<MarkdownParser
|
||||||
overrides: {
|
sourcePos
|
||||||
h1: {
|
components={{
|
||||||
component: Paragraph,
|
h1: 'p',
|
||||||
|
h2: 'p',
|
||||||
|
ul: ({ children, ...props }) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { ordered, ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul className={classNames('tw-ml-3', className)} {...rest}>
|
||||||
|
{children}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
h2: {
|
ol: ({ children, ...props }) => {
|
||||||
component: Paragraph,
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { ordered, ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ol className="tw-ml-3" {...rest} style={{ listStyle: 'auto' }}>
|
||||||
|
{children}
|
||||||
|
</ol>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
h3: {
|
code: ({ children, ...props }) => {
|
||||||
component: Paragraph,
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { inline, ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<code {...rest} className="tw-my">
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
h4: {
|
p: ({ children, ...props }) => {
|
||||||
component: Paragraph,
|
return (
|
||||||
|
<p className={className} {...props}>
|
||||||
|
{children}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
h5: {
|
span: ({ children, ...props }) => {
|
||||||
component: Paragraph,
|
return (
|
||||||
|
<span className={className} {...props}>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
h6: {
|
}}
|
||||||
component: Paragraph,
|
rehypePlugins={[rehypeRaw]}
|
||||||
},
|
remarkPlugins={[remarkGfm]}>
|
||||||
ul: {
|
{content}
|
||||||
component: UnOrderedList,
|
</MarkdownParser>
|
||||||
props: {
|
</Fragment>
|
||||||
className: `${className} tw-ml-3`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
p: {
|
|
||||||
component: Paragraph,
|
|
||||||
props: {
|
|
||||||
className: `${className}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
span: {
|
|
||||||
component: Span,
|
|
||||||
props: {
|
|
||||||
className: `${className}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}>
|
|
||||||
{content}
|
|
||||||
</Markdown>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,6 +51,15 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// .mjs files to be handled
|
||||||
|
{
|
||||||
|
test: /\.m?js/,
|
||||||
|
include: path.resolve(__dirname, 'node_modules/kleur'),
|
||||||
|
resolve: {
|
||||||
|
fullySpecified: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// .ts and .tsx files to be handled by ts-loader
|
// .ts and .tsx files to be handled by ts-loader
|
||||||
{
|
{
|
||||||
test: /\.(ts|tsx)$/,
|
test: /\.(ts|tsx)$/,
|
||||||
|
@ -52,6 +52,15 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// .mjs files to be handled
|
||||||
|
{
|
||||||
|
test: /\.m?js/,
|
||||||
|
include: path.resolve(__dirname, 'node_modules/kleur'),
|
||||||
|
resolve: {
|
||||||
|
fullySpecified: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// .ts and .tsx files to be handled by ts-loader
|
// .ts and .tsx files to be handled by ts-loader
|
||||||
{
|
{
|
||||||
test: /\.(ts|tsx)$/,
|
test: /\.(ts|tsx)$/,
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user