Full Radar grid with chart

This commit is contained in:
Jarosław Marek
2021-04-28 23:25:52 +12:00
parent ad4c8475f5
commit 13ba3120c3
27 changed files with 493 additions and 369 deletions

View File

@@ -67,6 +67,7 @@
"react-dom": "^16.0.0", "react-dom": "^16.0.0",
"react-faux-dom": "^4.5.0", "react-faux-dom": "^4.5.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-tooltip": "^4.2.18",
"resolve": "1.15.0", "resolve": "1.15.0",
"resolve-url-loader": "3.1.2", "resolve-url-loader": "3.1.2",
"sass-loader": "8.0.2", "sass-loader": "8.0.2",

View File

@@ -1,7 +1,8 @@
// TODO remove faux-dom and start using the React hook approach
import ReactFauxDOM from 'react-faux-dom'; import ReactFauxDOM from 'react-faux-dom';
import * as d3 from 'd3'; import * as d3 from "d3";
export const LeftAxis = ({ scale }) => { export const YAxis = ({ scale }) => {
const el = ReactFauxDOM.createElement('g'); const el = ReactFauxDOM.createElement('g');
const axisGenerator = d3.axisLeft(scale).ticks(6); const axisGenerator = d3.axisLeft(scale).ticks(6);
@@ -14,7 +15,7 @@ export const LeftAxis = ({ scale }) => {
return el.toReact(); return el.toReact();
}; };
export const BottomAxis = ({ scale }) => { export const XAxis = ({ scale }) => {
const el = ReactFauxDOM.createElement('g'); const el = ReactFauxDOM.createElement('g');
const axisGenerator = d3.axisBottom(scale).ticks(6); const axisGenerator = d3.axisBottom(scale).ticks(6);

View File

@@ -1,66 +1,112 @@
import ReactFauxDOM from 'react-faux-dom'; import React from 'react';
import * as d3 from "d3"; import { quadrantsMap, ringsMap, chartConfig, blipFlags } from '../..//config';
import { quadrantsMap, ringsMap } from '../../config'; import { NewBlip, ChangedBlip, DefaultBlip } from './BlipShapes';
/*
See https://medium.com/create-code/build-a-radar-diagram-with-d3-js-9db6458a9248
for a good explanation of formulas used to calculate various things in this component
*/
const generateCoordinates = (enrichedBlip, xScale, yScale) => { const generateCoordinates = (enrichedBlip, xScale, yScale) => {
const pi = Math.PI; const pi = Math.PI,
// radian between 5 and 85 ringRadius = chartConfig.ringsAttributes[enrichedBlip.ringPosition - 1].radius,
const randomDegree = ((Math.random() * 80 + 5) * pi) / 180; previousRingRadius = enrichedBlip.ringPosition == 1 ? 0 : chartConfig.ringsAttributes[enrichedBlip.ringPosition - 2].radius,
const radius = enrichedBlip.ringPosition - 0.2; ringPadding = 0.6;
const r = Math.random() * 0.6 + (radius - 0.6);
// multiples of PI/2 // radian between 0 and 90 degrees
const shift = pi * [1, 4, 3, 2][enrichedBlip.quadrantPosition - 1] / 2; const randomDegree = ((Math.random() * 90) * pi) / 180;
// random distance from the centre of the radar, but within given ring. Also, with some "padding" so the points don't touch ring borders.
const radius = randomBetween(previousRingRadius + ringPadding, ringRadius - ringPadding);
/*
Multiples of PI/2. To apply the calculated position to the specific quadrant.
Order here is counter-clockwise and starts at the top left, so we need to "invert" quadrant positions
*/
const shift = pi * [4, 3, 2, 1][enrichedBlip.quadrantPosition - 1] / 2;
return { return {
x: xScale(Math.cos(randomDegree + shift) * r), x: xScale(Math.cos(randomDegree + shift) * radius),
y: yScale(Math.sin(randomDegree + shift) * r) y: yScale(Math.sin(randomDegree + shift) * radius)
}; };
}; };
const distanceBetweenPoints = (point1, point2) => { const randomBetween = (min, max) => {
return Math.random() * (max - min) + min;
};
const distanceBetween = (point1, point2) => {
const a = point2.x - point1.x; const a = point2.x - point1.x;
const b = point2.y - point1.y; const b = point2.y - point1.y;
return Math.sqrt((a * a) + (b * b)); return Math.sqrt((a * a) + (b * b));
}; };
export default function BlipPoints({blips, xScale, yScale, navigate}) {
export default function BlipPoints({blips, xScale, yScale}) {
const enrichedBlips = blips.reduce((list, blip) => { const enrichedBlips = blips.reduce((list, blip) => {
if (!blip.ring || !blip.quadrant) { if (!blip.ring || !blip.quadrant) {
// skip the blip if it doesn't have a ring or quadrant assigned // skip the blip if it doesn't have a ring or quadrant assigned
return list; return list;
} }
blip.ringPosition = ringsMap[blip.ring].position; let enrichedBlip = { ...blip,
blip.quadrantPosition = quadrantsMap[blip.quadrant].position; ringPosition: ringsMap[blip.ring].position,
blip.colour = quadrantsMap[blip.quadrant].colour; quadrantPosition: quadrantsMap[blip.quadrant].position,
colour: quadrantsMap[blip.quadrant].colour,
txtColour: quadrantsMap[blip.quadrant].txtColour
};
let point; let point;
let counter = 1; let counter = 1;
do { do {
point = generateCoordinates(blip, xScale, yScale); point = generateCoordinates(enrichedBlip, xScale, yScale);
counter++; counter++;
// generate position of the new blip until it has a satisfactory distance to every other blip /*
// this feels pretty inefficient, but good enough for now Generate position of the new blip until it has a satisfactory distance to every other blip (so that they don't touch each other)
} while (list.some(item => distanceBetweenPoints(point, item) < 8) || counter > 100); and quadrant borders (so that they don't overlap quadrants)
This feels pretty inefficient, but good enough for now.
*/
} while (counter < 100
&& (Math.abs(point.x - xScale(0)) < 15
|| Math.abs(point.y - yScale(0)) < 15
|| list.some(item => distanceBetween(point, item) < chartConfig.blipSize + chartConfig.blipSize / 2)
));
blip.x = point.x; enrichedBlip.x = point.x;
blip.y = point.y; enrichedBlip.y = point.y;
list.push(blip); list.push(enrichedBlip);
return list; return list;
}, []); }, []);
const el = ReactFauxDOM.createElement('g'); const handleClick = (pageName, event) => {
event.preventDefault();
navigate(pageName);
}
d3.select(el) const renderBlip = (blip, index) => {
.attr('class', 'circles') const props = {
.selectAll('circle') blip,
.data(enrichedBlips) className: 'blip',
.enter().append('circle') fill: blip.colour,
.attr('fill', blip => blip.colour) 'data-background-color': blip.colour,
.attr('r', 3) 'data-text-color': blip.txtColour,
.attr('data-value', blip => blip.title) 'data-tip': blip.title,
.attr('cx', blip => blip.x) onClick: handleClick.bind(this, `${blip.quadrant}/${blip.name}`),
.attr('cy', blip => blip.y) key: index
}
switch (blip.flag) {
case blipFlags.new.name:
return <NewBlip {...props} />;
case blipFlags.changed.name:
return <ChangedBlip {...props} />;
default:
return <DefaultBlip {...props} />;
}
}
return el.toReact(); return (
} <g className="blips">
{enrichedBlips.map((blip, index) => (
renderBlip(blip, index)
))}
</g>
);
};

View File

@@ -0,0 +1,48 @@
import React from 'react';
import { chartConfig } from '../../config';
export const ChangedBlip = ({blip, ...props}) => {
const centeredX = blip.x - chartConfig.blipSize/2,
centeredY = blip.y - chartConfig.blipSize/2;
return (
<rect
transform={`rotate(-45 ${centeredX} ${centeredY})`}
x={centeredX}
y={centeredY}
width={chartConfig.blipSize}
height={chartConfig.blipSize}
rx="3"
{...props}
/>
);
};
export const NewBlip = ({blip, ...props}) => {
const centeredX = blip.x - chartConfig.blipSize/2,
centeredY = blip.y - chartConfig.blipSize/2;
/*
The below is a predefined path of a triangle with rounded corners.
I didn't find any more human friendly way of doing this as all examples I found have tons of lines of code
e.g. https://observablehq.com/@perlmonger42/interactive-rounded-corners-on-svg-polygons-using-d3-js
*/
return (
<path
transform={`translate(${centeredX}, ${centeredY})`}
d="M.247 10.212l5.02-8.697a2 2 0 013.465 0l5.021 8.697a2 2 0 01-1.732 3H1.98a2 2 0 01-1.732-3z"
{...props}
/>
);
};
export const DefaultBlip = ({blip, ...props}) => {
return (
<circle
r={chartConfig.blipSize / 2}
cx={blip.x}
cy={blip.y}
{...props}
/>
);
};

View File

@@ -2,45 +2,34 @@ import React from 'react';
import * as d3 from 'd3'; import * as d3 from 'd3';
import { chartConfig } from '../../config'; import { chartConfig } from '../../config';
const size = chartConfig.canvasSize / 2; const arcPath = (quadrantPosition, ringPosition, xScale) => {
const startAngle = (quadrantPosition - 1) * Math.PI / 2,
endAngle = quadrantPosition * Math.PI / 2,
arcAttrs = chartConfig.ringsAttributes[ringPosition - 1],
ringRadiusPx = xScale(arcAttrs.radius) - xScale(0),
arc = d3.arc();
const arcPath = (quadrantPosition, ringPosition) => {
// order from the centre outwards
const arcAttributes = [
{radius: size / 4, width: 6},
{radius: size / 2, width: 4},
{radius: (size / 4 * 3), width: 2},
{radius: size, width: 2}
]
const startAngle = quadrantPosition == 1 ?
3 * Math.PI / 2
: (quadrantPosition - 2) * Math.PI / 2
const endAngle = quadrantPosition == 1 ?
4 * Math.PI / 2
: (quadrantPosition -1) * Math.PI / 2
const arcAttrs = arcAttributes[ringPosition - 1];
const arc = d3.arc();
return arc({ return arc({
innerRadius: arcAttrs.radius + (arcAttrs.width / 2), innerRadius: ringRadiusPx - arcAttrs.arcWidth,
outerRadius: arcAttrs.radius - (arcAttrs.width / 2), outerRadius: ringRadiusPx,
startAngle, startAngle,
endAngle endAngle
}); });
} }
export default function QuadrantRings ({ quadrant }) { export default function QuadrantRings ({ quadrant, xScale}) {
// order from top left clockwise // order from top-right clockwise
const gradientAttributes = [ const gradientAttributes = [
{x: 0, y: 0, cx: 1, cy: 1, r: 1}, {x: xScale(0), y: 0, cx: 0, cy: 1, r: 1},
{x: size, y: 0, cx: 0, cy: 1, r: 1}, {x: xScale(0), y: xScale(0), cx: 0, cy: 0, r: 1},
{x: size, y: size, cx: 0, cy: 0, r: 1}, {x: 0, y: xScale(0), cx: 1, cy: 0, r: 1},
{x: 0, y: size, cx: 1, cy: 0, r: 1} {x: 0, y: 0, cx: 1, cy: 1, r: 1}
]; ];
const gradientId = `${quadrant.position}-radial-gradient`; const gradientId = `${quadrant.position}-radial-gradient`,
quadrantSize = chartConfig.size / 2;
return ( return (
<g> <g className="quadrant-ring">
{/* Definition of the quadrant gradient */} {/* Definition of the quadrant gradient */}
<defs> <defs>
<radialGradient id={gradientId} {...gradientAttributes[quadrant.position - 1]}> <radialGradient id={gradientId} {...gradientAttributes[quadrant.position - 1]}>
@@ -51,8 +40,8 @@ export default function QuadrantRings ({ quadrant }) {
{/* Gradient background area */} {/* Gradient background area */}
<rect <rect
width={size} width={quadrantSize}
height={size} height={quadrantSize}
x={gradientAttributes[quadrant.position - 1].x} x={gradientAttributes[quadrant.position - 1].x}
y={gradientAttributes[quadrant.position - 1].y} y={gradientAttributes[quadrant.position - 1].y}
fill={`url(#${gradientId})`} fill={`url(#${gradientId})`}
@@ -64,8 +53,8 @@ export default function QuadrantRings ({ quadrant }) {
<path <path
key={index} key={index}
fill={quadrant.colour} fill={quadrant.colour}
d={arcPath(quadrant.position, ringPosition)} d={arcPath(quadrant.position, ringPosition, xScale)}
style={{transform: `translate(${size}px, ${size}px)`}} style={{transform: `translate(${quadrantSize}px, ${quadrantSize}px)`}}
/> />
))} ))}

View File

@@ -1,23 +1,28 @@
import React from 'react'; import React from 'react';
import * as d3 from "d3"; import * as d3 from "d3";
import './chart.scss'; import ReactTooltip from 'react-tooltip';
import { blipFlags, chartConfig, quadrantsMap, ringsMap } from '../../config'; import { chartConfig, quadrantsMap, ringsMap } from '../../config';
import { LeftAxis, BottomAxis } from './Axes'; import { YAxis, XAxis } from './Axes';
import QuadrantRings from './QuadrantRings'; import QuadrantRings from './QuadrantRings';
import BlipPoints from './BlipPoints'; import BlipPoints from './BlipPoints';
const RingLabel = ({ring}) => { import './chart.scss';
const middlePoint = chartConfig.canvasSize / 2;
const shift = (ring.position - 1) * chartConfig.canvasSize / 8 + chartConfig.canvasSize / 16; const RingLabel = ({ring, xScale, yScale}) => {
const ringRadius = chartConfig.ringsAttributes[ring.position - 1].radius,
previousRingRadius = ring.position == 1 ? 0 : chartConfig.ringsAttributes[ring.position - 2].radius,
// middle point in between two ring arcs
distanceFromCentre = previousRingRadius + (ringRadius - previousRingRadius) / 2;
return ( return (
<g> <g className="ring-label">
{/* Right hand-side label */} {/* Right hand-side label */}
<text x={middlePoint + shift} y={middlePoint} textAnchor="middle" dy=".35em"> <text x={xScale(distanceFromCentre)} y={yScale(0)} textAnchor="middle" dy=".35em">
{ring.displayName} {ring.displayName}
</text> </text>
{/* Left hand-side label */} {/* Left hand-side label */}
<text x={middlePoint - shift} y={middlePoint} textAnchor="middle" dy=".35em"> <text x={xScale(-distanceFromCentre)} y={yScale(0)} textAnchor="middle" dy=".35em">
{ring.displayName} {ring.displayName}
</text> </text>
</g> </g>
@@ -26,35 +31,33 @@ const RingLabel = ({ring}) => {
export default function RadarChart({ blips }) { export default function RadarChart({ blips }) {
const xScale = d3.scaleLinear() const xScale = d3.scaleLinear()
.domain([-4, 4]) .domain(chartConfig.scale)
.range([0, chartConfig.canvasSize]); .range([0, chartConfig.size]);
const yScale = d3.scaleLinear() const yScale = d3.scaleLinear()
.domain([-4, 4]) .domain(chartConfig.scale)
.range([chartConfig.canvasSize, 0]); .range([chartConfig.size, 0]);
return ( return (
<div className="chart"> <div className="chart" style={{maxWidth: `${chartConfig.size}px`}}>
<svg viewBox={`0 0 ${chartConfig.size} ${chartConfig.size}`}> <svg viewBox={`0 0 ${chartConfig.size} ${chartConfig.size}`}>
<g transform={`translate(${chartConfig.margin}, ${chartConfig.margin})`}> <g transform={`translate(${xScale(0)}, 0)`}>
<YAxis scale={yScale}/>
<g transform={`translate(${xScale.range()[1] / 2}, 0)`}>
<LeftAxis scale={yScale}/>
</g> </g>
<g transform={`translate(0, ${yScale.range()[0] / 2})`}> <g transform={`translate(0, ${yScale(0)})`}>
<BottomAxis scale={xScale}/> <XAxis scale={xScale}/>
</g> </g>
{Object.keys(quadrantsMap).map((id, index) => ( {Object.keys(quadrantsMap).map((id, index) => (
<QuadrantRings key={index} quadrant={quadrantsMap[id]} /> <QuadrantRings key={index} quadrant={quadrantsMap[id]} xScale={xScale} />
))} ))}
{Object.keys(ringsMap).map((id, index) => ( {Object.keys(ringsMap).map((id, index) => (
<RingLabel key={index} ring={ringsMap[id]} /> <RingLabel key={index} ring={ringsMap[id]} xScale={xScale} yScale={yScale} />
))} ))}
<BlipPoints blips={blips} xScale={xScale} yScale={yScale}/> <BlipPoints blips={blips} xScale={xScale} yScale={yScale}/>
</g>
</svg> </svg>
<ReactTooltip className="tooltip" offset={{top: -5}}/>
</div> </div>
); );
} }

View File

@@ -2,4 +2,15 @@
fill: white; fill: white;
font-size: 12px; font-size: 12px;
text-align: center; text-align: center;
position: relative;
margin: 0 auto;
}
.chart .blip:hover {
cursor: pointer;
}
.chart .tooltip {
padding: 5px 10px;
border-radius: 11px;
} }

View File

@@ -1,7 +1,7 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import Branding from '../Branding/Branding'; import Branding from '../Branding/Branding';
import Link from '../Link/Link'; import IconLink from '../IconLink/IconLink';
import LogoLink from '../LogoLink/LogoLink'; import LogoLink from '../LogoLink/LogoLink';
import Search from '../Search/Search'; import Search from '../Search/Search';
import { radarNameShort } from '../../config'; import { radarNameShort } from '../../config';
@@ -50,14 +50,10 @@ export default function Header({ pageName }: { pageName: string }) {
<Branding logoContent={<LogoLink small={smallLogo} />}> <Branding logoContent={<LogoLink small={smallLogo} />}>
<div className='nav'> <div className='nav'>
<div className='nav__item'> <div className='nav__item'>
<Link pageName='help-and-about-tech-radar' className='icon-link'> <IconLink pageName="help-and-about-tech-radar" icon="question" text={`How to Use ${radarNameShort}?`} />
<span className='icon icon--question icon-link__icon'/>How to Use {radarNameShort}?
</Link>
</div> </div>
<div className='nav__item'> <div className='nav__item'>
<Link pageName='overview' className='icon-link'> <IconLink pageName="overview" icon="overview" text="All Technologies" />
<span className='icon icon--overview icon-link__icon'/>Technologies Overview
</Link>
</div> </div>
<div className='nav__item'> <div className='nav__item'>
<button className='icon-link' onClick={handleOpenClick}> <button className='icon-link' onClick={handleOpenClick}>

View File

@@ -0,0 +1,11 @@
import React from 'react';
import Link from '../Link/Link';
export default function IconLink({icon, pageName, text}) {
return (
<Link className="icon-link" pageName={pageName}>
<span className={`icon icon--${icon} icon-link__icon`} />
{text}
</Link>
);
}

View File

@@ -3,7 +3,7 @@ import { formatRelease } from '../../date';
import { featuredOnly, Item } from '../../model'; import { featuredOnly, Item } from '../../model';
import HeroHeadline from '../HeroHeadline/HeroHeadline'; import HeroHeadline from '../HeroHeadline/HeroHeadline';
import QuadrantGrid from '../QuadrantGrid/QuadrantGrid'; import QuadrantGrid from '../QuadrantGrid/QuadrantGrid';
import RadarChart from '../Chart/RadarChart'; import RadarGrid from '../RadarGrid/RadarGrid';
import Fadeable from '../Fadeable/Fadeable'; import Fadeable from '../Fadeable/Fadeable';
import SetTitle from '../SetTitle'; import SetTitle from '../SetTitle';
import { radarName, radarNameShort } from '../../config'; import { radarName, radarNameShort } from '../../config';
@@ -25,8 +25,10 @@ export default function PageIndex({ leaving, onLeave, items, releases }: PageInd
<div className='headline-group'> <div className='headline-group'>
<HeroHeadline alt={`Version #${numberOfReleases}`}>{radarName}</HeroHeadline> <HeroHeadline alt={`Version #${numberOfReleases}`}>{radarName}</HeroHeadline>
</div> </div>
<RadarChart blips={featuredOnly(items)} /> <RadarGrid blips={featuredOnly(items)} />
{/*
<QuadrantGrid items={featuredOnly(items)} /> <QuadrantGrid items={featuredOnly(items)} />
*/}
<div className='publish-date'>Published {formatRelease(newestRelease)}</div> <div className='publish-date'>Published {formatRelease(newestRelease)}</div>
</Fadeable> </Fadeable>
); );

View File

@@ -1,7 +1,7 @@
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import Badge from '../Badge/Badge'; import Badge from '../Badge/Badge';
import ItemList from '../ItemList/ItemList'; import ItemList from '../ItemList/ItemList';
import Link from '../Link/Link'; import IconLink from '../IconLink/IconLink';
import FooterEnd from '../FooterEnd/FooterEnd'; import FooterEnd from '../FooterEnd/FooterEnd';
import SetTitle from '../SetTitle'; import SetTitle from '../SetTitle';
import ItemRevisions from '../ItemRevisions/ItemRevisions'; import ItemRevisions from '../ItemRevisions/ItemRevisions';
@@ -11,7 +11,7 @@ import {
createAnimationRunner createAnimationRunner
} from '../../animation'; } from '../../animation';
import './item-page.scss'; import './item-page.scss';
import {translate} from '../../config'; import {quadrantsMap} from '../../config';
import {groupByQuadrants, Item} from '../../model'; import {groupByQuadrants, Item} from '../../model';
const getItem = (pageName: string, items: Item[]) => { const getItem = (pageName: string, items: Item[]) => {
@@ -191,7 +191,7 @@ export default function PageItem({pageName, items, leaving, onLeave}: PageItemPr
<div className='item-page__nav'> <div className='item-page__nav'>
<div className='item-page__nav__inner'> <div className='item-page__nav__inner'>
<div className='item-page__header' style={getAnimationState('navHeader')}> <div className='item-page__header' style={getAnimationState('navHeader')}>
<h3 className='headline'>{translate(item.quadrant)}</h3> <h3 className='headline'>{quadrantsMap[item.quadrant].displayName}</h3>
</div> </div>
<ItemList items={itemsInRing} activeItem={item} headerStyle={getAnimationState('navHeader')} <ItemList items={itemsInRing} activeItem={item} headerStyle={getAnimationState('navHeader')}
@@ -203,10 +203,7 @@ export default function PageItem({pageName, items, leaving, onLeave}: PageItemPr
</Badge> </Badge>
</div> </div>
<div className='split__right'> <div className='split__right'>
<Link className='icon-link' pageName={item.quadrant}> <IconLink pageName={item.quadrant} icon="pie" text="Quadrant Overview" />
<span className='icon icon--pie icon-link__icon'/>
Quadrant Overview
</Link>
</div> </div>
</div> </div>
</ItemList> </ItemList>

View File

@@ -1,12 +1,12 @@
import React from 'react'; import React from 'react';
import Badge from '../Badge/Badge'; import Badge from '../Badge/Badge';
import ItemList from '../ItemList/ItemList'; import ItemList from '../ItemList/ItemList';
import Link from '../Link/Link'; import IconLink from '../IconLink/IconLink';
import Fadeable from '../Fadeable/Fadeable'; import Fadeable from '../Fadeable/Fadeable';
import SetTitle from '../SetTitle'; import SetTitle from '../SetTitle';
import ItemRevisions from '../ItemRevisions/ItemRevisions'; import ItemRevisions from '../ItemRevisions/ItemRevisions';
import { translate } from '../../config'; import { quadrantsMap } from '../../config';
import { groupByQuadrants, Item } from '../../model'; import { groupByQuadrants, Item } from '../../model';
type PageItemMobileProps = { type PageItemMobileProps = {
@@ -40,7 +40,7 @@ export default function PageItemMobile({ pageName, items, leaving, onLeave }: Pa
<div className='mobile-item-page__header'> <div className='mobile-item-page__header'>
<div className='split'> <div className='split'>
<div className='split__left'> <div className='split__left'>
<h3 className='headline'>{translate(item.quadrant)}</h3> <h3 className='headline'>{quadrantsMap[item.quadrant].displayName}</h3>
<h1 className='hero-headline hero-headline--inverse'>{item.title}</h1> <h1 className='hero-headline hero-headline--inverse'>{item.title}</h1>
</div> </div>
<div className='split__right'> <div className='split__right'>
@@ -59,12 +59,10 @@ export default function PageItemMobile({ pageName, items, leaving, onLeave }: Pa
<ItemList items={itemsInRing} activeItem={item}> <ItemList items={itemsInRing} activeItem={item}>
<div className='split'> <div className='split'>
<div className='split__left'> <div className='split__left'>
<h3 className='headline'>{translate(item.quadrant)}</h3> <h3 className='headline'>{quadrantsMap[item.quadrant].displayName}</h3>
</div> </div>
<div className='split__right'> <div className='split__right'>
<Link className='icon-link' pageName={item.quadrant}> <IconLink pageName={item.quadrant} icon="pie" text="Zoom in" />
<span className='icon icon--pie icon-link__icon'></span>Zoom In
</Link>
</div> </div>
</div> </div>
</ItemList> </ItemList>

View File

@@ -8,7 +8,7 @@ import Fadeable from '../Fadeable/Fadeable';
import SetTitle from '../SetTitle'; import SetTitle from '../SetTitle';
import Flag from '../Flag/Flag'; import Flag from '../Flag/Flag';
import { groupByFirstLetter, Item } from '../../model'; import { groupByFirstLetter, Item } from '../../model';
import { translate, Ring } from '../../config'; import { quadrantsMap, Ring } from '../../config';
const containsSearchTerm = (text = '', term = '') => { const containsSearchTerm = (text = '', term = '') => {
// TODO search refinement // TODO search refinement
@@ -109,7 +109,7 @@ export default function PageOverview({ rings, search: searchProp, items, leaving
</div> </div>
<div className='split__right'> <div className='split__right'>
<div className='nav nav--relations'> <div className='nav nav--relations'>
<div className='nav__item'>{translate(item.quadrant)}</div> <div className='nav__item'>{quadrantsMap[item.quadrant].displayName}</div>
<div className='nav__item'> <div className='nav__item'>
<Badge type={item.ring}>{item.ring}</Badge> <Badge type={item.ring}>{item.ring}</Badge>
</div> </div>

View File

@@ -5,7 +5,7 @@ import QuadrantSection from '../QuadrantSection/QuadrantSection';
import Fadeable from '../Fadeable/Fadeable'; import Fadeable from '../Fadeable/Fadeable';
import SetTitle from '../SetTitle'; import SetTitle from '../SetTitle';
import { translate } from '../../config'; import { quadrantsMap } from '../../config';
import { featuredOnly, groupByQuadrants, Item } from '../../model'; import { featuredOnly, groupByQuadrants, Item } from '../../model';
type PageQuadrantProps = { type PageQuadrantProps = {
@@ -19,11 +19,11 @@ export default function PageQuadrant({ leaving, onLeave, pageName, items }: Page
const groups = groupByQuadrants(featuredOnly(items)); const groups = groupByQuadrants(featuredOnly(items));
return ( return (
<Fadeable leaving={leaving} onLeave={onLeave}> <Fadeable leaving={leaving} onLeave={onLeave}>
<SetTitle title={translate(pageName)} /> <SetTitle title={quadrantsMap[pageName].displayName} />
<HeadlineGroup> <HeadlineGroup>
<HeroHeadline>{translate(pageName)}</HeroHeadline> <HeroHeadline>{quadrantsMap[pageName].displayName}</HeroHeadline>
</HeadlineGroup> </HeadlineGroup>
<QuadrantSection groups={groups} quadrantName={pageName} big /> <QuadrantSection groups={groups} quadrantName={pageName} big showTitle={false} />
</Fadeable> </Fadeable>
); );
} }

View File

@@ -1,7 +1,8 @@
import React from 'react'; import React from 'react';
import { translate, rings, Ring, showEmptyRings } from '../../config'; import { rings, quadrantsMap, Ring, showEmptyRings } from '../../config';
import Badge from '../Badge/Badge'; import Badge from '../Badge/Badge';
import Link from '../Link/Link'; import Link from '../Link/Link';
import IconLink from '../IconLink/IconLink';
import ItemList from '../ItemList/ItemList'; import ItemList from '../ItemList/ItemList';
import Flag from '../Flag/Flag'; import Flag from '../Flag/Flag';
import { Group } from '../../model'; import { Group } from '../../model';
@@ -47,20 +48,19 @@ const renderRing = (ringName: Ring, quadrantName: string, groups: Group, big: bo
); );
}; };
export default function QuadrantSection({ quadrantName, groups, big = false }: { quadrantName: string; groups: Group; big?: boolean }) { export default function QuadrantSection({ quadrantName, groups, big = false, showTitle = true}: { quadrantName: string; groups: Group; big?: boolean; showTitle?: boolean }) {
return ( return (
<div className='quadrant-section'> <div className='quadrant-section'>
<div className='quadrant-section__header'> <div className='quadrant-section__header'>
<div className='split'> <div className='split'>
<div className='split__left'> {showTitle && (
<h4 className='headline'>{translate(quadrantName)}</h4> <div className="split__left">
<h4 className="headline">{quadrantsMap[quadrantName].displayName}</h4>
</div> </div>
)}
{!big && ( {!big && (
<div className='split__right'> <div className='split__right'>
<Link className='icon-link' pageName={`${quadrantName}`}> <IconLink pageName={quadrantName} icon="pie" text="Zoom In" />
<span className='icon icon--pie icon-link__icon' />
Zoom In
</Link>
</div> </div>
)} )}
</div> </div>

View File

@@ -0,0 +1,63 @@
import React from 'react';
import RadarChart from '../Chart/RadarChart';
import IconLink from '../IconLink/IconLink';
import { quadrantsMap } from '../../config';
import './radar-grid.scss';
const QuadrantLabel = ({quadrant}) => {
const stylesMap = [
{top: 0, right: 0},
{bottom: 0, right: 0},
{bottom: 0, left: 0},
{top: 0, left: 0},
]
return (
<div className="quadrant-label" style={stylesMap[quadrant.position - 1]}>
<div className="split">
<div className="split__left">
<small>Quadrant {quadrant.position}</small>
</div>
<div className="split__right">
<IconLink icon="pie" pageName={`${quadrant.id}`} text="Zoom In" />
</div>
</div>
<hr style={{borderColor: quadrant.colour}}/>
<h4 className="headline">{quadrant.displayName}</h4>
<div className="description">{quadrant.description}</div>
</div>
);
};
const Legend = () => {
return (
<div className="radar-legend">
<div className="wrapper">
<span className="icon icon--blip_new"></span>
New in this version
</div>
<div className="wrapper">
<span className="icon icon--blip_changed"></span>
Recently changed
</div>
<div className="wrapper">
<span className="icon icon--blip_default"></span>
Unchanged
</div>
</div>
);
}
export default function RadarGrid({ blips }) {
return (
<div className="radar-grid">
<RadarChart blips={blips} />
{Object.keys(quadrantsMap).map((id, index) => (
<QuadrantLabel key={index} quadrant={quadrantsMap[id]} />
))}
<Legend />
</div>
);
}

View File

@@ -0,0 +1,52 @@
.radar-grid {
position: relative;
margin-bottom: 50px;
color: white;
}
.radar-grid .quadrant-label {
position: absolute;
width: 20%;
}
.quadrant-label .split {
font-size: 12 px;
text-transform: uppercase;
}
.quadrant-label hr {
width: 100%;
margin: 10px 0 10px 0;
}
.quadrant-label .description {
font-size: 14px;
color: #a6b1bb
}
.quadrant-label .icon-link {
font-size: 12px;
}
.quadrant-label .icon-link .icon {
background-size: 18px 18px;
width: 18px;
height: 18px;
}
.radar-grid .radar-legend {
position: absolute;
width: 15%;
right: 0;
top: 45%;
}
.radar-legend .wrapper {
margin-bottom: 10px;
}
.radar-legend .icon {
background-position: center;
margin-right: 5px;
}

View File

@@ -5,7 +5,7 @@ import PageHelp from './PageHelp/PageHelp';
import PageQuadrant from './PageQuadrant/PageQuadrant'; import PageQuadrant from './PageQuadrant/PageQuadrant';
import PageItem from './PageItem/PageItem'; import PageItem from './PageItem/PageItem';
import PageItemMobile from './PageItemMobile/PageItemMobile'; import PageItemMobile from './PageItemMobile/PageItemMobile';
import {quadrants, getItemPageNames, isMobileViewport, rings} from '../config'; import {quadrantsMap, getItemPageNames, isMobileViewport, rings} from '../config';
import {Item} from '../model'; import {Item} from '../model';
type RouterProps = { type RouterProps = {
@@ -35,7 +35,7 @@ const getPageByName = (items: Item[], pageName: string): page => {
if (pageName === 'help-and-about-tech-radar') { if (pageName === 'help-and-about-tech-radar') {
return page.help; return page.help;
} }
if (quadrants.includes(pageName)) { if (Object.keys(quadrantsMap).includes(pageName)) {
return page.quadrant; return page.quadrant;
} }
if (getItemPageNames(items).includes(pageName)) { if (getItemPageNames(items).includes(pageName)) {

View File

@@ -3,43 +3,52 @@ import {Item} from './model';
export const radarName = process.env.RADAR_NAME || 'AOE Technology Radar' export const radarName = process.env.RADAR_NAME || 'AOE Technology Radar'
export const radarNameShort = radarName; export const radarNameShort = radarName;
export const quadrants = [ // Quadrants positions start from the top right and go clockwise
'languages-and-frameworks',
'methods-and-patterns',
'platforms-and-aoe-services',
'tools',
];
// Quadrants positions start from the top left and go clockwise
export const quadrantsMap = { export const quadrantsMap = {
'languages-and-frameworks': {
displayName: 'Languages & Frameworks',
colour: '#84BFA4',
position: 1
},
'methods-and-patterns': { 'methods-and-patterns': {
id: 'methods-and-patterns',
displayName: 'Methods & Patterns', displayName: 'Methods & Patterns',
colour: '#248EA6', colour: '#248EA6',
position: 2 txtColour: 'white',
position: 1,
description: 'Optional description goes here'
}, },
'platforms-and-aoe-services': { 'platforms-and-aoe-services': {
id: 'platforms-and-aoe-services',
displayName: 'Platforms and Operations', displayName: 'Platforms and Operations',
colour: '#F25244', colour: '#F25244',
position: 3 txtColour: '#444444',
position: 2,
description: 'Optional description goes here'
}, },
'tools': { 'tools': {
id: 'tools',
displayName: 'Tools', displayName: 'Tools',
colour: '#F2A25C', colour: '#F2A25C',
position: 4 txtColour: 'white',
position: 3,
description: 'Optional descrption goes here'
}, },
}; 'languages-and-frameworks': {
id: 'languages-and-frameworks',
displayName: 'Languages & Frameworks',
colour: '#84BFA4',
txtColour: '#444444',
position: 4,
description: 'Optional description goes here'
},
};
const chartMargin = 20,
chartSize = 900;
export const chartConfig = { export const chartConfig = {
margin: chartMargin, size: 800, //in px
size: chartSize, scale: [-16, 16],
canvasSize: chartSize - chartMargin * 2 blipSize: 12, // in px, be careful when increasing this value as it may cause a lot of calculations during placing the blips on the chart
ringsAttributes: [ // order from the centre outwards
{ radius: 8, arcWidth: 6 }, // radius values are based on the scale (not px!)
{ radius: 11, arcWidth: 4 },
{ radius: 14, arcWidth: 2 },
{ radius: 16, arcWidth: 2 }
]
}; };
export const rings = [ export const rings = [
@@ -57,18 +66,18 @@ export const ringsMap = {
position: 1 position: 1
}, },
'trial': { 'trial': {
displayName: 'TRIAL', displayName: 'EXPLORE',
position: 2 position: 2
}, },
'assess': { 'assess': {
displayName: 'ASSESS', displayName: 'ENDURE',
position: 3 position: 3
}, },
'hold': { 'hold': {
displayName: 'HOLD', displayName: 'RETIRE',
position: 4 position: 4
} }
}; };
// TODO replace with TS enum // TODO replace with TS enum
export const blipFlags = { export const blipFlags = {
@@ -83,15 +92,6 @@ export const getItemPageNames = (items: Item[]) => items.map(item => `${item.qua
export const showEmptyRings = false; export const showEmptyRings = false;
const messages: { [k: string]: string } = {
'languages-and-frameworks': 'Languages & Frameworks',
'methods-and-patterns': 'Methods & Patterns',
'platforms-and-aoe-services': 'Platforms and Operations',
'tools': 'Tools',
};
export const translate = (key: string) => (messages[key] || '-');
export function isMobileViewport() { export function isMobileViewport() {
// return false for server side rendering // return false for server side rendering
if (typeof window == 'undefined') return false; if (typeof window == 'undefined') return false;

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<rect transform="rotate(-45 8 8)" x="2" y="2" width="12" height="12" rx="3" fill="#a6b1bb"></rect>
</svg>

After

Width:  |  Height:  |  Size: 319 B

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="6" fill="#a6b1bb"></circle>
</svg>

After

Width:  |  Height:  |  Size: 273 B

4
src/icons/blip_new.svg Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path fill="#a6b1bb" d="M.247 10.212l5.02-8.697a2 2 0 013.465 0l5.021 8.697a2 2 0 01-1.732 3H1.98a2 2 0 01-1.732-3z"></path>
</svg>

After

Width:  |  Height:  |  Size: 345 B

View File

@@ -30,4 +30,25 @@
&--close { &--close {
background-image: url('../../icons/close.svg'); background-image: url('../../icons/close.svg');
} }
&--blip_new {
background-image: url('../../icons/blip_new.svg');
width: 18px;
height: 18px;
background-size: 18px;
}
&--blip_changed {
background-image: url('../../icons/blip_changed.svg');
width: 18px;
height: 18px;
background-size: 18px;
}
&--blip_default {
background-image: url('../../icons/blip_default.svg');
width: 18px;
height: 18px;
background-size: 18px;
}
} }

View File

@@ -1,9 +1,8 @@
#!/usr/bin/env node #!/usr/bin/env node
import {createRadar} from "./radar"; import {createRadar} from "./radar";
import {save} from "./file"; import {copyFileSync, mkdirSync} from "fs";
import {copyFileSync, mkdir, mkdirSync} from "fs"; import {quadrantsMap} from "../src/config";
import {quadrants} from "../src/config";
(async () => { (async () => {
@@ -14,7 +13,7 @@ import {quadrants} from "../src/config";
copyFileSync('build/index.html', 'build/overview.html') copyFileSync('build/index.html', 'build/overview.html')
copyFileSync('build/index.html', 'build/help-and-about-tech-radar.html') copyFileSync('build/index.html', 'build/help-and-about-tech-radar.html')
quadrants.forEach(quadrant => { Object.keys(quadrantsMap).forEach(quadrant => {
copyFileSync('build/index.html', 'build/' + quadrant + '.html') copyFileSync('build/index.html', 'build/' + quadrant + '.html')
mkdirSync('build/' + quadrant) mkdirSync('build/' + quadrant)
}) })

View File

@@ -3,7 +3,7 @@ import path from 'path';
import frontmatter from 'front-matter'; import frontmatter from 'front-matter';
import marked from 'marked'; import marked from 'marked';
import hljs from 'highlight.js'; import hljs from 'highlight.js';
import { quadrants, rings, blipFlags } from '../src/config'; import { quadrantsMap, ringsMap, blipFlags } from '../src/config';
import { radarPath, getAllMarkdownFiles } from './file'; import { radarPath, getAllMarkdownFiles } from './file';
import { Item, Revision, ItemAttributes, Radar } from '../src/model'; import { Item, Revision, ItemAttributes, Radar } from '../src/model';
@@ -27,12 +27,15 @@ export const createRadar = async (): Promise<Radar> => {
}; };
const checkAttributes = (fileName: string, attributes: FMAttributes) => { const checkAttributes = (fileName: string, attributes: FMAttributes) => {
if (attributes.ring && !rings.includes(attributes.ring)) { const validQuadrants = Object.keys(quadrantsMap);
throw new Error(`Error: ${fileName} has an illegal value for 'ring' - must be one of ${rings}`); const validRings = Object.keys(ringsMap);
if (attributes.ring && !validRings.includes(attributes.ring)) {
throw new Error(`Error: ${fileName} has an illegal value for 'ring' - must be one of ${validRings}`);
} }
if (attributes.quadrant && !quadrants.includes(attributes.quadrant)) { if (attributes.quadrant && !validQuadrants.includes(attributes.quadrant)) {
throw new Error(`Error: ${fileName} has an illegal value for 'quadrant' - must be one of ${quadrants}`); throw new Error(`Error: ${fileName} has an illegal value for 'quadrant' - must be one of ${validQuadrants}`);
} }
if (!attributes.quadrant || attributes.quadrant === '') { if (!attributes.quadrant || attributes.quadrant === '') {

View File

@@ -2,9 +2,6 @@
import {createRadar} from "./radar"; import {createRadar} from "./radar";
import {save} from "./file"; import {save} from "./file";
import {copyFileSync, mkdir, mkdirSync} from "fs";
import {quadrants} from "../src/config";
export const radarJsonGenerator = (async () => { export const radarJsonGenerator = (async () => {
try { try {

162
yarn.lock
View File

@@ -1004,11 +1004,6 @@
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18"
integrity sha1-8JULuhiBlRLUL3GX5WxRiqSRzxg= integrity sha1-8JULuhiBlRLUL3GX5WxRiqSRzxg=
"@discoveryjs/json-ext@^0.5.0":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==
"@hapi/address@2.x.x": "@hapi/address@2.x.x":
version "2.1.4" version "2.1.4"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
@@ -1597,23 +1592,6 @@
"@webassemblyjs/wast-parser" "1.8.5" "@webassemblyjs/wast-parser" "1.8.5"
"@xtuc/long" "4.2.2" "@xtuc/long" "4.2.2"
"@webpack-cli/configtest@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.0.2.tgz#2a20812bfb3a2ebb0b27ee26a52eeb3e3f000836"
integrity sha512-3OBzV2fBGZ5TBfdW50cha1lHDVf9vlvRXnjpVbJBa20pSZQaSkMJZiwA8V2vD9ogyeXn8nU5s5A6mHyf5jhMzA==
"@webpack-cli/info@^1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.2.3.tgz#ef819d10ace2976b6d134c7c823a3e79ee31a92c"
integrity sha512-lLek3/T7u40lTqzCGpC6CAbY6+vXhdhmwFRxZLMnRm6/sIF/7qMpT8MocXCRQfz0JAh63wpbXLMnsQ5162WS7Q==
dependencies:
envinfo "^7.7.3"
"@webpack-cli/serve@^1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.3.1.tgz#911d1b3ff4a843304b9c3bacf67bb34672418441"
integrity sha512-0qXvpeYO6vaNoRBI52/UsbcaBydJCggoBBnIo/ovQQdn6fug0BgwsjorV1hVS7fMqGVTZGcVxv8334gjmbj5hw==
"@xtuc/ieee754@^1.2.0": "@xtuc/ieee754@^1.2.0":
version "1.2.0" version "1.2.0"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
@@ -1721,11 +1699,6 @@ ansi-colors@^3.0.0:
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
integrity sha1-46PaS/uubIapwoViXeEkojQCb78= integrity sha1-46PaS/uubIapwoViXeEkojQCb78=
ansi-colors@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
ansi-escapes@^4.2.1: ansi-escapes@^4.2.1:
version "4.3.1" version "4.3.1"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61"
@@ -2824,11 +2797,6 @@ commander@^4.1.1:
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha1-n9YCvZNilOnp70aj9NaWQESxgGg= integrity sha1-n9YCvZNilOnp70aj9NaWQESxgGg=
commander@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
common-tags@^1.8.0: common-tags@^1.8.0:
version "1.8.0" version "1.8.0"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@@ -3063,7 +3031,7 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0" shebang-command "^1.2.0"
which "^1.2.9" which "^1.2.9"
cross-spawn@^7.0.0, cross-spawn@^7.0.3: cross-spawn@^7.0.0:
version "7.0.3" version "7.0.3"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha1-9zqFudXUHQRVUcF34ogtSshXKKY= integrity sha1-9zqFudXUHQRVUcF34ogtSshXKKY=
@@ -3950,13 +3918,6 @@ enhanced-resolve@^4.1.0:
memory-fs "^0.5.0" memory-fs "^0.5.0"
tapable "^1.0.0" tapable "^1.0.0"
enquirer@^2.3.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
dependencies:
ansi-colors "^4.1.1"
entities@^1.1.1: entities@^1.1.1:
version "1.1.2" version "1.1.2"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
@@ -3967,11 +3928,6 @@ entities@^2.0.0:
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
integrity sha1-mS0xKc999ocLlsV4WMJJoSD4uLU= integrity sha1-mS0xKc999ocLlsV4WMJJoSD4uLU=
envinfo@^7.7.3:
version "7.8.1"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475"
integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==
errno@^0.1.3, errno@~0.1.7: errno@^0.1.3, errno@~0.1.7:
version "0.1.8" version "0.1.8"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
@@ -4186,21 +4142,6 @@ execa@^4.0.0:
signal-exit "^3.0.2" signal-exit "^3.0.2"
strip-final-newline "^2.0.0" strip-final-newline "^2.0.0"
execa@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376"
integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==
dependencies:
cross-spawn "^7.0.3"
get-stream "^6.0.0"
human-signals "^2.1.0"
is-stream "^2.0.0"
merge-stream "^2.0.0"
npm-run-path "^4.0.1"
onetime "^5.1.2"
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"
exit@^0.1.2: exit@^0.1.2:
version "0.1.2" version "0.1.2"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@@ -4354,11 +4295,6 @@ fast-levenshtein@~2.0.6:
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fastest-levenshtein@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
faye-websocket@^0.11.3: faye-websocket@^0.11.3:
version "0.11.3" version "0.11.3"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e"
@@ -4708,11 +4644,6 @@ get-stream@^5.0.0:
dependencies: dependencies:
pump "^3.0.0" pump "^3.0.0"
get-stream@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
get-value@^2.0.3, get-value@^2.0.6: get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6" version "2.0.6"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
@@ -5136,11 +5067,6 @@ human-signals@^1.1.1:
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha1-xbHNFPUK6uCatsWf5jujOV/k36M= integrity sha1-xbHNFPUK6uCatsWf5jujOV/k36M=
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24: iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24:
version "0.4.24" version "0.4.24"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -5313,11 +5239,6 @@ internmap@^1.0.0:
resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95"
integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==
interpret@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
invariant@^2.2.2: invariant@^2.2.2:
version "2.2.4" version "2.2.4"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@@ -5431,13 +5352,6 @@ is-core-module@^2.1.0:
dependencies: dependencies:
has "^1.0.3" has "^1.0.3"
is-core-module@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.3.0.tgz#d341652e3408bca69c4671b79a0954a3d349f887"
integrity sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw==
dependencies:
has "^1.0.3"
is-data-descriptor@^0.1.4: is-data-descriptor@^0.1.4:
version "0.1.4" version "0.1.4"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@@ -7049,7 +6963,7 @@ npm-run-path@^2.0.0:
dependencies: dependencies:
path-key "^2.0.0" path-key "^2.0.0"
npm-run-path@^4.0.0, npm-run-path@^4.0.1: npm-run-path@^4.0.0:
version "4.0.1" version "4.0.1"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
integrity sha1-t+zR5e1T2o43pV4cImnguX7XSOo= integrity sha1-t+zR5e1T2o43pV4cImnguX7XSOo=
@@ -7202,7 +7116,7 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
dependencies: dependencies:
wrappy "1" wrappy "1"
onetime@^5.1.0, onetime@^5.1.2: onetime@^5.1.0:
version "5.1.2" version "5.1.2"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4= integrity sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4=
@@ -8317,7 +8231,7 @@ prompts@^2.0.1:
kleur "^3.0.3" kleur "^3.0.3"
sisteransi "^1.0.5" sisteransi "^1.0.5"
prop-types@^15.6.2: prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha1-UsQedbjIfnK52TYOAga5ncv/psU= integrity sha1-UsQedbjIfnK52TYOAga5ncv/psU=
@@ -8582,6 +8496,14 @@ react-router@5.2.0:
tiny-invariant "^1.0.2" tiny-invariant "^1.0.2"
tiny-warning "^1.0.0" tiny-warning "^1.0.0"
react-tooltip@^4.2.18:
version "4.2.18"
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-4.2.18.tgz#2fb8c5e115c4e5476f94081f4bb2ba77f5b2297f"
integrity sha512-MBdWuH925GL2ai5TWJelVJD9Opfk+3cLw0SP0rXR7s2RcNb7FefaNmljFndqYo8ghVcIEj5yM7aqV5Ith2bnqg==
dependencies:
prop-types "^15.7.2"
uuid "^7.0.3"
react@^16.13.1: react@^16.13.1:
version "16.14.0" version "16.14.0"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
@@ -8665,13 +8587,6 @@ readdirp@~3.5.0:
dependencies: dependencies:
picomatch "^2.2.1" picomatch "^2.2.1"
rechoir@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca"
integrity sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==
dependencies:
resolve "^1.9.0"
recursive-readdir@2.2.2: recursive-readdir@2.2.2:
version "2.2.2" version "2.2.2"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f"
@@ -8926,14 +8841,6 @@ resolve@^1.10.0, resolve@^1.12.0, resolve@^1.18.1, resolve@^1.3.2, resolve@^1.8.
is-core-module "^2.1.0" is-core-module "^2.1.0"
path-parse "^1.0.6" path-parse "^1.0.6"
resolve@^1.9.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
is-core-module "^2.2.0"
path-parse "^1.0.6"
restore-cursor@^3.1.0: restore-cursor@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
@@ -9302,7 +9209,7 @@ shellwords@^0.1.1:
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
integrity sha1-1rkYHBpI05cyTISHHvvPxz/AZUs= integrity sha1-1rkYHBpI05cyTISHHvvPxz/AZUs=
signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.3" version "3.0.3"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw= integrity sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw=
@@ -10333,16 +10240,16 @@ uuid@^3.3.2, uuid@^3.4.0:
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4= integrity sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=
uuid@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
uuid@^8.3.0: uuid@^8.3.0:
version "8.3.2" version "8.3.2"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha1-gNW1ztJxu5r2xEXyGhoExgbO++I= integrity sha1-gNW1ztJxu5r2xEXyGhoExgbO++I=
v8-compile-cache@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
v8-to-istanbul@^7.0.0: v8-to-istanbul@^7.0.0:
version "7.1.0" version "7.1.0"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz#5b95cef45c0f83217ec79f8fc7ee1c8b486aee07" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz#5b95cef45c0f83217ec79f8fc7ee1c8b486aee07"
@@ -10452,26 +10359,6 @@ webidl-conversions@^6.1.0:
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
integrity sha1-kRG01+qArNQPUnDWZmIa+ni2lRQ= integrity sha1-kRG01+qArNQPUnDWZmIa+ni2lRQ=
webpack-cli@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.6.0.tgz#27ae86bfaec0cf393fcfd58abdc5a229ad32fd16"
integrity sha512-9YV+qTcGMjQFiY7Nb1kmnupvb1x40lfpj8pwdO/bom+sQiP4OBMKjHq29YQrlDWDPZO9r/qWaRRywKaRDKqBTA==
dependencies:
"@discoveryjs/json-ext" "^0.5.0"
"@webpack-cli/configtest" "^1.0.2"
"@webpack-cli/info" "^1.2.3"
"@webpack-cli/serve" "^1.3.1"
colorette "^1.2.1"
commander "^7.0.0"
enquirer "^2.3.6"
execa "^5.0.0"
fastest-levenshtein "^1.0.12"
import-local "^3.0.2"
interpret "^2.2.0"
rechoir "^0.7.0"
v8-compile-cache "^2.2.0"
webpack-merge "^5.7.3"
webpack-dev-middleware@^3.7.2: webpack-dev-middleware@^3.7.2:
version "3.7.3" version "3.7.3"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5"
@@ -10540,14 +10427,6 @@ webpack-manifest-plugin@2.2.0:
object.entries "^1.1.0" object.entries "^1.1.0"
tapable "^1.0.0" tapable "^1.0.0"
webpack-merge@^5.7.3:
version "5.7.3"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.7.3.tgz#2a0754e1877a25a8bbab3d2475ca70a052708213"
integrity sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==
dependencies:
clone-deep "^4.0.1"
wildcard "^2.0.0"
webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
version "1.4.3" version "1.4.3"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
@@ -10646,11 +10525,6 @@ wide-align@^1.1.0:
dependencies: dependencies:
string-width "^1.0.2 || 2" string-width "^1.0.2 || 2"
wildcard@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
word-wrap@~1.2.3: word-wrap@~1.2.3:
version "1.2.3" version "1.2.3"
resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" resolved "https://extranet.aoe.com/artifactory/api/npm/om3-npm/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"