Commit 807e70ca authored by Robert Knight's avatar Robert Knight

Merge branch 'master' into dependabot/npm_and_yarn/babel/preset-env-7.5.0

Merge with `yarn.lock` updates on master.
parents dcaeba85 e080b8b9
......@@ -28,7 +28,6 @@ function fetchThread(api, id) {
// @ngInject
function AnnotationViewerContentController(
$location,
$routeParams,
store,
api,
......@@ -43,12 +42,6 @@ function AnnotationViewerContentController(
const id = $routeParams.id;
this.$onInit = () => {
this.search.update = function(query) {
$location.path('/stream').search('q', query);
};
};
store.subscribe(function() {
self.rootThread = rootThread.thread(store.getState());
});
......@@ -87,8 +80,6 @@ function AnnotationViewerContentController(
module.exports = {
controller: AnnotationViewerContentController,
controllerAs: 'vm',
bindings: {
search: '<',
},
bindings: {},
template: require('../templates/annotation-viewer-content.html'),
};
......@@ -35,7 +35,6 @@ function authStateFromProfile(profile) {
// @ngInject
function HypothesisAppController(
$document,
$location,
$rootScope,
$route,
$scope,
......@@ -185,15 +184,6 @@ function HypothesisAppController(
session.logout();
};
this.search = {
query: function() {
return store.getState().filterQuery;
},
update: function(query) {
store.setFilterQuery(query);
},
};
this.countPendingUpdates = streamer.countPendingUpdates;
this.applyPendingUpdates = streamer.applyPendingUpdates;
}
......
'use strict';
module.exports = {
controllerAs: 'vm',
//@ngInject
controller: function() {},
bindings: {
/**
* An object representing the current authentication status.
*/
auth: '<',
/**
* Called when the user clicks on the "About this version" text.
*/
onLogin: '&',
/**
* Called when the user clicks on the "Sign Up" text.
*/
onSignUp: '&',
/**
* Called when the user clicks on the "Log out" text.
*/
onLogout: '&',
},
template: require('../templates/login-control.html'),
};
......@@ -75,7 +75,7 @@ function ModerationBanner({ annotation, api, flash }) {
}
return (
<div className={bannerClasses}>
{flagCount && !annotation.hidden && (
{!!flagCount && !annotation.hidden && (
<span>Flagged for review x{flagCount}</span>
)}
{annotation.hidden && (
......
......@@ -30,10 +30,7 @@ function SearchInput({ alwaysExpanded, query, onSearch }) {
const onSubmit = e => {
e.preventDefault();
// TODO - When the parent components are converted to React, the signature
// of the callback can be simplified to `onSearch(query)` rather than
// `onSearch({ $query: query })`.
onSearch({ $query: input.current.value });
onSearch(input.current.value);
};
// When the active query changes outside of this component, update the input
......@@ -61,6 +58,7 @@ function SearchInput({ alwaysExpanded, query, onSearch }) {
<button
type="button"
className="search-input__icon top-bar__btn"
title="Search"
onClick={() => input.current.focus()}
>
<i className="h-icon-search" />
......
......@@ -3,7 +3,6 @@
// @ngInject
function StreamContentController(
$scope,
$location,
$route,
$routeParams,
annotationMapper,
......@@ -55,6 +54,10 @@ function StreamContentController(
}
});
// In case this route loaded after a client-side route change (eg. from
// '/a/:id'), clear any existing annotations.
store.clearAnnotations();
// Perform the initial search
fetch(20);
......@@ -68,18 +71,11 @@ function StreamContentController(
store.setSortKey('Newest');
this.loadMore = fetch;
this.$onInit = () => {
this.search.query = () => $routeParams.q || '';
this.search.update = q => $location.search({ q });
};
}
module.exports = {
controller: StreamContentController,
controllerAs: 'vm',
bindings: {
search: '<',
},
bindings: {},
template: require('../templates/stream-content.html'),
};
'use strict';
const { createElement } = require('preact');
const { useEffect, useState } = require('preact/hooks');
const propTypes = require('prop-types');
const { withServices } = require('../util/service-context');
const SearchInput = require('./search-input');
/**
* Search input for the single annotation view and stream.
*
* This displays and updates the "q" query param in the URL.
*/
function StreamSearchInput({ $location, $rootScope }) {
const [query, setQuery] = useState($location.search().q);
const search = query => {
$rootScope.$apply(() => {
// Re-route the user to `/stream` if they are on `/a/:id` and then set
// the search query.
$location.path('/stream').search({ q: query });
});
};
useEffect(() => {
$rootScope.$on('$locationChangeSuccess', () => {
setQuery($location.search().q);
});
});
return <SearchInput query={query} onSearch={search} alwaysExpanded={true} />;
}
StreamSearchInput.propTypes = {
$location: propTypes.object,
$rootScope: propTypes.object,
};
StreamSearchInput.injectedProps = ['$location', '$rootScope'];
module.exports = withServices(StreamSearchInput);
......@@ -19,7 +19,6 @@ describe('sidebar.components.hypothesis-app', function() {
let fakeFeatures = null;
let fakeFlash = null;
let fakeFrameSync = null;
let fakeLocation = null;
let fakeParams = null;
let fakeServiceConfig = null;
let fakeSession = null;
......@@ -96,10 +95,6 @@ describe('sidebar.components.hypothesis-app', function() {
connect: sandbox.spy(),
};
fakeLocation = {
search: sandbox.stub().returns({}),
};
fakeParams = { id: 'test' };
fakeSession = {
......@@ -144,7 +139,6 @@ describe('sidebar.components.hypothesis-app', function() {
$provide.value('streamer', fakeStreamer);
$provide.value('groups', fakeGroups);
$provide.value('$route', fakeRoute);
$provide.value('$location', fakeLocation);
$provide.value('$routeParams', fakeParams);
$provide.value('$window', fakeWindow);
})
......
'use strict';
const angular = require('angular');
const util = require('../../directive/test/util');
const loginControl = require('../login-control');
describe('loginControl', function() {
before(function() {
angular.module('app', []).component('loginControl', loginControl);
});
beforeEach(function() {
angular.mock.module('app', {});
});
describe('sign up and log in links', () => {
it('should render empty login and signup element if user auth status is unknown', () => {
const el = util.createDirective(document, 'loginControl', {
auth: {
username: 'someUsername',
status: 'unknown',
},
newStyle: true,
});
const loginEl = el.find('.login-text');
const links = loginEl.find('a');
assert.lengthOf(loginEl, 1);
assert.lengthOf(links, 0);
});
it('should render login and signup links if user is logged out', () => {
const el = util.createDirective(document, 'loginControl', {
auth: {
username: 'someUsername',
status: 'logged-out',
},
newStyle: true,
});
const loginEl = el.find('.login-text');
const links = loginEl.find('a');
assert.lengthOf(loginEl, 1);
assert.lengthOf(links, 2);
});
it('should not render login and signup element if user is logged in', () => {
const el = util.createDirective(document, 'loginControl', {
auth: {
username: 'someUsername',
status: 'logged-in',
},
newStyle: true,
});
const loginEl = el.find('.login-text');
assert.lengthOf(loginEl, 0);
});
});
describe('user menu', () => {
it('should render a user menu if the user is logged in', () => {
const el = util.createDirective(document, 'loginControl', {
auth: {
username: 'someUsername',
status: 'logged-in',
},
newStyle: true,
});
const menuEl = el.find('user-menu');
assert.lengthOf(menuEl, 1);
});
it('should not render a user menu if user is not logged in', () => {
const el = util.createDirective(document, 'loginControl', {
auth: {
username: 'someUsername',
status: 'logged-out',
},
newStyle: true,
});
const menuEl = el.find('user-menu');
assert.lengthOf(menuEl, 0);
});
});
});
......@@ -59,7 +59,7 @@ describe('SearchInput', () => {
const wrapper = createSearchInput({ query: 'foo', onSearch });
typeQuery(wrapper, 'new-query');
wrapper.find('form').simulate('submit');
assert.calledWith(onSearch, { $query: 'new-query' });
assert.calledWith(onSearch, 'new-query');
});
it('renders loading indicator when app is in a "loading" state', () => {
......
......@@ -94,18 +94,14 @@ describe('StreamContentController', function() {
});
function createController() {
return $componentController(
'streamContent',
{},
{
search: {
query: sinon.stub(),
update: sinon.stub(),
},
}
);
return $componentController('streamContent', {}, {});
}
it('clears any existing annotations when the /stream route is loaded', () => {
createController();
assert.calledOnce(fakeStore.clearAnnotations);
});
it('calls the search API with `_separate_replies: true`', function() {
createController();
assert.equal(fakeApi.search.firstCall.args[0]._separate_replies, true);
......@@ -144,7 +140,10 @@ describe('StreamContentController', function() {
it('does not reload the route if the query did not change', function() {
fakeRouteParams.q = 'test query';
createController();
fakeStore.clearAnnotations.resetHistory();
$rootScope.$broadcast('$routeUpdate');
assert.notCalled(fakeStore.clearAnnotations);
assert.notCalled(fakeRoute.reload);
});
......
'use strict';
const { shallow } = require('enzyme');
const { createElement } = require('preact');
const { act } = require('preact/test-utils');
const StreamSearchInput = require('../stream-search-input');
describe('StreamSearchInput', () => {
let fakeLocation;
let fakeRootScope;
beforeEach(() => {
fakeLocation = {
path: sinon.stub().returnsThis(),
search: sinon.stub().returns({ q: 'the-query' }),
};
fakeRootScope = {
$apply: callback => callback(),
$on: sinon.stub(),
};
});
function createSearchInput(props = {}) {
return shallow(
<StreamSearchInput
$location={fakeLocation}
$rootScope={fakeRootScope}
{...props}
/>
).dive(); // Dive through `withServices` wrapper.
}
it('displays current "q" search param', () => {
const wrapper = createSearchInput();
assert.equal(wrapper.find('SearchInput').prop('query'), 'the-query');
});
it('sets path and query when user searches', () => {
const wrapper = createSearchInput();
act(() => {
wrapper
.find('SearchInput')
.props()
.onSearch('new-query');
});
assert.calledWith(fakeLocation.path, '/stream');
assert.calledWith(fakeLocation.search, { q: 'new-query' });
});
it('updates query when changed in URL', () => {
fakeLocation.search.returns({ q: 'query-b' });
const wrapper = createSearchInput();
assert.calledOnce(fakeRootScope.$on);
assert.calledWith(fakeRootScope.$on, '$locationChangeSuccess');
act(() => {
fakeRootScope.$on.lastCall.callback();
});
// Check that new query is displayed.
wrapper.update();
assert.equal(wrapper.find('SearchInput').prop('query'), 'query-b');
});
});
This diff is collapsed.
'use strict';
const { Fragment, createElement } = require('preact');
const classnames = require('classnames');
const propTypes = require('prop-types');
const useStore = require('../store/use-store');
const { applyTheme } = require('../util/theme');
const isThirdPartyService = require('../util/is-third-party-service');
const { withServices } = require('../util/service-context');
const GroupList = require('./group-list');
const SearchInput = require('./search-input');
const StreamSearchInput = require('./stream-search-input');
const SortMenu = require('./sort-menu');
const SvgIcon = require('./svg-icon');
const UserMenu = require('./user-menu');
/**
* The toolbar which appears at the top of the sidebar providing actions
* to switch groups, view account information, sort/filter annotations etc.
*/
function TopBar({
auth,
isSidebar,
onApplyPendingUpdates,
onLogin,
onLogout,
onSharePage,
onShowHelpPanel,
onSignUp,
pendingUpdateCount,
settings,
}) {
const useCleanTheme = settings.theme === 'clean';
const showSharePageButton = !isThirdPartyService(settings);
const loginLinkStyle = applyTheme(['accentColor'], settings);
const filterQuery = useStore(store => store.filterQuery());
const setFilterQuery = useStore(store => store.setFilterQuery);
const loginControl = (
<Fragment>
{auth.status === 'unknown' && (
<span className="top-bar__login-links"></span>
)}
{auth.status === 'logged-out' && (
<span className="top-bar__login-links">
<a href="#" onClick={onSignUp} target="_blank" style={loginLinkStyle}>
Sign up
</a>{' '}
/{' '}
<a href="#" onClick={onLogin} style={loginLinkStyle}>
Log in
</a>
</span>
)}
{auth.status === 'logged-in' && (
<UserMenu auth={auth} onLogout={onLogout} />
)}
</Fragment>
);
return (
<div
className={classnames('top-bar', useCleanTheme && 'top-bar--theme-clean')}
>
{/* Single-annotation and stream views. */}
{!isSidebar && (
<div className="top-bar__inner content">
<StreamSearchInput />
<div className="top-bar__expander" />
<button
className="top-bar__btn top-bar__help-btn"
onClick={onShowHelpPanel}
title="Help"
aria-label="Help"
>
<SvgIcon name="help" className="top-bar__help-icon" />
</button>
{loginControl}
</div>
)}
{/* Sidebar view */}
{isSidebar && (
<div className="top-bar__inner content">
<GroupList className="GroupList" auth={auth} />
<div className="top-bar__expander" />
{pendingUpdateCount > 0 && (
<a
className="top-bar__apply-update-btn"
onClick={onApplyPendingUpdates}
title={`Show ${pendingUpdateCount} new/updated ${
pendingUpdateCount === 1 ? 'annotation' : 'annotations'
}`}
>
<SvgIcon className="top-bar__apply-icon" name="refresh" />
</a>
)}
<SearchInput query={filterQuery} onSearch={setFilterQuery} />
<SortMenu />
{showSharePageButton && (
<button
className="top-bar__btn"
onClick={onSharePage}
title="Share this page"
aria-label="Share this page"
>
<i className="h-icon-annotation-share" />
</button>
)}
<button
className="top-bar__btn top-bar__help-btn"
onClick={onShowHelpPanel}
title="Help"
aria-label="Help"
>
<SvgIcon name="help" className="top-bar__help-icon" />
</button>
{loginControl}
</div>
)}
</div>
);
}
TopBar.propTypes = {
/**
* Object containing current authentication status.
*/
auth: propTypes.shape({
status: propTypes.string.isRequired,
// Additional properties when user is logged in.
displayName: propTypes.string,
userid: propTypes.string,
username: propTypes.string,
}),
/**
* Flag indicating whether the app is the sidebar or a top-level page.
*/
isSidebar: propTypes.bool,
module.exports = {
controllerAs: 'vm',
//@ngInject
controller: function(settings) {
if (settings.theme && settings.theme === 'clean') {
this.isThemeClean = true;
} else {
this.isThemeClean = false;
}
this.showSharePageButton = function() {
return !isThirdPartyService(settings);
};
},
bindings: {
auth: '<',
isSidebar: '<',
onShowHelpPanel: '&',
onLogin: '&',
onLogout: '&',
onSharePage: '&',
onSignUp: '&',
searchController: '<',
pendingUpdateCount: '<',
onApplyPendingUpdates: '&',
},
template: require('../templates/top-bar.html'),
/**
* Callback invoked when user clicks "Help" button.
*/
onShowHelpPanel: propTypes.func,
/**
* Callback invoked when user clicks "Login" button.
*/
onLogin: propTypes.func,
/** Callback invoked when user clicks "Logout" action in account menu. */
onLogout: propTypes.func,
/** Callback invoked when user clicks "Share" toolbar action. */
onSharePage: propTypes.func,
/** Callback invoked when user clicks "Sign up" button. */
onSignUp: propTypes.func,
/** Count of updates received via WebSocket that have not been applied. */
pendingUpdateCount: propTypes.number,
/** Called when user clicks button to apply pending real-time updates. */
onApplyPendingUpdates: propTypes.func,
// Services
settings: propTypes.object,
};
TopBar.injectedProps = ['settings'];
module.exports = withServices(TopBar);
......@@ -79,13 +79,12 @@ function configureRoutes($routeProvider) {
// The `vm.{auth,search}` properties used in these templates come from the
// `<hypothesis-app>` component which hosts the router's container element.
$routeProvider.when('/a/:id', {
template:
'<annotation-viewer-content search="vm.search"></annotation-viewer-content>',
template: '<annotation-viewer-content></annotation-viewer-content>',
reloadOnSearch: false,
resolve: resolve,
});
$routeProvider.when('/stream', {
template: '<stream-content search="vm.search"></stream-content>',
template: '<stream-content></stream-content>',
reloadOnSearch: false,
resolve: resolve,
});
......@@ -167,27 +166,18 @@ function startAngularApp(config) {
require('./components/annotation-viewer-content')
)
.component('excerpt', require('./components/excerpt'))
.component(
'groupList',
wrapReactComponent(require('./components/group-list'))
)
.component(
'helpLink',
wrapReactComponent(require('./components/help-link'))
)
.component('helpPanel', require('./components/help-panel'))
.component('loggedoutMessage', require('./components/loggedout-message'))
.component('loginControl', require('./components/login-control'))
.component('markdown', require('./components/markdown'))
.component(
'moderationBanner',
wrapReactComponent(require('./components/moderation-banner'))
)
.component('newNoteBtn', require('./components/new-note-btn'))
.component(
'searchInput',
wrapReactComponent(require('./components/search-input'))
)
.component('searchStatusBar', require('./components/search-status-bar'))
.component('selectionTabs', require('./components/selection-tabs'))
.component('sidebarContent', require('./components/sidebar-content'))
......@@ -197,11 +187,6 @@ function startAngularApp(config) {
)
.component('sidebarTutorial', require('./components/sidebar-tutorial'))
.component('shareDialog', require('./components/share-dialog'))
.component(
'sortMenu',
wrapReactComponent(require('./components/sort-menu'))
)
.component('spinner', wrapReactComponent(require('./components/spinner')))
.component('streamContent', require('./components/stream-content'))
.component('svgIcon', wrapReactComponent(require('./components/svg-icon')))
.component('tagEditor', require('./components/tag-editor'))
......@@ -210,12 +195,7 @@ function startAngularApp(config) {
'timestamp',
wrapReactComponent(require('./components/timestamp'))
)
.component('topBar', require('./components/top-bar'))
.component(
'userMenu',
wrapReactComponent(require('./components/user-menu'))
)
.component('topBar', wrapReactComponent(require('./components/top-bar')))
.directive('hAutofocus', require('./directive/h-autofocus'))
.directive('hBranding', require('./directive/h-branding'))
.directive('hOnTouch', require('./directive/h-on-touch'))
......
......@@ -348,6 +348,10 @@ const getFirstSelectedAnnotationId = createSelector(
selected => (selected ? Object.keys(selected)[0] : null)
);
function filterQuery(state) {
return state.filterQuery;
}
module.exports = {
init: init,
update: update,
......@@ -369,6 +373,7 @@ module.exports = {
selectors: {
hasSelectedAnnotations,
filterQuery,
isAnnotationSelected,
getFirstSelectedAnnotationId,
},
......
......@@ -8,8 +8,7 @@
on-show-help-panel="vm.showHelpPanel()"
is-sidebar="::vm.isSidebar"
pending-update-count="vm.countPendingUpdates()"
on-apply-pending-updates="vm.applyPendingUpdates()"
search-controller="vm.search">
on-apply-pending-updates="vm.applyPendingUpdates()">
</top-bar>
<div class="content">
......
<!-- New controls -->
<span class="login-text"
ng-if="vm.auth.status === 'unknown'"></span>
<span class="login-text"
ng-if="vm.auth.status === 'logged-out'">
<a href="" ng-click="vm.onSignUp()" target="_blank" h-branding="accentColor">Sign up</a>
/ <a href="" ng-click="vm.onLogin()" h-branding="accentColor">Log in</a>
</span>
<user-menu auth="vm.auth" on-logout="vm.onLogout()" ng-if="vm.auth.status === 'logged-in'"/>
<div class="moderation-banner"
ng-if="vm.isHiddenOrFlagged()"
ng-class="{'is-flagged': vm.flagCount() > 0,
'is-hidden': vm.isHidden(),
'is-reply': vm.isReply()}">
<span ng-if="vm.flagCount() > 0 && !vm.isHidden()">
Flagged for review x{{ vm.flagCount() }}
</span>
<span ng-if="vm.isHidden()">
Hidden from users. Flagged x{{ vm.flagCount() }}
</span>
<span class="u-stretch"></span>
<button ng-if="!vm.isHidden()"
ng-click="vm.hideAnnotation()"
title="Hide this annotation from non-moderators">
Hide
</button>
<button ng-if="vm.isHidden()"
ng-click="vm.unhideAnnotation()"
title="Make this annotation visible to everyone">
Unhide
</button>
</div>
<!-- top bar for the sidebar and the stream.
!-->
<div class="top-bar"
ng-class="{'top-bar--theme-clean' : vm.isThemeClean }">
<!-- Legacy design for top bar, as used in the stream !-->
<div class="top-bar__inner content" ng-if="::!vm.isSidebar">
<search-input
class="search-input"
query="vm.searchController.query()"
on-search="vm.searchController.update($query)"
always-expanded="true">
</search-input>
<div class="top-bar__expander"></div>
<button class="top-bar__btn top-bar__help-btn"
ng-click="vm.onShowHelpPanel()"
title="Help"
aria-label="Help">
<svg-icon name="'help'" class-name="'top-bar__help-icon'"></svg-icon>
</button>
<login-control
class="login-control"
auth="vm.auth"
on-login="vm.onLogin()"
on-logout="vm.onLogout()"
on-sign-up="vm.onSignUp()">
</login-control>
</div>
<!-- New design for the top bar, as used in the sidebar.
The inner div is styled with 'content' to center it in
the stream view.
!-->
<div class="top-bar__inner content" ng-if="::vm.isSidebar">
<group-list class="group-list" auth="vm.auth"></group-list>
<div class="top-bar__expander"></div>
<a class="top-bar__apply-update-btn"
ng-if="vm.pendingUpdateCount > 0"
ng-click="vm.onApplyPendingUpdates()"
h-tooltip
tooltip-direction="up"
aria-label="Show {{vm.pendingUpdateCount}} new/updated annotation(s)">
<svg-icon class="top-bar__apply-icon" name="'refresh'"></svg-icon>
</a>
<search-input
class="search-input"
query="vm.searchController.query()"
on-search="vm.searchController.update($query)"
title="Filter the annotation list">
</search-input>
<sort-menu></sort-menu>
<button class="top-bar__btn"
ng-click="vm.onSharePage()"
ng-if="vm.showSharePageButton()"
title="Share this page"
aria-label="Share this page">
<i class="h-icon-annotation-share"></i>
</button>
<button class="top-bar__btn top-bar__help-btn"
ng-click="vm.onShowHelpPanel()"
title="Help"
aria-label="Help">
<svg-icon name="'help'" class-name="'top-bar__help-icon'"></svg-icon>
</button>
<login-control
class="login-control"
auth="vm.auth"
on-login="vm.onLogin()"
on-logout="vm.onLogout()"
on-sign-up="vm.onSignUp()">
</login-control>
</div>
</div>
......@@ -6,6 +6,11 @@
align-items: center;
color: $grey-6;
display: flex;
// Prevent label from wrapping if top bar is too narrow to fit all of its
// items.
flex-shrink: 0;
font-size: $body2-font-size;
font-weight: bold;
}
......
.login-control {
flex-shrink: 0;
}
.login-text {
font-size: $body2-font-size;
padding-left: 6px;
}
......@@ -21,6 +21,12 @@
border-bottom: none;
}
.top-bar__login-links {
flex-shrink: 0;
font-size: $body2-font-size;
padding-left: 6px;
}
.top-bar__inner {
// the edges of the top-bar's contents should be aligned
// with the edges of annotation cards displayed below
......
......@@ -31,7 +31,6 @@ $base-line-height: 20px;
@import './components/group-list-item';
@import './components/help-panel';
@import './components/loggedout-message';
@import './components/login-control';
@import './components/markdown';
@import './components/menu';
@import './components/menu-item';
......
......@@ -1279,17 +1279,17 @@ autofill-event@0.0.1:
integrity sha1-w4LPmJshth/0oSs1l+GUNHHTz3o=
autoprefixer@^9.4.7:
version "9.6.0"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.0.tgz#0111c6bde2ad20c6f17995a33fad7cf6854b4c87"
integrity sha512-kuip9YilBqhirhHEGHaBTZKXL//xxGnzvsD0FtBQa6z+A69qZD6s/BAX9VzDF1i9VKDquTJDQaPLSEhOnL6FvQ==
version "9.6.1"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47"
integrity sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==
dependencies:
browserslist "^4.6.1"
caniuse-lite "^1.0.30000971"
browserslist "^4.6.3"
caniuse-lite "^1.0.30000980"
chalk "^2.4.2"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^7.0.16"
postcss-value-parser "^3.3.1"
postcss "^7.0.17"
postcss-value-parser "^4.0.0"
aws-sdk@^2.345.0:
version "2.400.0"
......@@ -1700,7 +1700,16 @@ browserify@^16.1.0, browserify@^16.2.3:
vm-browserify "^1.0.0"
xtend "^4.0.0"
browserslist@^4.6.0, browserslist@^4.6.2:
browserslist@^4.6.0, browserslist@^4.6.3:
version "4.6.3"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.3.tgz#0530cbc6ab0c1f3fc8c819c72377ba55cf647f05"
integrity sha512-CNBqTCq22RKM8wKJNowcqihHJ4SkI8CGeK7KOR9tPboXUuS5Zk5lQgzzTbs4oxD8x+6HUshZUa2OyNI9lR93bQ==
dependencies:
caniuse-lite "^1.0.30000975"
electron-to-chromium "^1.3.164"
node-releases "^1.1.23"
browserslist@^4.6.2:
version "4.6.4"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.4.tgz#fd0638b3f8867fec2c604ed0ed9300379f8ec7c2"
integrity sha512-ErJT8qGfRt/VWHSr1HeqZzz50DvxHtr1fVL1m5wf20aGrG8e1ce8fpZ2EjZEfs09DDZYSvtRaDlMpWslBf8Low==
......@@ -1709,15 +1718,6 @@ browserslist@^4.6.0, browserslist@^4.6.2:
electron-to-chromium "^1.3.188"
node-releases "^1.1.25"
browserslist@^4.6.1:
version "4.6.2"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.2.tgz#574c665950915c2ac73a4594b8537a9eba26203f"
integrity sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==
dependencies:
caniuse-lite "^1.0.30000974"
electron-to-chromium "^1.3.150"
node-releases "^1.1.23"
btoa-lite@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337"
......@@ -1836,12 +1836,7 @@ camelcase@^5.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42"
integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==
caniuse-lite@^1.0.30000971:
version "1.0.30000974"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000974.tgz#b7afe14ee004e97ce6dc73e3f878290a12928ad8"
integrity sha512-xc3rkNS/Zc3CmpMKuczWEdY2sZgx09BkAxfvkxlAEBTqcMHeL8QnPqhKse+5sRTi3nrw2pJwToD2WvKn1Uhvww==
caniuse-lite@^1.0.30000974, caniuse-lite@^1.0.30000981:
caniuse-lite@^1.0.30000975, caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000981:
version "1.0.30000981"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000981.tgz#5b6828803362363e5a1deba2eb550185cf6cec8f"
integrity sha512-JTByHj4DQgL2crHNMK6PibqAMrqqb/Vvh0JrsTJVSWG4VSUrT16EklkuRZofurlMjgA9e+zlCM4Y39F3kootMQ==
......@@ -2860,7 +2855,7 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.3.150, electron-to-chromium@^1.3.188:
electron-to-chromium@^1.3.164, electron-to-chromium@^1.3.188:
version "1.3.188"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.188.tgz#e28e1afe4bb229989e280bfd3b395c7ec03c8b7a"
integrity sha512-tEQcughYIMj8WDMc59EGEtNxdGgwal/oLLTDw+NEqJRJwGflQvH3aiyiexrWeZOETP4/ko78PVr6gwNhdozvuQ==
......@@ -6899,12 +6894,12 @@ postcss-url@^8.0.0:
postcss "^7.0.2"
xxhashjs "^0.2.1"
postcss-value-parser@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
postcss-value-parser@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz#99a983d365f7b2ad8d0f9b8c3094926eab4b936d"
integrity sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ==
postcss@^7.0.13, postcss@^7.0.16, postcss@^7.0.2:
postcss@^7.0.13, postcss@^7.0.17, postcss@^7.0.2:
version "7.0.17"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f"
integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment