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);