Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for markdown in toggle descriptions #6453

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"name": "unleash-frontend-local",
"version": "0.0.0",
"private": true,
"files": ["index.js", "build"],
"files": [
"index.js",
"build"
],
"engines": {
"node": ">=18"
},
Expand Down Expand Up @@ -142,11 +145,18 @@
}
},
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"dependencies": {
"remove-markdown": "^0.5.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the way vite bundles dependencies, and for consistency sake, I think this belongs in devDependencies instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this was a lazy mistake by me.

}
}
4 changes: 4 additions & 0 deletions frontend/src/component/common/Markdown/Markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ const LinkRenderer = ({
export const Markdown = (props: ComponentProps<typeof ReactMarkdown>) => (
<ReactMarkdown components={{ a: LinkRenderer }} {...props} />
);

export const SimpleMarkdown = (props: ComponentProps<typeof ReactMarkdown>) => (
<ReactMarkdown components={{ a: LinkRenderer }} skipHtml allowedElements={['a', 'p', 'strong', 'em']} {...props} />
);
nunogois marked this conversation as resolved.
Show resolved Hide resolved
20 changes: 13 additions & 7 deletions frontend/src/component/common/Table/cells/LinkCell/LinkCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {
StyledDescription,
} from './LinkCell.styles';

//@ts-ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious - Why is this needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because remove-markdown does not have typescript definitions. I should add one instead of ignoring, just did not want to do it for the PoC.

import removeMd from 'remove-markdown';
import { SimpleMarkdown } from 'component/common/Markdown/Markdown';

interface ILinkCellProps {
title?: string;
to?: string;
Expand All @@ -26,23 +30,25 @@ export const LinkCell: React.FC<ILinkCellProps> = ({
subtitle,
children,
}) => {
const subTitleClean = removeMd(subtitle);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this casing is more consistent, since it matches the original name.

Alternatively, if it's more readable, we could use something like plainSubtitle or plainTextSubtitle.

Suggested change
const subTitleClean = removeMd(subtitle);
const subtitleClean = removeMd(subtitle);


const { searchQuery } = useSearchHighlightContext();

const renderSubtitle = (
<ConditionallyRender
condition={Boolean(subtitle && subtitle.length > 40)}
condition={Boolean(subTitleClean && subTitleClean.length > 40)}
show={
<HtmlTooltip title={subtitle} placement='bottom-start' arrow>
<HtmlTooltip title={<SimpleMarkdown>{subtitle || ''}</SimpleMarkdown>} placement='bottom-start' arrow>
<StyledDescription data-loading>
<Highlighter search={searchQuery}>
{subtitle}
{subTitleClean}
</Highlighter>
</StyledDescription>
</HtmlTooltip>
}
elseShow={
<StyledDescription data-loading>
<Highlighter search={searchQuery}>{subtitle}</Highlighter>
<Highlighter search={searchQuery}>{subTitleClean}</Highlighter>
</StyledDescription>
}
/>
Expand All @@ -53,15 +59,15 @@ export const LinkCell: React.FC<ILinkCellProps> = ({
<StyledTitle
data-loading
style={{
WebkitLineClamp: subtitle ? 1 : 2,
lineClamp: subtitle ? 1 : 2,
WebkitLineClamp: subTitleClean ? 1 : 2,
lineClamp: subTitleClean ? 1 : 2,
}}
>
<Highlighter search={searchQuery}>{title}</Highlighter>
{children}
</StyledTitle>
<ConditionallyRender
condition={Boolean(subtitle)}
condition={Boolean(subTitleClean)}
show={renderSubtitle}
/>
</StyledContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { Edit } from '@mui/icons-material';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { Markdown, SimpleMarkdown } from 'component/common/Markdown/Markdown';
import { useUiFlag } from 'hooks/useUiFlag';

const StyledContainer = styled('div')(({ theme }) => ({
borderRadius: theme.shape.borderRadiusLarge,
Expand Down Expand Up @@ -63,6 +65,7 @@ const StyledDescription = styled('p')({
const FeatureOverviewMetaData = () => {
const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId');
const descriptionAsMarkdown = useUiFlag('descriptionAsMarkdown');
const { feature } = useFeature(projectId, featureId);
const { project, description, type } = feature;

Expand Down Expand Up @@ -93,7 +96,9 @@ const FeatureOverviewMetaData = () => {
<div>Description:</div>
<StyledDescriptionContainer>
<StyledDescription>
{description}
<ConditionallyRender condition={descriptionAsMarkdown}
show={<SimpleMarkdown>{description || ''}</SimpleMarkdown>}
elseShow={description || ''} />
</StyledDescription>
<PermissionIconButton
projectId={projectId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { useNavigate } from 'react-router-dom';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import { useUiFlag } from 'hooks/useUiFlag';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { SimpleMarkdown } from 'component/common/Markdown/Markdown';

interface IFeatureSettingsInformationProps {
projectId: string;
Expand All @@ -25,11 +28,14 @@ export const FeatureSettingsInformation = ({
}: IFeatureSettingsInformationProps) => {
const { feature } = useFeature(projectId, featureId);
const navigate = useNavigate();
const descriptionAsMarkdown = useUiFlag('descriptionAsMarkdown');

const onEdit = () => {
navigate(`/projects/${projectId}/features/${featureId}/edit`);
};

const description = feature.description || 'no description';

return (
<>
<StyledContainer>
Expand All @@ -49,11 +55,10 @@ export const FeatureSettingsInformation = ({
</Typography>
<Typography>
Description:{' '}
<strong>
{!feature.description?.length
? 'no description'
: feature.description}
</strong>
<ConditionallyRender
condition={descriptionAsMarkdown}
show={<SimpleMarkdown>{description}</SimpleMarkdown>}
elseShow={description} />
</Typography>
<Typography>
Type: <strong>{feature.type}</strong>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/interfaces/uiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export type UiFlags = {
featureSearchFeedbackPosting?: boolean;
userAccessUIEnabled?: boolean;
sdkReporting?: boolean;
descriptionAsMarkdown?: boolean;
};

export interface IVersionInfo {
Expand Down
5 changes: 5 additions & 0 deletions frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6204,6 +6204,11 @@ remark-rehype@^10.0.0:
mdast-util-to-hast "^12.1.0"
unified "^10.0.0"

remove-markdown@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/remove-markdown/-/remove-markdown-0.5.0.tgz#a596264bbd60b9ceab2e2ae86e5789eee91aee32"
integrity sha512-x917M80K97K5IN1L8lUvFehsfhR8cYjGQ/yAMRI9E7JIKivtl5Emo5iD13DhMr+VojzMCiYk8V2byNPwT/oapg==

request-progress@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe"
Expand Down
5 changes: 5 additions & 0 deletions src/lib/types/experimental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getDefaultVariant } from 'unleash-client/lib/variant';
export type IFlagKey =
| 'accessLogs'
| 'anonymiseEventLog'
| 'descriptionAsMarkdown'
| 'encryptEmails'
| 'enableLicense'
| 'enableLicenseChecker'
Expand Down Expand Up @@ -59,6 +60,10 @@ export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;

const flags: IFlags = {
anonymiseEventLog: false,
descriptionAsMarkdown: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_DESCRIPTION_AS_MARKDOWN,
false,
),
enableLicense: false,
enableLicenseChecker: false,
embedProxy: parseEnvVarBoolean(
Expand Down
1 change: 1 addition & 0 deletions src/server-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ process.nextTick(async () => {
executiveDashboard: true,
userAccessUIEnabled: true,
sdkReporting: true,
descriptionAsMarkdown: true,
},
},
authentication: {
Expand Down
Loading