这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
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
2 changes: 2 additions & 0 deletions ui/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
"@solid-primitives/resize-observer": "^2.1.0",
"lodash": "^4.17.21",
"moment": "^2.30.1",
"sanitize-html": "^2.17.0",
"solid-js": "^1.9.5",
"solid-styled-components": "^0.28.5"
},
"devDependencies": {
"@types/lodash": "^4.17.16",
"@types/sanitize-html": "^2.16.0",
"esbuild": "^0.25.1",
"esbuild-plugin-solid-js": "^1.0.1",
"eslint": "^9.22.0",
Expand Down
9 changes: 6 additions & 3 deletions ui/common/src/components/CollapsableText.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { createEffect, createSignal, on, Show } from 'solid-js';
import { css } from 'solid-styled-components';

import { formatSummaryField } from '../utils/formatSummaryField';

interface Props {
text: string;
maxLinesNumber?: number;
Expand Down Expand Up @@ -61,6 +63,7 @@ export const CollapsableText = (props: Props) => {

return (
<div class="position-relative">
{/* eslint-disable solid/no-innerhtml */}
<div
ref={setTextRef}
class={`${Content} ${props.class}`}
Expand All @@ -74,9 +77,9 @@ export const CollapsableText = (props: Props) => {
}
: {}
}
>
{props.text}
</div>
innerHTML={formatSummaryField(props.text)}
/>
{/* eslint-enable solid/no-innerhtml */}
<Show when={enabledCollapsable() && !collapsable()}>
<div class={`position-absolute end-0 ${BtnWrapper}`}>
<button
Expand Down
8 changes: 7 additions & 1 deletion ui/common/src/components/ItemModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { css } from 'solid-styled-components';
import { AdditionalCategory, Item, Repository, SecurityAudit, SVGIconKind } from '../types/types';
import { cutString, getItemDescription } from '../utils';
import { formatProfitLabel } from '../utils/formatProfitLabel';
import { formatSummaryField } from '../utils/formatSummaryField';
import { formatTAGName } from '../utils/formatTAGName';
import { getMainTag } from '../utils/getMainTag';
import { prettifyNumber } from '../utils/prettifyNumber';
Expand Down Expand Up @@ -744,7 +745,12 @@ export const ItemModalContent = (props: Props) => {
<Show when={!isUndefined(itemInfo()!.summary!.intro_url) && !isEmpty(itemInfo()!.summary!.intro_url)}>
<div class="summaryBlock">
<div class={`fw-bold text-uppercase ${TitleInSection}`}>Introduction</div>
<div class={`mt-2 ${SummaryContent}`}>{itemInfo()!.summary!.intro_url!}</div>
{/* eslint-disable solid/no-innerhtml */}
<div
class={`mt-2 ${SummaryContent}`}
innerHTML={formatSummaryField(itemInfo()!.summary!.intro_url!)}
/>
{/* eslint-enable solid/no-innerhtml */}
</div>
</Show>

Expand Down
34 changes: 27 additions & 7 deletions ui/common/src/components/ItemModalMobileContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { css } from 'solid-styled-components';
import { AdditionalCategory, Item, SecurityAudit, SVGIconKind } from '../types/types';
import { cutString, getItemDescription } from '../utils';
import { formatProfitLabel } from '../utils/formatProfitLabel';
import { formatSummaryField } from '../utils/formatSummaryField';
import { prettifyNumber } from '../utils/prettifyNumber';
import { AcquisitionsTable } from './AcquisitionsTable';
import { Badge } from './Badge';
Expand Down Expand Up @@ -498,14 +499,20 @@ export const ItemModalMobileContent = (props: Props) => {
<Show when={!isUndefined(itemInfo()!.summary!.intro_url) && !isEmpty(itemInfo()!.summary!.intro_url)}>
<div class="summaryBlock">
<div class={`fw-bold text-uppercase ${TitleInSection}`}>Introduction</div>
<div class={`mt-2 text-truncate ${SummaryContent}`}>{itemInfo()!.summary!.intro_url!}</div>
{/* eslint-disable solid/no-innerhtml */}
<div
class={`mt-2 text-truncate ${SummaryContent}`}
innerHTML={formatSummaryField(itemInfo()!.summary!.intro_url!)}
/>
{/* eslint-enable solid/no-innerhtml */}
</div>
</Show>

<Show when={!isUndefined(itemInfo()!.summary!.use_case) && !isEmpty(itemInfo()!.summary!.use_case)}>
<div class="summaryBlock">
<div class={`fw-bold text-uppercase ${TitleInSection}`}>Use case</div>
<div class={`mt-2 ${SummaryContent}`}>{itemInfo()!.summary!.use_case!}</div>
{/* eslint-disable-next-line solid/no-innerhtml */}
<div class={`mt-2 ${SummaryContent}`} innerHTML={formatSummaryField(itemInfo()!.summary!.use_case!)} />
</div>
</Show>

Expand All @@ -516,7 +523,12 @@ export const ItemModalMobileContent = (props: Props) => {
>
<div class="summaryBlock">
<div class={`fw-bold text-uppercase ${TitleInSection}`}>Business use case</div>
<div class={`mt-2 ${SummaryContent}`}>{itemInfo()!.summary!.business_use_case!}</div>
{/* eslint-disable solid/no-innerhtml */}
<div
class={`mt-2 ${SummaryContent}`}
innerHTML={formatSummaryField(itemInfo()!.summary!.business_use_case!)}
/>
{/* eslint-enable solid/no-innerhtml */}
</div>
</Show>

Expand All @@ -528,16 +540,24 @@ export const ItemModalMobileContent = (props: Props) => {
>
<div class="summaryBlock">
<div class={`fw-bold text-uppercase ${TitleInSection}`}>Integrations</div>
<div class={`mt-2 ${SummaryContent}`}>
{(itemInfo()!.summary!.integrations || itemInfo()!.summary!.integration)!}
</div>
{/* eslint-disable solid/no-innerhtml */}
<div
class={`mt-2 ${SummaryContent}`}
innerHTML={formatSummaryField(itemInfo()!.summary!.integrations || itemInfo()!.summary!.integration!)}
/>
{/* eslint-enable solid/no-innerhtml */}
</div>
</Show>

<Show when={!isUndefined(itemInfo()!.summary!.release_rate) && !isEmpty(itemInfo()!.summary!.release_rate)}>
<div class="summaryBlock">
<div class={`fw-bold text-uppercase ${TitleInSection}`}>Release rate</div>
<div class={`mt-2 ${SummaryContent}`}>{itemInfo()!.summary!.release_rate!}</div>
{/* eslint-disable solid/no-innerhtml */}
<div
class={`mt-2 ${SummaryContent}`}
innerHTML={formatSummaryField(itemInfo()!.summary!.release_rate!)}
/>
{/* eslint-enable solid/no-innerhtml */}
</div>
</Show>

Expand Down
25 changes: 25 additions & 0 deletions ui/common/src/utils/formatSummaryField.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import sanitizeHtml from 'sanitize-html';

// eslint-disable-next-line
const urlRegex = /(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g;
const LINE_BREAKS = /(?:\r\n|\r|\n)/g;

const replaceLineBreaks = (text: string): string => {
if (text.match(LINE_BREAKS)) {
return text.replace(LINE_BREAKS, '<br>');
}
return text;
};

const linkify = (text: string): string => {
if (text.match(urlRegex)) {
return text.replace(urlRegex, function (url) {
return `<a href="${url}" class="text-decoration-underline" target=_blank rel="noopener noreferrer">${url}</a>`;
});
}
return text;
};

export const formatSummaryField = (text: string): string => {
return replaceLineBreaks(linkify(sanitizeHtml(text, { allowedTags: [], allowedAttributes: {} })));
};
78 changes: 76 additions & 2 deletions ui/common/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,13 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.16.tgz#94ae78fab4a38d73086e962d0b65c30d816bfb0a"
integrity sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==

"@types/sanitize-html@^2.16.0":
version "2.16.0"
resolved "https://registry.yarnpkg.com/@types/sanitize-html/-/sanitize-html-2.16.0.tgz#860d72c1ba8a5d044946f37559cc359c0a13b24e"
integrity sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==
dependencies:
htmlparser2 "^8.0.0"

"@typescript-eslint/eslint-plugin@8.26.1":
version "8.26.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.1.tgz#3e48eb847924161843b092c87a9b65176b53782f"
Expand Down Expand Up @@ -1124,6 +1131,41 @@ deep-is@^0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==

deepmerge@^4.2.2:
version "4.3.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==

dom-serializer@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.2"
entities "^4.2.0"

domelementtype@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==

domhandler@^5.0.2, domhandler@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
dependencies:
domelementtype "^2.3.0"

domutils@^3.0.1:
version "3.2.2"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.2.tgz#edbfe2b668b0c1d97c24baf0f1062b132221bc78"
integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==
dependencies:
dom-serializer "^2.0.0"
domelementtype "^2.3.0"
domhandler "^5.0.3"

eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
Expand All @@ -1144,7 +1186,7 @@ emoji-regex@^9.2.2:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==

entities@^4.5.0:
entities@^4.2.0, entities@^4.4.0, entities@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
Expand Down Expand Up @@ -1511,6 +1553,16 @@ html-tags@^3.0.0:
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce"
integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==

htmlparser2@^8.0.0:
version "8.0.2"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.3"
domutils "^3.0.1"
entities "^4.4.0"

ignore@^5.2.0, ignore@^5.3.1:
version "5.3.2"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
Expand Down Expand Up @@ -1563,6 +1615,11 @@ is-number@^7.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==

is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==

is-what@^4.1.8:
version "4.1.16"
resolved "https://registry.yarnpkg.com/is-what/-/is-what-4.1.16.tgz#1ad860a19da8b4895ad5495da3182ce2acdd7a6f"
Expand Down Expand Up @@ -1814,6 +1871,11 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"

parse-srcset@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==

parse5@^7.1.2:
version "7.2.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a"
Expand Down Expand Up @@ -1866,7 +1928,7 @@ postcss-load-config@^6.0.1:
dependencies:
lilconfig "^3.1.1"

postcss@^8.4.43:
postcss@^8.3.11, postcss@^8.4.43:
version "8.5.3"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb"
integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==
Expand Down Expand Up @@ -1957,6 +2019,18 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"

sanitize-html@^2.17.0:
version "2.17.0"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.17.0.tgz#a8f66420a6be981d8fe412e3397cc753782598e4"
integrity sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==
dependencies:
deepmerge "^4.2.2"
escape-string-regexp "^4.0.0"
htmlparser2 "^8.0.0"
is-plain-object "^5.0.0"
parse-srcset "^1.0.2"
postcss "^8.3.11"

semver@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
Expand Down