Skip to content
18 changes: 11 additions & 7 deletions frontend/src/containers/AppList/AppList.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -36,25 +38,27 @@ 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 (
<main className={classes.root}>
{/* Show loader when fetching apps collections */}
<PageLoader show={isLoading} />

{/* Display list of apps */}
<Container className={classes.cardGrid} fixed>
{Object.keys(apps).map(key => (
{groups.map(group => (
<ExpansionPanel
defaultExpanded
className={classes.expansionPanel}
key={key}
key={group}
>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
Expand All @@ -63,12 +67,12 @@ export const AppList = ({ apps, isLoading, isLoaded, error, loadApps }) => {
className={classes.expansionPanelHeader}
>
<Typography className={classes.heading}>
{key.toUpperCase()} ({apps[key].length})
{group.toUpperCase()} ({apps[group].length})
</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails className={classes.panelDetails}>
<Grid container spacing={4}>
{apps[key].map((app, idx) => (
{apps[group].map((app, idx) => (
<Grid key={idx} item xs={12} sm={6} md={3}>
<AppCard card={app} />
</Grid>
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/redux/app/appsModule.js
Original file line number Diff line number Diff line change
@@ -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: [],
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}));
Loading