Some minor improvements in UI (#1413)

Signed-off-by: Cintia Sanchez Garcia <cynthiasg@icloud.com>
This commit is contained in:
Cynthia S. Garcia 2021-06-21 11:40:51 +02:00 committed by GitHub
parent 0fa8e1738f
commit 713d357244
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 254 additions and 794 deletions

View File

@ -10,27 +10,31 @@
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;">
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: {{ if .Repository.LastScanningErrors }} 15px; {{ else }} 25px; {{ end }}">
We encountered some errors while scanning the packages in repository <strong>{{ .Repository.Name }}</strong> for security vulnerabilities.
</p>
<h4 style="color: #921e12; font-family: sans-serif; margin: 0; Margin-bottom: 15px;">Errors log</h4>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="Margin-bottom: 30px; border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; background: #1D1F21; border-radius: 3px;">
<tbody>
<tr>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding: 16px;">
<code style="overflow-x: auto;">
{{ range $index, $scanningError := .Repository.LastScanningErrors }}
{{ if $index }}
<p style="font-family: 'Courier New', Courier, monospace; color: #C5C8C6 !important; border-top: 1px solid #333; padding-top: 15px; font-size: 13px; ">{{ $scanningError }}</p>
{{ else }}
<p style="font-family: 'Courier New', Courier, monospace; color: #C5C8C6 !important;font-size: 13px;">{{ $scanningError }}</p>
{{end}}
{{ end }}
</code>
</td>
</tr>
</tbody>
</table>
{{ if .Repository.LastScanningErrors }}
<h4 style="color: #921e12; font-family: sans-serif; margin: 0; Margin-bottom: 15px;">Errors log</h4>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="Margin-bottom: 30px; border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; background: #1D1F21; border-radius: 3px;">
<tbody>
<tr>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding: 16px;">
<code style="overflow-x: auto;">
{{ range $index, $scanningError := .Repository.LastScanningErrors }}
{{ if $index }}
<p style="font-family: 'Courier New', Courier, monospace; color: #C5C8C6 !important; border-top: 1px solid #333; padding-top: 15px; font-size: 13px; ">{{ $scanningError }}</p>
{{ else }}
<p style="font-family: 'Courier New', Courier, monospace; color: #C5C8C6 !important;font-size: 13px;">{{ $scanningError }}</p>
{{end}}
{{ end }}
</code>
</td>
</tr>
</tbody>
</table>
{{ end }}
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
<tbody>
<tr>

View File

@ -15,29 +15,30 @@
We encountered some errors while tracking repository <strong>{{ .Repository.Name }}</strong>.
</p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;">
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: {{ if .Repository.LastTrackingErrors }} 15px; {{ else }} 25px; {{ end }}">
Some or all of these errors may be just warnings, and it's possible that your packages have been still indexed properly. However, it'd be great if you can take a look at them just in case there is something missing or failing in your repository that may affect how your content is displayed on {{ .Theme.SiteName }}.
</p>
<h4 style="color: #921e12; font-family: sans-serif; margin: 0; Margin-bottom: 15px;">Errors log</h4>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="Margin-bottom: 30px; border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; background: #1D1F21; border-radius: 3px;">
<tbody>
<tr>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding: 16px;">
<code style="overflow-x: auto;">
{{ range $index, $trackingError := .Repository.LastTrackingErrors }}
{{ if $index }}
<p style="font-family: 'Courier New', Courier, monospace; color: #C5C8C6 !important; border-top: 1px solid #333; padding-top: 15px; font-size: 13px; ">{{ $trackingError }}</p>
{{ else }}
<p style="font-family: 'Courier New', Courier, monospace; color: #C5C8C6 !important;font-size: 13px;">{{ $trackingError }}</p>
{{end}}
{{ end }}
</code>
</td>
</tr>
</tbody>
</table>
{{ if .Repository.LastTrackingErrors }}
<h4 style="color: #921e12; font-family: sans-serif; margin: 0; Margin-bottom: 15px;">Errors log</h4>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="Margin-bottom: 30px; border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; background: #1D1F21; border-radius: 3px;">
<tbody>
<tr>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding: 16px;">
<code style="overflow-x: auto;">
{{ range $index, $trackingError := .Repository.LastTrackingErrors }}
{{ if $index }}
<p style="font-family: 'Courier New', Courier, monospace; color: #C5C8C6 !important; border-top: 1px solid #333; padding-top: 15px; font-size: 13px; ">{{ $trackingError }}</p>
{{ else }}
<p style="font-family: 'Courier New', Courier, monospace; color: #C5C8C6 !important;font-size: 13px;">{{ $trackingError }}</p>
{{end}}
{{ end }}
</code>
</td>
</tr>
</tbody>
</table>
{{ end }}
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
<tbody>

View File

@ -346,6 +346,15 @@ func (w *Worker) prepareRepoNotificationTemplateData(
eventKindStr = "repository.ownership-claim"
}
// Prepare last scanning and tracking errors
var lastScanningErrors, lastTrackingErrors []string
if v := strings.TrimSpace(r.LastScanningErrors); v != "" {
lastScanningErrors = strings.Split(v, "\n")
}
if v := strings.TrimSpace(r.LastTrackingErrors); v != "" {
lastTrackingErrors = strings.Split(v, "\n")
}
return &hub.RepositoryNotificationTemplateData{
BaseURL: w.svc.Cfg.GetString("server.baseURL"),
Event: map[string]interface{}{
@ -357,8 +366,8 @@ func (w *Worker) prepareRepoNotificationTemplateData(
"Name": r.Name,
"UserAlias": r.UserAlias,
"OrganizationName": r.OrganizationName,
"LastScanningErrors": strings.Split(r.LastScanningErrors, "\n"),
"LastTrackingErrors": strings.Split(r.LastTrackingErrors, "\n"),
"LastScanningErrors": lastScanningErrors,
"LastTrackingErrors": lastTrackingErrors,
},
Theme: map[string]string{
"PrimaryColor": w.svc.Cfg.GetString("theme.colors.primary"),

View File

@ -82,6 +82,7 @@
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
word-break: break-all;
}
.lastLine {
@ -111,6 +112,7 @@
@media only screen and (max-width: 575.98px) {
.lineClamp {
-webkit-line-clamp: 2;
word-break: normal;
}
}

View File

@ -6,6 +6,7 @@ import { useHistory } from 'react-router-dom';
import { Package, RepositoryKind } from '../../types';
import buildPackageURL from '../../utils/buildPackageURL';
import cutString from '../../utils/cutString';
import isFuture from '../../utils/isFuture';
import isPackageOfficial from '../../utils/isPackageOfficial';
import { prepareQueryString } from '../../utils/prepareQueryString';
import License from '../package/License';
@ -31,9 +32,13 @@ const PackageInfo = (props: Props) => {
const history = useHistory();
const pkgTS = (
<small className={`text-muted text-nowrap ${styles.date}`}>
Updated {moment(props.package.ts * 1000).fromNow()}
</small>
<>
{!isFuture(props.package.ts) && (
<small className={`text-muted text-nowrap ${styles.date}`}>
Updated {moment.unix(props.package.ts).fromNow()}
</small>
)}
</>
);
const starsAndKindInfo = (

View File

@ -13,6 +13,10 @@
right: 138px !important;
}
.onlyBadgeTooltipArrow {
right: 5px !important;
}
.ratingLetter {
top: 1px;
}

View File

@ -65,7 +65,7 @@ const SecurityRating = (props: Props) => {
}
alignmentTooltip="right"
tooltipClassName={styles.tooltip}
tooltipArrowClassName={styles.tooltipArrow}
tooltipArrowClassName={props.onlyBadge ? styles.onlyBadgeTooltipArrow : styles.tooltipArrow}
tooltipMessage={
<div className="d-flex flex-column">
<div className="d-flex flex-row align-items-center my-1">

View File

@ -15,6 +15,7 @@ import { tomorrowNight } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
import { AppCtx } from '../../../context/AppCtx';
import useOutsideClick from '../../../hooks/useOutsideClick';
import { AuthorizerAction, Repository } from '../../../types';
import isFuture from '../../../utils/isFuture';
import minutesToNearestInterval from '../../../utils/minutesToNearestInterval';
import ButtonCopyToClipboard from '../../common/ButtonCopyToClipboard';
import DisabledRepositoryBadge from '../../common/DisabledRepositoryBadge';
@ -95,7 +96,9 @@ const RepositoryCard = (props: Props) => {
const content = (
<>
<span>{moment(props.repository.lastTrackingTs! * 1000).fromNow()}</span>
{!isFuture(props.repository.lastTrackingTs!) && (
<span>{moment.unix(props.repository.lastTrackingTs!).fromNow()}</span>
)}
{hasErrors ? (
<>
<FaExclamation className="ml-2 text-warning" />
@ -195,7 +198,9 @@ const RepositoryCard = (props: Props) => {
const content = (
<>
<span>{moment(props.repository.lastScanningTs! * 1000).fromNow()}</span>
{!isFuture(props.repository.lastScanningTs!) && (
<span>{moment.unix(props.repository.lastScanningTs!).fromNow()}</span>
)}
{hasScanningErrors ? (
<FaExclamation className="mx-2 text-warning" />
) : (

View File

@ -18,6 +18,10 @@
font-size: 1rem;
}
.trackingWarningBtn {
min-width: 20px;
}
@media only screen and (max-width: 767.98px) {
.title {
font-size: 1.25rem;

View File

@ -11,7 +11,7 @@ const RepositoryWarningModal = () => {
<>
<button
data-testid="trackingWarningBtn"
className="d-inline-block pl-0 pr-1 py-2 btn btn-link"
className={`d-inline-block pl-0 pr-1 py-2 btn btn-link ${styles.trackingWarningBtn}`}
onClick={() => setOpenStatus(true)}
>
<small>

View File

@ -3,7 +3,7 @@
exports[`RepositoryWarningModal creates snapshot 1`] = `
<DocumentFragment>
<button
class="d-inline-block pl-0 pr-1 py-2 btn btn-link"
class="d-inline-block pl-0 pr-1 py-2 btn btn-link trackingWarningBtn"
data-testid="trackingWarningBtn"
>
<small>

View File

@ -8,7 +8,12 @@ import alertDispatcher from '../../../../../utils/alertDispatcher';
import Card from './Card';
jest.mock('../../../../../api');
jest.mock('../../../../../utils/alertDispatcher');
jest.mock('moment', () => () => ({ format: () => '2020/06/18 16:35:39 (+00:00)' }));
jest.mock('moment', () => ({
...(jest.requireActual('moment') as {}),
unix: () => ({
format: () => '2020/06/18 16:35:39 (+00:00)',
}),
}));
const APIKeyMock: APIKey = {
apiKeyId: 'bf28013f-610e-4691-80a2-bd3a673c4b3f',

View File

@ -188,7 +188,7 @@ const APIKeyCard = (props: Props) => {
</div>
<div className="text-truncate">
<small className="text-muted text-uppercase mr-1">Created at: </small>
<small>{moment(props.apiKey.createdAt! * 1000).format('YYYY/MM/DD HH:mm:ss (Z)')}</small>
<small>{moment.unix(props.apiKey.createdAt!).format('YYYY/MM/DD HH:mm:ss (Z)')}</small>
</div>
</div>
</div>

View File

@ -7,7 +7,7 @@ import API from '../../../../../api';
import { ErrorKind } from '../../../../../types';
import APIKeysSection from './index';
jest.mock('../../../../../api');
jest.mock('moment', () => () => ({ format: () => '2020/06/18 16:35:39 (+00:00)' }));
jest.mock('moment', () => ({ ...(jest.requireActual('moment') as {}), format: () => '2020/06/18 16:35:39 (+00:00)' }));
const getMockAPIKeys = (fixtureId: string) => {
return require(`./__fixtures__/index/${fixtureId}.json`);

View File

@ -57,7 +57,7 @@ const WebhookCard = (props: Props) => {
return (
<div className="col-12 col-xxl-6 py-sm-3 py-2" role="listitem">
<div className={`card cardWithHover w-100 ${styles.card}`}>
<div className={`card cardWithHover w-100 h-100 ${styles.card}`}>
<div className={`card-body p-0 position-relative ${styles.body}`}>
<div className="d-flex flex-row">
<div className={`h5 card-title mb-3 mr-3 ${styles.title}`}>

View File

@ -78,3 +78,10 @@
opacity: 1;
}
}
@media (min-width: 1920px) {
.btnWrapper {
max-width: 66.66667%;
padding-right: 5px;
}
}

View File

@ -773,7 +773,7 @@ const WebhookForm = (props: Props) => {
</div>
</div>
<div className="mt-4 mt-md-5">
<div className={`mt-4 mt-md-5 ${styles.btnWrapper}`}>
<div className="d-flex flex-row justify-content-between">
<div className="d-flex flex-row align-items-center mr-3">
<button

View File

@ -46,12 +46,12 @@ const LastNotificationsModal = (props: Props) => {
{props.notifications.map((item: WebhookNotification) => (
<tr data-testid="lastNotificationCell" key={`lastNotif_${item.notificationId}`}>
<td className="align-middle">{item.notificationId}</td>
<td className="align-middle">{moment(item.createdAt * 1000).format('YYYY/MM/DD HH:mm:ss (Z)')}</td>
<td className="align-middle">{moment.unix(item.createdAt).format('YYYY/MM/DD HH:mm:ss (Z)')}</td>
<td className="align-middle text-center">
{item.processed && <FaCheck className="text-success" data-testid="processedIcon" />}
</td>
<td className="align-middle">
{!isNull(item.processedAt) && moment(item.processedAt * 1000).format('YYYY/MM/DD HH:mm:ss (Z)')}
{!isNull(item.processedAt) && moment.unix(item.processedAt).format('YYYY/MM/DD HH:mm:ss (Z)')}
</td>
<td className="align-middle text-center">
{item.processed && (

View File

@ -7,7 +7,13 @@ import { ChangeLog } from '../../types';
import ChangelogModal from './ChangelogModal';
jest.mock('../../api');
jest.mock('moment', () => () => ({ fromNow: () => '3 hours ago' }));
jest.mock('moment', () => ({
...(jest.requireActual('moment') as {}),
unix: () => ({
isAfter: () => false,
fromNow: () => '3 hours ago',
}),
}));
const getMockChangelog = (fixtureId: string): ChangeLog[] => {
return require(`./__fixtures__/ChangelogModal/${fixtureId}.json`) as ChangeLog[];
@ -41,6 +47,10 @@ describe('ChangelogModal', () => {
jest.resetAllMocks();
});
beforeEach(() => {
jest.spyOn(Date, 'now').mockReturnValueOnce(new Date('2019/11/24').getTime());
});
it('creates snapshot', async () => {
const mockChangelog = getMockChangelog('1');
mocked(API).getChangelog.mockResolvedValue(mockChangelog);

View File

@ -15,6 +15,7 @@ import API from '../../api';
import { Change, ChangeKind, ChangeLog, PackageLink, Repository, RepositoryKind, SearchFiltersURL } from '../../types';
import alertDispatcher from '../../utils/alertDispatcher';
import buildPackageURL from '../../utils/buildPackageURL';
import isFuture from '../../utils/isFuture';
import ElementWithTooltip from '../common/ElementWithTooltip';
import ExternalLink from '../common/ExternalLink';
import Modal from '../common/Modal';
@ -199,9 +200,11 @@ const ChangelogModal = (props: Props) => {
</div>
)}
<div className="ml-auto pl-0 pl-md-2 text-nowrap">
<small className="text-muted">Released {moment(item.ts * 1000).fromNow()}</small>
</div>
{!isFuture(item.ts) && (
<div className="ml-auto pl-0 pl-md-2 text-nowrap">
<small className="text-muted">Released {moment.unix(item.ts).fromNow()}</small>
</div>
)}
</div>
<div className={`d-flex flex-column mb-4 ${styles.list}`}>

View File

@ -39,7 +39,7 @@ const Version = (props: Props) => {
}
}, [props.isActive, isLoading]);
const formattedDate = moment(props.ts! * 1000).format('D MMM, YYYY');
const formattedDate = moment.unix(props.ts!).format('D MMM, YYYY');
const getBadges = () => (
<>

View File

@ -29,7 +29,7 @@ const VersionInRow = (props: Props) => {
});
};
const formattedDate = moment(props.ts! * 1000).format('D MMM, YYYY');
const formattedDate = moment.unix(props.ts!).format('D MMM, YYYY');
return (
<tr>

View File

@ -43,7 +43,7 @@ describe('WidgetModal', () => {
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByText('Theme')).toBeInTheDocument();
expect(screen.getAllByText('light')).toHaveLength(2);
expect(screen.getByText('light')).toBeInTheDocument();
expect(screen.getByText('dark')).toBeInTheDocument();
expect(screen.getByTestId('radio-theme-light')).toBeChecked();
expect(screen.getByTestId('radio-theme-dark')).not.toBeChecked();

View File

@ -191,7 +191,7 @@ const WidgetModal = (props: Props) => {
<div data-testid="block-content" className={`flex-grow-1 mr-3 user-select-none ${styles.blockWrapper}`}>
<SyntaxHighlighter
language="html"
language="text"
style={docco}
customStyle={{
backgroundColor: 'var(--color-1-10)',

View File

@ -261,411 +261,11 @@ exports[`WidgetModal creates snapshot 1`] = `
style="display: block; overflow-x: auto; padding: 0.5em; color: rgb(0, 0, 0); background: rgb(248, 248, 255);"
>
<code
class="language-html"
class="language-text"
style="white-space: pre;"
>
<span>
&lt;div
</span>
<span
style="color: rgb(149, 65, 33);"
>
class
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
artifacthub
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
widget
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
url
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
http:
</span>
<span>
//
</span>
<span
style="color: rgb(153, 0, 115);"
>
localhost
</span>
<span>
/"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
theme
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
light
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
header
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
true
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
responsive
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
false
</span>
<span>
"&gt;&lt;
</span>
<span
style="color: rgb(153, 0, 115);"
>
blockquote
</span>
<span>
&gt;&lt;
</span>
<span
style="color: rgb(153, 0, 115);"
>
p
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
lang
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
en
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
dir
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
ltr
</span>
<span>
"&gt;&lt;
</span>
<span
style="color: rgb(153, 0, 115);"
>
b
</span>
<span>
&gt;
</span>
<span
style="color: rgb(153, 0, 115);"
>
pkg
</span>
<span>
&lt;/
</span>
<span
style="color: rgb(153, 0, 115);"
>
b
</span>
<span>
&gt;:
</span>
<span
style="color: rgb(153, 0, 115);"
>
this
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
is
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
the
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
description
</span>
<span>
&lt;/
</span>
<span
style="color: rgb(153, 0, 115);"
>
p
</span>
<span>
&gt;&
</span>
<span
style="color: rgb(153, 0, 115);"
>
mdash
</span>
<span>
;
</span>
<span
style="color: rgb(153, 0, 115);"
>
Open
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
in
</span>
<span>
&lt;
</span>
<span
style="color: rgb(153, 0, 115);"
>
a
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
href
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
http:
</span>
<span>
//
</span>
<span
style="color: rgb(153, 0, 115);"
>
localhost
</span>
<span>
/"&gt;
</span>
<span
style="color: rgb(153, 0, 115);"
>
null
</span>
<span>
&lt;/
</span>
<span
style="color: rgb(153, 0, 115);"
>
a
</span>
<span>
&gt;&lt;/
</span>
<span
style="color: rgb(153, 0, 115);"
>
blockquote
</span>
<span>
&gt;&lt;/
</span>
<span
style="color: rgb(153, 0, 115);"
>
div
</span>
<span>
&gt;&lt;
</span>
<span
style="color: rgb(153, 0, 115);"
>
script
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
async
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
src
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
http:
</span>
<span>
//
</span>
<span
style="color: rgb(153, 0, 115);"
>
localhost
</span>
<span>
/
</span>
<span
style="color: rgb(153, 0, 115);"
>
artifacthub
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
widget
</span>
<span>
.
</span>
<span
style="color: rgb(153, 0, 115);"
>
js
</span>
<span>
"&gt;&lt;/
</span>
<span
style="color: rgb(153, 0, 115);"
>
script
</span>
<span>
&gt;
&lt;div class="artifacthub-widget" data-url="http://localhost/" data-theme="light" data-header="true" data-responsive="false"&gt;&lt;blockquote&gt;&lt;p lang="en" dir="ltr"&gt;&lt;b&gt;pkg&lt;/b&gt;: this is the description&lt;/p&gt;&mdash; Open in &lt;a href="http://localhost/"&gt;null&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;script async src="http://localhost/artifacthub-widget.js"&gt;&lt;/script&gt;
</span>
</code>
</pre>

View File

@ -24,6 +24,7 @@ import {
SearchFiltersURL,
Version,
} from '../../types';
import isFuture from '../../utils/isFuture';
import isPackageOfficial from '../../utils/isPackageOfficial';
import { prepareQueryString } from '../../utils/prepareQueryString';
import sortPackageVersions from '../../utils/sortPackageVersions';
@ -558,9 +559,11 @@ const PackageView = (props: Props) => {
<div className="d-flex flex-wrap d-md-none">{getBadges(true, 'mt-3 mt-md-0')}</div>
<div className={`position-absolute d-flex flex-row align-items-center ${styles.optsWrapper}`}>
<span className={`d-block d-md-none text-muted text-nowrap ${styles.date}`}>
Updated {moment(detail!.ts * 1000).fromNow()}
</span>
{detail!.ts && !isFuture(detail!.ts) && (
<span className={`d-block d-md-none text-muted text-nowrap ${styles.date}`}>
Updated {moment.unix(detail!.ts).fromNow()}
</span>
)}
<StarButton packageId={detail.packageId} />
<SubscriptionsButton packageId={detail.packageId} />
<MoreActionsButton

View File

@ -80,6 +80,10 @@
background-color: var(--color-1-5) !important;
}
.md table code {
white-space: normal;
}
.md a {
overflow-wrap: break-word;
}

View File

@ -36,6 +36,10 @@ interface BasicProps {
children: JSX.Element | JSX.Element[];
}
interface TableRowProps extends BasicProps {
columnAlignment: any[];
}
const AVAILABLE_LANGUAGES = [
'oneC',
'abnf',
@ -328,6 +332,22 @@ const Readme = (props: Props) => {
</div>
);
const TableRow: React.ElementType = (data: TableRowProps) => {
// Fix tables with empty cells
if (isArray(data.children) && data.columnAlignment.length !== data.children.length) {
return (
<tr>
{data.children}
{[...Array(data.columnAlignment.length - data.children.length)].map((e, i) => (
<td key={`tr_td_${i}`}></td>
))}
</tr>
);
} else {
return <tr>{data.children}</tr>;
}
};
const Paragraph: React.ElementType = (data: BasicProps) => {
const isOneChild = data.children && isArray(data.children) && data.children.length === 1;
if (isUndefined(data.children)) return null;
@ -355,7 +375,7 @@ const Readme = (props: Props) => {
children={props.readme}
linkTarget="_blank"
skipHtml
plugins={[[gfm, { singleTilde: false }]]}
plugins={[[gfm, { tableCellPadding: false }]]}
renderers={{
code: Code,
image: Image,
@ -363,6 +383,7 @@ const Readme = (props: Props) => {
imageReference: Image,
linkReference: Link,
table: Table,
tableRow: TableRow,
heading: Heading,
paragraph: Paragraph,
blockquote: Blockquote,

View File

@ -5,6 +5,7 @@ import { FaCaretDown, FaCaretRight, FaLink } from 'react-icons/fa';
import { Vulnerability, VulnerabilitySeverity } from '../../../types';
import { SEVERITY_RATING } from '../../../utils/data';
import isFuture from '../../../utils/isFuture';
import ExternalLink from '../../common/ExternalLink';
import styles from './Cell.module.css';
import CVSSVector from './CVSSVector';
@ -104,11 +105,12 @@ const SecurityCell = (props: Props) => {
<p className="text-muted mb-1">{props.vulnerability.Description}</p>
)}
<div className="d-flex flex-column text-right">
{!isUndefined(props.vulnerability.LastModifiedDate) && (
<small className="font-italic">
Updated {moment(props.vulnerability.LastModifiedDate).fromNow()}
</small>
)}
{!isUndefined(props.vulnerability.LastModifiedDate) &&
!isFuture(props.vulnerability.LastModifiedDate, false) && (
<small className="font-italic">
Updated {moment(props.vulnerability.LastModifiedDate).fromNow()}
</small>
)}
</div>
{props.vulnerability.CVSS && (
<CVSSVector

View File

@ -7,7 +7,13 @@ import { SecurityReport, VulnerabilitySeverity } from '../../../types';
import SecurityModal from './Modal';
jest.mock('../../../api');
jest.mock('moment', () => () => ({ fromNow: () => '3 hours ago' }));
jest.mock('moment', () => ({
...(jest.requireActual('moment') as {}),
unix: () => ({
isAfter: () => false,
fromNow: () => '3 hours ago',
}),
}));
const getMockSecurityReport = (fixtureId: string): SecurityReport => {
return require(`./__fixtures__/Modal/${fixtureId}.json`) as SecurityReport;
@ -34,6 +40,7 @@ const defaultProps = {
packageId: 'pkgID',
version: '1.1.1',
visibleSecurityReport: false,
hasWhitelistedContainers: false,
};
describe('SecurityModal', () => {

View File

@ -7,6 +7,7 @@ import { useHistory } from 'react-router-dom';
import API from '../../../api';
import { SearchFiltersURL, SecurityReport, SecurityReportSummary } from '../../../types';
import alertDispatcher from '../../../utils/alertDispatcher';
import isFuture from '../../../utils/isFuture';
import Modal from '../../common/Modal';
import styles from './Modal.module.css';
import SecuritySummary from './Summary';
@ -100,9 +101,9 @@ const SecurityModal = (props: Props) => {
return (
<>
<div>
{props.createdAt && (
{props.createdAt && !isFuture(props.createdAt) && (
<div className={`my-2 ${styles.created}`}>
<small className="text-uppercase text-muted">Last scan: </small> {moment(props.createdAt * 1000).fromNow()}
<small className="text-uppercase text-muted">Last scan: </small> {moment.unix(props.createdAt).fromNow()}
</div>
)}

View File

@ -31,12 +31,12 @@ describe('WidgetsGroupModal', () => {
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByText('Theme')).toBeInTheDocument();
expect(screen.getAllByText('light')).toHaveLength(2);
expect(screen.getByText('light')).toBeInTheDocument();
expect(screen.getByText('dark')).toBeInTheDocument();
expect(screen.getByTestId('radio-theme-light')).toBeChecked();
expect(screen.getByTestId('radio-theme-dark')).not.toBeChecked();
expect(screen.getByText('Container width')).toBeInTheDocument();
expect(screen.getAllByText('responsive')).toHaveLength(2);
expect(screen.getByText('responsive')).toBeInTheDocument();
expect(screen.getByText('fixed')).toBeInTheDocument();
expect(screen.getByTestId('radio-wrapper-width-responsive')).toBeChecked();
expect(screen.getByTestId('radio-wrapper-width-fixed')).not.toBeChecked();

View File

@ -109,6 +109,7 @@ const WidgetsGroupModal = (props: Props) => {
fixedWidth,
groupWrapperWidthOpt,
color,
loading,
props.visibleWidget,
]); /* eslint-enable react-hooks/exhaustive-deps */
@ -316,7 +317,7 @@ const WidgetsGroupModal = (props: Props) => {
<div data-testid="block-content" className={`flex-grow-1 mr-3 user-select-none ${styles.blockWrapper}`}>
<SyntaxHighlighter
language="html"
language="text"
style={docco}
customStyle={{
backgroundColor: 'var(--color-1-10)',

View File

@ -417,275 +417,11 @@ exports[`WidgetsGroupModal creates snapshot 1`] = `
style="display: block; overflow-x: auto; padding: 0.5em; color: rgb(0, 0, 0); background: rgb(248, 248, 255);"
>
<code
class="language-html"
class="language-text"
style="white-space: pre;"
>
<span>
&lt;div
</span>
<span
style="color: rgb(149, 65, 33);"
>
class
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
artifacthub
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
widget
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
group
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
url
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
http:
</span>
<span>
//
</span>
<span
style="color: rgb(153, 0, 115);"
>
localhost
</span>
<span>
/"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
theme
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
light
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
header
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
false
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
color
</span>
<span>
="#
</span>
<span
style="color: rgb(153, 0, 115);"
>
417598
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
responsive
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
true
</span>
<span>
"
</span>
<span
style="color: rgb(153, 0, 115);"
>
data
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
loading
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
true
</span>
<span>
"&gt;&lt;/
</span>
<span
style="color: rgb(153, 0, 115);"
>
div
</span>
<span>
&gt;&lt;
</span>
<span
style="color: rgb(153, 0, 115);"
>
script
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
async
</span>
<span>
</span>
<span
style="color: rgb(153, 0, 115);"
>
src
</span>
<span>
="
</span>
<span
style="color: rgb(153, 0, 115);"
>
http:
</span>
<span>
//
</span>
<span
style="color: rgb(153, 0, 115);"
>
localhost
</span>
<span>
/
</span>
<span
style="color: rgb(153, 0, 115);"
>
artifacthub
</span>
<span>
-
</span>
<span
style="color: rgb(153, 0, 115);"
>
widget
</span>
<span>
.
</span>
<span
style="color: rgb(153, 0, 115);"
>
js
</span>
<span>
"&gt;&lt;/
</span>
<span
style="color: rgb(153, 0, 115);"
>
script
</span>
<span>
&gt;
&lt;div class="artifacthub-widget-group" data-url="http://localhost/" data-theme="light" data-header="false" data-color="#417598" data-responsive="true" data-loading="true"&gt;&lt;/div&gt;&lt;script async src="http://localhost/artifacthub-widget.js"&gt;&lt;/script&gt;
</span>
</code>
</pre>

View File

@ -0,0 +1,9 @@
import moment from 'moment';
export default (date: number, timestampFormat: boolean = true): boolean => {
if (!timestampFormat) {
return moment(date).isAfter();
} else {
return moment.unix(date).isAfter();
}
};

View File

@ -7,7 +7,12 @@ import { SearchResults } from '../types';
import Group from './Group';
jest.mock('../api');
jest.mock('moment', () => () => ({ fromNow: () => '3 days ago' }));
jest.mock('moment', () => ({
...(jest.requireActual('moment') as {}),
unix: () => ({
fromNow: () => '3 hours ago',
}),
}));
const defaultProps = {
url: 'https://localhost:8000/api/v1/packages/search',

View File

@ -7,7 +7,12 @@ import { PackageSummary } from '../types';
import Widget from './Widget';
jest.mock('../api');
jest.mock('moment', () => () => ({ fromNow: () => '3 days ago' }));
jest.mock('moment', () => ({
...(jest.requireActual('moment') as {}),
unix: () => ({
fromNow: () => '3 hours ago',
}),
}));
const defaultProps = {
url: 'https://localhost:8000/packages/helm/artifact-hub/artifact-hub',
@ -74,7 +79,7 @@ describe('Widget', () => {
expect(screen.getByText('Official')).toBeInTheDocument();
expect(screen.getByTitle('verified')).toBeInTheDocument();
expect(screen.getByText('Verified Publisher')).toBeInTheDocument();
expect(screen.getByText('Updated 3 days ago')).toBeInTheDocument();
expect(screen.getByText('Updated 3 hours ago')).toBeInTheDocument();
const image = screen.getByAltText('Logo artifact-hub');
expect(image).toBeInTheDocument();
@ -141,7 +146,7 @@ describe('Widget', () => {
expect(screen.getByText('Official')).toBeInTheDocument();
expect(screen.getByTitle('verified')).toBeInTheDocument();
expect(screen.getByText('Verified Publisher')).toBeInTheDocument();
expect(screen.getByText('Updated 3 days ago')).toBeInTheDocument();
expect(screen.getByText('Updated 3 hours ago')).toBeInTheDocument();
const image = screen.getByAltText('Logo artifact-hub');
expect(image).toBeInTheDocument();

View File

@ -417,7 +417,7 @@ export default function Widget(props: Props) {
theme={currentTheme}
/>
<Date>Updated {moment(packageSummary.ts * 1000).fromNow()}</Date>
<Date>Updated {moment.unix(packageSummary.ts).fromNow()}</Date>
</ExtraInfo>
<Description>{packageSummary.description || ''}</Description>

View File

@ -1892,9 +1892,9 @@
integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
"@types/node@*":
version "15.12.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.2.tgz#1f2b42c4be7156ff4a6f914b2fb03d05fa84e38d"
integrity sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==
version "15.12.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.4.tgz#e1cf817d70a1e118e81922c4ff6683ce9d422e26"
integrity sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==
"@types/node@^14.6.4":
version "14.17.3"
@ -1927,9 +1927,9 @@
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/react-dom@>=16.9.0":
version "17.0.7"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.7.tgz#b8ee15ead9e5d6c2c858b44949fdf2ebe5212232"
integrity sha512-Wd5xvZRlccOrCTej8jZkoFZuZRKHzanDDv1xglI33oBNFMWrqOSzrvWFw7ngSiZjrpJAzPKFtX7JvuXpkNmQHA==
version "17.0.8"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.8.tgz#3180de6d79bf53762001ad854e3ce49f36dd71fc"
integrity sha512-0ohAiJAx1DAUEcY9UopnfwCE9sSMDGnY/oXjWMax6g3RpzmTt2GMyMVAXcbn0mo8XAff0SbQJl2/SBU+hjSZ1A==
dependencies:
"@types/react" "*"
@ -2816,12 +2816,12 @@ babel-plugin-polyfill-corejs2@^0.2.2:
semver "^6.1.1"
babel-plugin-polyfill-corejs3@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.2.tgz#7424a1682ee44baec817327710b1b094e5f8f7f5"
integrity sha512-l1Cf8PKk12eEk5QP/NQ6TH8A1pee6wWDJ96WjxrMXFLHLOBFzYM4moG80HFgduVhTqAFez4alnZKEhP/bYHg0A==
version "0.2.3"
resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.3.tgz#72add68cf08a8bf139ba6e6dfc0b1d504098e57b"
integrity sha512-rCOFzEIJpJEAU14XCcV/erIf/wZQMmMT5l5vXOpL5uoznyOGfDIjPj6FVytMvtzaKSTSVKouOCTPJ5OMUZH30g==
dependencies:
"@babel/helper-define-polyfill-provider" "^0.2.2"
core-js-compat "^3.9.1"
core-js-compat "^3.14.0"
babel-plugin-polyfill-regenerator@^0.2.2:
version "0.2.2"
@ -3337,9 +3337,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001219:
version "1.0.30001237"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001237.tgz#4b7783661515b8e7151fc6376cfd97f0e427b9e5"
integrity sha512-pDHgRndit6p1NR2GhzMbQ6CkRrp4VKuSsqbcLeOQppYPKOYkKT/6ZvZDvKJUqcmtyWIAHuZq3SVS2vc1egCZzw==
version "1.0.30001239"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001239.tgz#66e8669985bb2cb84ccb10f68c25ce6dd3e4d2b8"
integrity sha512-cyBkXJDMeI4wthy8xJ2FvDU6+0dtcZSJW3voUF8+e9f1bBeuvyZfc3PNbkOETyhbR+dGCPzn9E7MA3iwzusOhQ==
capture-exit@^2.0.0:
version "2.0.0"
@ -3709,7 +3709,7 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
convert-source-map@1.7.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
convert-source-map@1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
@ -3721,6 +3721,13 @@ convert-source-map@^0.3.3:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA=
convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
dependencies:
safe-buffer "~5.1.1"
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
@ -3755,18 +3762,18 @@ copy-to-clipboard@^3.2.0:
dependencies:
toggle-selection "^1.0.6"
core-js-compat@^3.14.0, core-js-compat@^3.6.2, core-js-compat@^3.9.1:
version "3.14.0"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.14.0.tgz#b574dabf29184681d5b16357bd33d104df3d29a5"
integrity sha512-R4NS2eupxtiJU+VwgkF9WTpnSfZW4pogwKHd8bclWU2sp93Pr5S1uYJI84cMOubJRou7bcfL0vmwtLslWN5p3A==
core-js-compat@^3.14.0, core-js-compat@^3.6.2:
version "3.15.0"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.15.0.tgz#e14a371123db9d1c5b41206d3f420643d238b8fa"
integrity sha512-8X6lWsG+s7IfOKzV93a7fRYfWRZobOfjw5V5rrq43Vh/W+V6qYxl7Akalsvgab4PFT/4L/pjQbdBUEM36NXKrw==
dependencies:
browserslist "^4.16.6"
semver "7.0.0"
core-js-pure@^3.14.0:
version "3.14.0"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.14.0.tgz#72bcfacba74a65ffce04bf94ae91d966e80ee553"
integrity sha512-YVh+LN2FgNU0odThzm61BsdkwrbrchumFq3oztnE9vTKC4KS2fvnPmcx8t6jnqAyOTCTF4ZSiuK8Qhh7SNcL4g==
version "3.15.0"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.15.0.tgz#c19349ae0be197b8bcf304acf4d91c5e29ae2091"
integrity sha512-RO+LFAso8DB6OeBX9BAcEGvyth36QtxYon1OyVsITNVtSKr/Hos0BXZwnsOJ7o+O6KHtK+O+cJIEj9NGg6VwFA==
core-js@^2.4.0:
version "2.6.12"
@ -3774,9 +3781,9 @@ core-js@^2.4.0:
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-js@^3.6.5:
version "3.14.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.14.0.tgz#62322b98c71cc2018b027971a69419e2425c2a6c"
integrity sha512-3s+ed8er9ahK+zJpp9ZtuVcDoFzHNiZsPbNAAE4KXgrRHbjSqqNN6xGSXq6bq7TZIbKj4NLrLb6bJ5i+vSVjHA==
version "3.15.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.15.0.tgz#db9554ebce0b6fd90dc9b1f2465c841d2d055044"
integrity sha512-GUbtPllXMYRzIgHNZ4dTYTcUemls2cni83Q4Q/TrFONHfhcg9oEGOtaGHfb0cpzec60P96UKPvMkjX1jET8rUw==
core-util-is@~1.0.0:
version "1.0.2"
@ -4948,9 +4955,9 @@ eslint@^6.8.0:
v8-compile-cache "^2.0.3"
eslint@^7.11.0:
version "7.28.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.28.0.tgz#435aa17a0b82c13bb2be9d51408b617e49c1e820"
integrity sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==
version "7.29.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.29.0.tgz#ee2a7648f2e729485e4d0bd6383ec1deabc8b3c0"
integrity sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==
dependencies:
"@babel/code-frame" "7.12.11"
"@eslint/eslintrc" "^0.4.2"
@ -5728,9 +5735,9 @@ globby@11.0.1:
slash "^3.0.0"
globby@^11.0.3:
version "11.0.3"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb"
integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==
version "11.0.4"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
dependencies:
array-union "^2.1.0"
dir-glob "^3.0.1"
@ -9249,9 +9256,9 @@ postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, po
supports-color "^6.1.0"
postcss@^8.1.0:
version "8.3.4"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.4.tgz#41ece1c43f2f7c74dc7d90144047ce052757b822"
integrity sha512-/tZY0PXExXXnNhKv3TOvZAOUYRyuqcCbBm2c17YMDK0PlVII3K7/LKdt3ScHL+hhouddjUWi+1sKDf9xXW+8YA==
version "8.3.5"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709"
integrity sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.23"
@ -11415,9 +11422,9 @@ typedarray@^0.0.6:
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^3.9.7:
version "3.9.9"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674"
integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==
version "3.9.10"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==
unbox-primitive@^1.0.1:
version "1.0.1"
@ -12152,9 +12159,9 @@ ws@^6.2.1:
async-limiter "~1.0.0"
ws@^7.4.5:
version "7.4.6"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
version "7.5.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.0.tgz#0033bafea031fb9df041b2026fc72a571ca44691"
integrity sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==
xml-name-validator@^3.0.0:
version "3.0.0"
@ -12192,9 +12199,9 @@ yaml@^1.10.0, yaml@^1.7.2:
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yargs-parser@20.x:
version "20.2.7"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a"
integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
yargs-parser@^13.1.2:
version "13.1.2"