diff --git a/frontend/src/containers/AppList/AppList.js b/frontend/src/containers/AppList/AppList.js index ad91d6cd..9ff12501 100644 --- a/frontend/src/containers/AppList/AppList.js +++ b/frontend/src/containers/AppList/AppList.js @@ -5,6 +5,8 @@ import { Box, Grid, Container, makeStyles } from "@material-ui/core"; import * as appsStore from "../../redux/app/appsModule"; import selectApps from "../../redux/app/appsSelector"; +import { sortAlphabetically } from "../../utils/utils"; + import { AppCard, PageLoader } from "../../components"; import ExpansionPanel from "@material-ui/core/ExpansionPanel"; @@ -36,13 +38,15 @@ const useStyles = makeStyles(theme => ({ } })); -export const AppList = ({ apps, isLoading, isLoaded, error, loadApps }) => { +export const AppList = ({ apps, groups, isLoading, isLoaded, error, loadApps }) => { const classes = useStyles(); useEffect(() => { loadApps(); }, [loadApps]); + const groups = sortAlphabetically(Object.keys(apps || {})) + return (
{/* Show loader when fetching apps collections */} @@ -50,11 +54,11 @@ export const AppList = ({ apps, isLoading, isLoaded, error, loadApps }) => { {/* Display list of apps */} - {Object.keys(apps).map(key => ( + {groups.map(group => ( } @@ -63,12 +67,12 @@ export const AppList = ({ apps, isLoading, isLoaded, error, loadApps }) => { className={classes.expansionPanelHeader} > - {key.toUpperCase()} ({apps[key].length}) + {group.toUpperCase()} ({apps[group].length}) - {apps[key].map((app, idx) => ( + {apps[group].map((app, idx) => ( @@ -93,14 +97,14 @@ export const AppList = ({ apps, isLoading, isLoaded, error, loadApps }) => { }; AppList.props = { - apps: PropTypes.array, + apps: PropTypes.object, isLoading: PropTypes.bool.isRequired, isLoaded: PropTypes.bool.isRequired, error: PropTypes.oneOf([PropTypes.string, PropTypes.object]) }; AppList.defaultProps = { - apps: [], + apps: {}, isLoading: false, isLoaded: false, error: null diff --git a/frontend/src/redux/app/appsModule.js b/frontend/src/redux/app/appsModule.js index 1fad046a..63f4c218 100644 --- a/frontend/src/redux/app/appsModule.js +++ b/frontend/src/redux/app/appsModule.js @@ -1,6 +1,6 @@ import { createSlice } from "@reduxjs/toolkit"; import { getApps } from "../../services/api"; -import { groupBy } from "../../utils/utils"; +import { groupBy, sortAlphabetically } from "../../utils/utils"; const initialState = { data: [], @@ -44,7 +44,7 @@ const loadApps = () => async dispatch => { dispatch(loading()); let { data } = await getApps(); - data = groupBy("group")(data); + data = groupBy("group")(sortAlphabetically(data, i => i.name)); dispatch(loadAppsSuccess(data)); } catch (e) { diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js index 94e98b33..bd1bb893 100644 --- a/frontend/src/utils/utils.js +++ b/frontend/src/utils/utils.js @@ -12,3 +12,6 @@ export const isURL = str => { var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; return regexp.test(str); }; + +export const sortAlphabetically = (array, accessor = i => i) => + array.slice().sort((a, b) => accessor(a).toLowerCase().localeCompare(accessor(b).toLowerCase(), 'en', {numeric: true}));