New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@lhci/server

Package Overview
Dependencies
Maintainers
2
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lhci/server - npm Package Compare versions

Comparing version 0.2.0 to 0.2.1-alpha.0

dist/build-view.2013fce7.css

6

package.json
{
"name": "@lhci/server",
"main": "./src/server.js",
"version": "0.2.0",
"version": "0.2.1-alpha.0",
"license": "Apache-2.0",

@@ -20,3 +20,3 @@ "repository": {

"dependencies": {
"@lhci/utils": "0.2.0",
"@lhci/utils": "0.2.1-alpha.0",
"body-parser": "^1.18.3",

@@ -41,3 +41,3 @@ "compression": "^1.7.4",

},
"gitHead": "2f0fb8e52eab3d73500a9b327c03c2fb48154b93"
"gitHead": "926eb335f3acfd4851a19910854dbd098d5fea28"
}

@@ -28,2 +28,4 @@ /**

runAt: {type: Sequelize.DATE()}, // should mostly be equal to createdAt but modifiable by the consumer
committedAt: {type: Sequelize.DATE()},
ancestorCommittedAt: {type: Sequelize.DATE()},
};

@@ -30,0 +32,0 @@

@@ -18,2 +18,3 @@ /**

const {errorMiddleware} = require('./api/express-utils.js');
const version = require('../package.json').version;

@@ -42,2 +43,3 @@ const DIST_FOLDER = path.join(__dirname, '../dist');

app.use('/version', (_, res) => res.send(version));
app.use('/v1/projects', createProjectsRouter({storageMethod}));

@@ -44,0 +46,0 @@ app.use('/app', express.static(DIST_FOLDER));

@@ -7,26 +7,32 @@ /**

import {h} from 'preact';
import {h, Fragment} from 'preact';
import clsx from 'clsx';
import './dropdown.css';
/** @param {{options: Array<{value: string, label: string}>, value: string, setValue(v: string): void, className?: string, title?: string}} props */
/** @param {{options: Array<{value: string, label: string}>, value: string, setValue(v: string): void, className?: string, title?: string, label?: string}} props */
export const Dropdown = props => {
const {options, value, setValue, className, title} = props;
const {options, value, setValue, className, title, label} = props;
return (
<div className={className} style={{position: 'relative'}} data-tooltip={title}>
<select
className={clsx('dropdown')}
onChange={evt => {
if (!(evt.target instanceof HTMLSelectElement)) return;
setValue(evt.target.value);
}}
>
{options.map(option => {
return (
<option key={option.value} value={option.value} selected={option.value === value}>
{option.label}
</option>
);
})}
</select>
<div
className={clsx('dropdown', className)}
style={{position: 'relative'}}
data-tooltip={title}
>
<label>
{label ? <span className="dropdown__label">{label}</span> : <Fragment />}
<select
onChange={evt => {
if (!(evt.target instanceof HTMLSelectElement)) return;
setValue(evt.target.value);
}}
>
{options.map(option => {
return (
<option key={option.value} value={option.value} selected={option.value === value}>
{option.label}
</option>
);
})}
</select>
</label>
<div className="dropdown__chevron" />

@@ -33,0 +39,0 @@ </div>

@@ -7,9 +7,9 @@ /**

import {h} from 'preact';
import {h, Fragment} from 'preact';
import clsx from 'clsx';
import './pill.css';
/** @param {{children: string|JSX.Element|JSX.Element[], className?: string, variant?: 'base'|'compare'|'master-branch'|'dev-branch', onClick?: () => void, solid?: boolean}} props */
/** @param {{children: string|JSX.Element|JSX.Element[], className?: string, variant?: 'base'|'compare'|'master-branch'|'dev-branch', onClick?: () => void, solid?: boolean, avatar?: Pick<LHCI.ServerCommand.Build, 'avatarUrl'|'author'>}} props */
export const Pill = props => {
const {children, variant = 'base'} = props;
const {children, avatar, variant = 'base'} = props;
return (

@@ -23,2 +23,12 @@ <div

>
{avatar ? (
<img
className="pill__avatar"
title={avatar.author}
alt={avatar.author}
src={avatar.avatarUrl}
/>
) : (
<Fragment />
)}
<span>{children}</span>

@@ -25,0 +35,0 @@ </div>

@@ -86,3 +86,4 @@ /**

export function useProjectBuilds(projectId) {
return useApiData('getBuilds', [projectId]);
const options = useMemo(() => ({limit: 20}), []);
return useApiData('getBuilds', [projectId, options]);
}

@@ -89,0 +90,0 @@

@@ -8,2 +8,3 @@ /**

import {h, Fragment} from 'preact';
import clsx from 'clsx';
import * as _ from '@lhci/utils/src/lodash.js';

@@ -35,15 +36,17 @@ import './build-hash-selector.css';

return (
<li className="build-hash-selector__label-li">
<span className="build-hash-selector__selection" />
<GitViz
branch={props.branch}
withNode={false}
withDevBranchArc={false}
withDevLine={props.withDevLine}
/>
<span
className={`build-hash-selector__branch-label build-hash-selector__branch-label--${variant}`}
>
{props.branch}
</span>
<li className="build-hash-selector__item build-hash-selector__label-li">
<div className="container">
<span className="build-hash-selector__selection" />
<GitViz
branch={props.branch}
withNode={false}
withDevBranchArc={false}
withDevLine={props.withDevLine}
/>
<span
className={`build-hash-selector__branch-label build-hash-selector__branch-label--${variant}`}
>
{props.branch}
</span>
</div>
</li>

@@ -58,2 +61,4 @@ );

const isBaseBranch = build.id === (baseBuild && baseBuild.id);
const isSelected =
(selector === 'base' && isBaseBranch) || (selector === 'compare' && isCompareBranch);
const variant = build.branch === 'master' ? 'master-branch' : 'dev-branch';

@@ -63,2 +68,5 @@

<li
className={clsx('build-hash-selector__item', {
'build-hash-selector__item--selected': isSelected,
})}
key={build.id}

@@ -82,28 +90,34 @@ onClick={() => {

>
<span className="build-hash-selector__selection">
{isCompareBranch && (
<Pill variant="compare" solid>
compare
</Pill>
)}
{isBaseBranch && (
<Pill variant="base" solid>
base
</Pill>
)}
</span>
<GitViz
branch={build.branch}
withNode
withDevBranchArc={props.withDevBranchArc}
withDevLine={props.withDevLine}
/>
<Pill variant={variant}>
<span className="build-hash-selector__hash">{build.hash.slice(0, 8)}</span>
</Pill>{' '}
<img className="build-hash-selector__avatar" alt={build.author} src={build.avatarUrl} />
<span className="build-hash-selector__commit">{build.commitMessage}</span>
<span className="build-hash-selector__links">
{build.externalBuildUrl ? <a href={build.externalBuildUrl}>View Build</a> : <Fragment />}
</span>
<div className="container">
<span className="build-hash-selector__selection">
{isCompareBranch && selector === 'base' && (
<Pill variant="compare" solid>
compare
</Pill>
)}
{isBaseBranch && selector === 'compare' && (
<Pill variant="base" solid>
base
</Pill>
)}
</span>
<GitViz
branch={build.branch}
withNode
withDevBranchArc={props.withDevBranchArc}
withDevLine={props.withDevLine}
/>
<Pill variant={variant} avatar={build}>
<span className="build-hash-selector__hash">{build.hash.slice(0, 8)}</span>
</Pill>{' '}
<span className="build-hash-selector__commit">{build.commitMessage}</span>
<span className="build-hash-selector__links">
{build.externalBuildUrl ? <a href={build.externalBuildUrl}>View Build</a> : <Fragment />}
</span>
</div>
{isSelected ? (
<i className="material-icons build-hash-selector__selector-selection">check</i>
) : (
<Fragment />
)}
</li>

@@ -151,25 +165,23 @@ );

return (
<div className="container">
<ul className={`build-hash-selector__list build-hash-selector--${props.selector}`}>
{builds.map((build, index) => (
<Fragment key={build.id}>
<BuildLineItem
key={build.id}
build={build}
compareBuild={props.build}
baseBuild={props.ancestorBuild}
selector={props.selector}
withDevLine={index <= indexOfFirstDev && props.build.branch !== 'master'}
withDevBranchArc={index === indexOfFirstDev + 1}
/>
{index === indexOfFirstDev && build.branch !== 'master' ? (
<LabelLineItem branch={build.branch} withDevLine={true} />
) : null}
{index === builds.length - 1 ? (
<LabelLineItem branch={build.branch} withDevLine={false} />
) : null}
</Fragment>
))}
</ul>
</div>
<ul className={`build-hash-selector__list build-hash-selector--${props.selector}`}>
{builds.map((build, index) => (
<Fragment key={build.id}>
<BuildLineItem
key={build.id}
build={build}
compareBuild={props.build}
baseBuild={props.ancestorBuild}
selector={props.selector}
withDevLine={index <= indexOfFirstDev && props.build.branch !== 'master'}
withDevBranchArc={index === indexOfFirstDev + 1}
/>
{index === indexOfFirstDev && build.branch !== 'master' ? (
<LabelLineItem branch={build.branch} withDevLine={true} />
) : null}
{index === builds.length - 1 ? (
<LabelLineItem branch={build.branch} withDevLine={false} />
) : null}
</Fragment>
))}
</ul>
);

@@ -176,0 +188,0 @@ };

@@ -29,3 +29,3 @@ /**

/**
* @param {{build: LHCI.ServerCommand.Build | null, variant: 'base'|'compare', isOpen?: boolean, onClick?: () => void}} props
* @param {{build: LHCI.ServerCommand.Build | null, variant: 'base'|'compare', isOpen?: boolean, isDimmed?: boolean, onClick?: () => void}} props
*/

@@ -37,2 +37,3 @@ export const BuildSelectorPill = props => {

'build-selector-pill--open': props.isOpen,
'build-selector-pill--dim': props.isDimmed,
})}

@@ -39,0 +40,0 @@ onClick={props.onClick}

@@ -9,3 +9,2 @@ /**

import './build-view-options.css';
import {Dropdown} from '../../components/dropdown';
import {LhrViewerLink} from '../../components/lhr-viewer-link';

@@ -16,3 +15,3 @@

/** @param {{compareLhr: LH.Result, baseLhr?: LH.Result, percentAbsoluteDeltaThreshold: number, setPercentAbsoluteDeltaThreshold: (x: number) => void}} props */
/** @param {{compareLhr: LH.Result, baseLhr?: LH.Result}} props */
export const BuildViewOptions = props => {

@@ -33,19 +32,4 @@ return (

</LhrViewerLink>
<Dropdown
className="build-view-options__dropdown"
title="Set minimum delta threshold (% change)"
value={props.percentAbsoluteDeltaThreshold.toString()}
setValue={value => {
props.setPercentAbsoluteDeltaThreshold(Number(value));
}}
options={[
{value: '0', label: '0%'},
{value: '0.05', label: '5%'},
{value: '0.1', label: '10%'},
{value: '0.15', label: '15%'},
{value: '0.25', label: '25%'},
]}
/>
</div>
);
};

@@ -9,52 +9,78 @@ /**

import {Paper} from '../../components/paper';
import './build-view-warnings.css';
import {LhrViewerLink} from '../../components/lhr-viewer-link';
/** @param {{build: LHCI.ServerCommand.Build, baseBuild: LHCI.ServerCommand.Build | null, baseLhr?: LH.Result, hasBaseOverride: boolean}} props */
/** @param {{build: LHCI.ServerCommand.Build, baseBuild: LHCI.ServerCommand.Build | null, auditGroups: Array<any>, lhr: LH.Result, baseLhr?: LH.Result, hasBaseOverride: boolean}} props */
export const BuildViewWarnings = props => {
const {build, baseBuild, baseLhr, hasBaseOverride} = props;
/** @type {Array<string>} */
const warningMessages = [];
const {build, baseBuild, baseLhr, auditGroups, hasBaseOverride} = props;
const lhrLinkEl = (
<Fragment>
<LhrViewerLink className="build-view-empty__lhr-link" lhr={props.lhr}>
jump straight to the Lighthouse report.
</LhrViewerLink>
</Fragment>
);
if (!baseBuild) {
warningMessages.push('No base build could be found for this commit.');
return (
<Paper className="build-view__warning">
<i className="material-icons">sentiment_very_dissatisfied</i>
<div>
Oops, no base build could be found for this commit. Manually select a base build above, or{' '}
{lhrLinkEl}
</div>
</Paper>
);
}
if (baseBuild && build.hash === baseBuild.hash) {
warningMessages.push(
[
'This base build is the same commit as the compare.',
'Select a different base build to explore differences.',
].join(' ')
if (build.hash === baseBuild.hash) {
return (
<Paper className="build-view__warning">
<i className="material-icons">sentiment_very_dissatisfied</i>
<div>
Oops, this base build is the same commit as the compare. Select a different base build to
explore differences, or {lhrLinkEl}
</div>
</Paper>
);
}
if (baseBuild && !baseLhr) {
warningMessages.push('This base build is missing a run for this URL.');
if (!baseLhr) {
return (
<Paper className="build-view__warning">
<i className="material-icons">sentiment_very_dissatisfied</i>
<div>
Oops, this base build is missing a run for this URL. Select a different URL to explore
differences, or {lhrLinkEl}
</div>
</Paper>
);
}
if (
baseBuild &&
baseBuild.hash !== build.ancestorHash &&
!warningMessages.length &&
!hasBaseOverride
) {
warningMessages.push(
[
'This base build is not the target ancestor of the compare.',
'Differences may not be due to this specific commit.',
].join(' ')
if (baseBuild.hash !== build.ancestorHash && !hasBaseOverride) {
return (
<Paper className="build-view__warning">
<i className="material-icons">warning</i>
<div>
This base build is not the exact ancestor of the compare. Differences may not be due to
this specific commit.
</div>
</Paper>
);
}
return (
<Fragment>
{warningMessages.map(message => {
return (
<Paper className="build-view__warning" key={message}>
<i className="material-icons">warning</i>
<div>{message}</div>
</Paper>
);
})}
</Fragment>
);
if (baseLhr && !auditGroups.length) {
return (
<Paper className="build-view__warning">
<i className="material-icons">sentiment_satisified_alt</i>
<div>
Woah, no differences found! Switch base builds to explore other differences, or{' '}
{lhrLinkEl}
</div>
</Paper>
);
}
return <Fragment />;
};

@@ -30,3 +30,2 @@ /**

import {findAuditDiffs, getDiffSeverity} from '@lhci/utils/src/audit-diff-finder';
import {BuildViewEmpty} from './build-view-empty';
import {route} from 'preact-router';

@@ -92,3 +91,3 @@ import {BuildViewOptions} from './build-view-options';

/** @param {{selectedUrl: string, build: LHCI.ServerCommand.Build | null, lhr?: LH.Result, baseLhr?: LH.Result, urls: Array<string>}} props */
/** @param {{selectedUrl: string, selectedAuditId?: string | null, build: LHCI.ServerCommand.Build | null, lhr?: LH.Result, baseLhr?: LH.Result, urls: Array<string>, percentAbsoluteDeltaThreshold: number, setPercentAbsoluteDeltaThreshold: (x: number) => void}} props */
const BuildViewScoreAndUrl = props => {

@@ -98,14 +97,29 @@ return (

<div className="container">
<Dropdown
title="Comparison URL"
className="build-view__url-dropdown"
value={props.selectedUrl}
setValue={url => {
const to = new URL(window.location.href);
to.searchParams.set('compareUrl', url);
route(`${to.pathname}${to.search}`);
}}
options={props.urls.map(url => ({value: url, label: url}))}
/>
<BuildScoreComparison {...props} />
<div className="build-view__dropdowns">
<Dropdown
label="URL"
value={props.selectedUrl}
setValue={url => {
const to = new URL(window.location.href);
to.searchParams.set('compareUrl', url);
route(`${to.pathname}${to.search}`);
}}
options={props.urls.map(url => ({value: url, label: url}))}
/>
<Dropdown
label="Threshold"
value={props.percentAbsoluteDeltaThreshold.toString()}
setValue={value => {
props.setPercentAbsoluteDeltaThreshold(Number(value));
}}
options={[
{value: '0', label: '0%'},
{value: '0.05', label: '5%'},
{value: '0.1', label: '10%'},
{value: '0.15', label: '15%'},
{value: '0.25', label: '25%'},
]}
/>
</div>
{props.selectedAuditId ? <Fragment /> : <BuildScoreComparison {...props} />}
</div>

@@ -191,13 +205,6 @@ </div>

<Fragment>
{openBuildHash === null ? (
<Fragment />
) : (
<div className={`build-selector-header build-selector-header--${openBuildHash}`}>
<i className="material-icons">arrow_back</i>
<span>Select {_.startCase(openBuildHash)}</span>
</div>
)}
<BuildSelectorPill
build={props.ancestorBuild}
variant="base"
isDimmed={openBuildHash === 'compare'}
isOpen={openBuildHash === 'base'}

@@ -209,2 +216,3 @@ onClick={() => setOpenBuild(openBuildHash === 'base' ? null : 'base')}

variant="compare"
isDimmed={openBuildHash === 'base'}
isOpen={openBuildHash === 'compare'}

@@ -240,16 +248,17 @@ onClick={() => setOpenBuild(openBuildHash === 'compare' ? null : 'compare')}

>
{selectedAuditId ? (
<Fragment />
) : (
<BuildViewScoreAndUrl
build={props.build}
lhr={lhr}
baseLhr={baseLhr}
selectedUrl={selectedUrl}
urls={availableUrls}
/>
)}
<BuildViewScoreAndUrl
build={props.build}
lhr={lhr}
baseLhr={baseLhr}
selectedUrl={selectedUrl}
selectedAuditId={selectedAuditId}
urls={availableUrls}
percentAbsoluteDeltaThreshold={percentAbsoluteDeltaThreshold}
setPercentAbsoluteDeltaThreshold={setDiffThreshold}
/>
<div className="container">
<BuildViewWarnings
lhr={lhr}
build={props.build}
auditGroups={auditGroups}
baseBuild={props.ancestorBuild}

@@ -266,8 +275,3 @@ baseLhr={baseLhr}

<BuildViewLegend />
<BuildViewOptions
compareLhr={lhr}
baseLhr={baseLhr}
percentAbsoluteDeltaThreshold={percentAbsoluteDeltaThreshold}
setPercentAbsoluteDeltaThreshold={setDiffThreshold}
/>
<BuildViewOptions compareLhr={lhr} baseLhr={baseLhr} />
</div>

@@ -284,3 +288,3 @@ )}

) : (
<BuildViewEmpty lhr={lhr} />
<Fragment />
)}

@@ -287,0 +291,0 @@ </div>

@@ -18,2 +18,3 @@ /**

import './project-dashboard.css';
import {Pill} from '../../components/pill';

@@ -35,4 +36,4 @@ /** @param {{project: LHCI.ServerCommand.Project, builds: Array<LHCI.ServerCommand.Build>, runUrl?: string, branch?: string}} props */

>
<td className="build-list__avatar" data-tooltip={build.author}>
<img src={build.avatarUrl} alt={build.author} />
<td className="build-list__hash" data-tooltip={build.author}>
<Pill avatar={build}>{build.hash.slice(0, 8)}</Pill>
</td>

@@ -46,3 +47,2 @@ <td className="build-list__commit">{build.commitMessage}</td>

</td>
<td className="build-list__hash">{build.hash.slice(0, 8)}</td>
<td className="build-list__date">

@@ -49,0 +49,0 @@ {new Date(build.runAt).toDateString().replace(/\w+ (.*) \d{4}/, '$1')}{' '}

@@ -16,2 +16,4 @@ /**

import './project-graphs.css';
import {Dropdown} from '../../components/dropdown';
import {route} from 'preact-router';

@@ -25,3 +27,3 @@ const COLORS = ['#4587f4', '#f44587', '#87f445'];

/** @param {{statistics?: Array<StatisticWithBuild>}} props */
/** @param {{statistics?: Array<StatisticWithBuild>, builds: Array<LHCI.ServerCommand.Build>, branch: string}} props */
const Legend = props => {

@@ -31,2 +33,3 @@ if (!props.statistics) return null;

const urls = computeURLsFromStats(props.statistics);
const branches = Array.from(new Set(props.builds.map(build => build.branch)));
return (

@@ -42,2 +45,12 @@ <div className="dashboard-graphs__legend">

})}
<Dropdown
label="Branch"
options={branches.map(branch => ({value: branch, label: branch}))}
value={props.branch}
setValue={value => {
const url = new URL(window.location.href);
url.searchParams.set('branch', value);
route(`${url.pathname}${url.search}`);
}}
/>
</div>

@@ -56,2 +69,6 @@ );

render={allStats => {
if (allStats.length === 0) {
return <Paper className="dashboard-graph">No data to display</Paper>;
}
const urls = computeURLsFromStats(allStats);

@@ -153,3 +170,11 @@ const matchingStats = allStats

const {project, builds, branch = 'master'} = props;
const buildIds = useMemo(() => builds.map(build => build.id), builds);
const buildIds = useMemo(
() =>
builds
.filter(build => build.branch === branch)
.sort((a, b) => new Date(b.runAt).getTime() - new Date(a.runAt).getTime())
.map(build => build.id)
.slice(0, 8),
[builds, branch]
);
const [loadingState, stats] = useBuildStatistics(project.id, buildIds);

@@ -165,3 +190,3 @@ const statsWithBuildsUnfiltered = augmentStatsWithBuilds(stats, builds);

<div className="dashboard-graphs">
<Legend statistics={statsWithBuilds} />
<Legend statistics={statsWithBuilds} builds={builds} branch={branch} />
<StatisticPlot

@@ -168,0 +193,0 @@ title="Performance"

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc