diff --git a/app/components/packages/details/PackageDependencies.js b/app/components/packages/details/PackageDependencies.js
index 2a44f310..304e92a6 100644
--- a/app/components/packages/details/PackageDependencies.js
+++ b/app/components/packages/details/PackageDependencies.js
@@ -7,6 +7,7 @@ import Typography from '@material-ui/core/Typography';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
+import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
import styles from './styles';
@@ -35,12 +36,10 @@ const PackageDependencies = ({ classes, dependencies }) => {
{dependency.name}
}
- secondary={
-
- {dependency.version}
-
- }
/>
+
+ {dependency.version}
+
))}
diff --git a/app/components/packages/details/styles.js b/app/components/packages/details/styles.js
index 37fa4954..f8b12dff 100644
--- a/app/components/packages/details/styles.js
+++ b/app/components/packages/details/styles.js
@@ -25,7 +25,7 @@ const styles = (theme) => ({
maxHeight: 425,
},
listItem: {
- padding: theme.spacing(1) / 2,
+ padding: theme.spacing(1),
margin: 0,
},
cardHeader: {
diff --git a/app/components/packages/item/styles.js b/app/components/packages/item/styles.js
index 66a39757..8fc7d6db 100644
--- a/app/components/packages/item/styles.js
+++ b/app/components/packages/item/styles.js
@@ -45,10 +45,8 @@ const styles = (theme) => ({
color: darken(grayColor, 0.5),
},
group: {
+ fontSize: 14,
color: theme.palette.common.grayColor,
- [theme.breakpoints.down('md')]: {
- fontSize: 14,
- },
},
statusMissing: {
color: theme.palette.secondary.main,
diff --git a/app/components/sidebar/Container.js b/app/components/sidebar/Container.js
index 3e51b645..afc80454 100755
--- a/app/components/sidebar/Container.js
+++ b/app/components/sidebar/Container.js
@@ -133,7 +133,7 @@ const AppSidebar = ({ classes, className }) => {
return showDialog(dialogHandler, dialogOptions);
}, [mode, directory, dispatch]);
- const dedupe = useCallback(() => {
+ const onDedupe = useCallback(() => {
const dialogOptions = {
title: 'Confirmation',
type: 'question',
@@ -214,7 +214,10 @@ const AppSidebar = ({ classes, className }) => {
npmEnv={npmEnv}
fromSearch={fromSearch}
installPackagesFromJson={installPackagesFromJson}
- dedupe={dedupe}
+ onDedupe={onDedupe}
+ onCacheClean={() => {}}
+ onCacheVerify={() => {}}
+ onShrinkWrap={() => {}}
cache={cache}
/>
diff --git a/app/components/sidebar/Sidebar.js b/app/components/sidebar/Sidebar.js
index e1a1cc42..fbeb0ce7 100755
--- a/app/components/sidebar/Sidebar.js
+++ b/app/components/sidebar/Sidebar.js
@@ -20,7 +20,7 @@ const Sidebar = ({
projectInfo,
npmEnv,
installPackagesFromJson,
- dedupe,
+ onDedupe,
cache,
}) => {
return (
@@ -36,15 +36,16 @@ const Sidebar = ({
mode={mode}
npmEnv={npmEnv}
/>
+
-
>
);
@@ -56,7 +57,7 @@ Sidebar.propTypes = {
history: arrayOf(object),
loadDirectory: func.isRequired,
installPackagesFromJson: func.isRequired,
- dedupe: func.isRequired,
+ onDedupe: func.isRequired,
cache: func.isRequired,
projectInfo: objectOf(string).isRequired,
updatedAt: string,
diff --git a/app/components/sidebar/tabs/Tabs.js b/app/components/sidebar/tabs/Tabs.js
index dc66444e..e37eaa12 100644
--- a/app/components/sidebar/tabs/Tabs.js
+++ b/app/components/sidebar/tabs/Tabs.js
@@ -39,18 +39,21 @@ const SidebarTabs = ({ classes, className, children }) => {
root: classes.tabLabel,
}}
icon={}
+ label="Packages"
/>
}
+ icon={}
+ label="Actions"
/>
}
+ icon={}
+ label="History"
/>
diff --git a/app/components/sidebar/tabs/actions/Actions.js b/app/components/sidebar/tabs/actions/Actions.js
index e78e6a94..9ddd4e9f 100755
--- a/app/components/sidebar/tabs/actions/Actions.js
+++ b/app/components/sidebar/tabs/actions/Actions.js
@@ -10,68 +10,137 @@ import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
import ListItemText from '@material-ui/core/ListItemText';
import ArrowRightIcon from '@material-ui/icons/ArrowRightAlt';
import InstallIcon from '@material-ui/icons/ArchiveOutlined';
+import CacheCleanIcon from '@material-ui/icons/DeleteSweepOutlined';
+import CacheCleanVerify from '@material-ui/icons/VerticalAlignBottom';
+import ShrinkWrapIcon from '@material-ui/icons/CenterFocusWeakOutlined';
+import DedupeIcon from '@material-ui/icons/CenterFocusWeakOutlined';
import Typography from '@material-ui/core/Typography';
import { iMessage } from 'commons/utils';
import styles from './styles';
-const ActionsTab = ({ classes, mode, onInstallPackagesFromJson }) => (
- <>
-
-
- {iMessage('title', 'actions')}
-
-
-
-
-
-
-
-
-
- {iMessage('action', 'npmInstall')}
-
-
- }
- secondary={
-
- {iMessage('info', 'npmInstallInfo')}
-
- }
- />
-
- {
+ return (
+
+
+ {icon}
+ {label}
+
+ }
+ secondary={
+ {details}
+ }
+ />
+
+
+
- >
-);
+
+
+
+
+
+
+ );
+};
+
+ActionItem.propTypes = {
+ classes: PropTypes.objectOf(PropTypes.string).isRequired,
+ mode: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ details: PropTypes.string.isRequired,
+ handler: PropTypes.func.isRequired,
+};
+
+const WithStylesActionItem = withStyles(styles)(ActionItem);
+
+const ActionsTab = ({
+ classes,
+ mode,
+ onInstallPackagesFromJson,
+ onCacheClean,
+ onCacheVerify,
+ onShrinkWrap,
+ onDedupe,
+}) => {
+ const actions = [
+ {
+ label: 'npm install',
+ details: 'Install packages from package.json',
+ title: 'Run npm install',
+ handler: onInstallPackagesFromJson,
+ icon: ,
+ },
+ {
+ label: 'npm cache clean',
+ details: 'Delete all data out of the cache folder.',
+ title: 'Run npm cache clean',
+ handler: onCacheClean,
+ icon: ,
+ },
+ {
+ label: 'npm cache verify',
+ details: 'Verify the contents of the cache folder',
+ title: 'Run npm cache verify',
+ handler: onCacheVerify,
+ icon: ,
+ },
+ {
+ label: 'npm shrinkwrap',
+ details:
+ 'Repurposes package-lock.json into a publishable npm-shrinkwrap.json',
+ title: 'Run npm shrinkwrap',
+ handler: onShrinkWrap,
+ icon: ,
+ },
+ {
+ label: 'npm dedupe',
+ details: 'Mode dependencies further up the tree',
+ title: 'Run npm dedupe',
+ handler: onDedupe,
+ icon: ,
+ },
+ ];
+
+ return (
+ <>
+
+
+ {iMessage('title', 'actions')}
+
+
+
+
+
+ {actions.map((action) => (
+
+ ))}
+
+
+ >
+ );
+};
ActionsTab.propTypes = {
classes: PropTypes.objectOf(PropTypes.string).isRequired,
onInstallPackagesFromJson: PropTypes.func.isRequired,
+ onCacheClean: PropTypes.func.isRequired,
mode: PropTypes.string.isRequired,
};
diff --git a/app/models/notifications/epics.js b/app/models/notifications/epics.js
index 27c9cd06..60b8a364 100755
--- a/app/models/notifications/epics.js
+++ b/app/models/notifications/epics.js
@@ -1,5 +1,5 @@
import { of } from 'rxjs';
-import { mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
+import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { v1 as uuidv1 } from 'uuid';
import semver from 'semver';
import { combineEpics, ofType } from 'redux-observable';
@@ -13,7 +13,7 @@ const parseNotificationEpic = (action$, state$) =>
action$.pipe(
ofType(parseNotification.type),
withLatestFrom(state$),
- mergeMap((values) => {
+ map((values) => {
const [notification, state] = values;
const {
notifications: { notifications: stateNotifications },
@@ -25,7 +25,14 @@ const parseNotificationEpic = (action$, state$) =>
const [reason, details] = notificationText.split(':');
const isExtraneous = reason === 'extraneous';
const detailsArr = details.trim().split(',');
- const [requiredDetails, requiredByName] = detailsArr;
+
+ return {
+ isExtraneous,
+ details: detailsArr,
+ };
+ }),
+ mergeMap(({ details, isExtraneous }) => {
+ const [requiredDetails, requiredByName] = details;
const [requiredName, requiredVersion] = requiredDetails.split('@');
const isValidVersion = semver.valid(requiredVersion);