Skip to content

Commit

Permalink
feat: allow filtering of packages (#214)
Browse files Browse the repository at this point in the history
This change updates the Packages Page and Repository Page to allow filters to be applied to the Packages Table so only draft, proposed, published, and upgrade available packages are shown.
  • Loading branch information
ChristopherFry committed Nov 13, 2022
1 parent 025dae1 commit 39c80e9
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 55 deletions.
48 changes: 48 additions & 0 deletions plugins/cad/src/components/Controls/Chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Chip as MaterialChip, makeStyles } from '@material-ui/core';
import React from 'react';

type ChipProps = {
label: string;
selected: boolean;
onClick: () => void;
};

const useStyles = makeStyles({
chip: {
marginBottom: 0,
transitionDuration: '0s !important',
'& > span': {
fontWeight: 'normal',
},
},
});

export const Chip = ({ label, selected, onClick }: ChipProps) => {
const classes = useStyles();

return (
<MaterialChip
className={classes.chip}
label={label}
color={selected ? 'primary' : undefined}
variant={selected ? undefined : 'outlined'}
onClick={onClick}
/>
);
};
1 change: 1 addition & 0 deletions plugins/cad/src/components/Controls/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
export { Autocomplete } from './Autocomplete';
export { ConfirmationDialog } from './ConfirmationDialog';
export { Checkbox } from './Checkbox';
export { Chip } from './Chip';
export { IconButton } from './IconButton';
export { MultiSelect } from './MultiSelect';
export { PackageIcon } from './PackageIcon';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ import { makeStyles } from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import React, { Fragment } from 'react';
import { packagesRouteRef } from '../../../routes';
import { PackageRevisionLifecycle } from '../../../types/PackageRevision';
import { Repository } from '../../../types/Repository';
import { PackageSummary } from '../../../utils/packageSummary';
import {
filterPackageSummaries,
PackageSummary,
} from '../../../utils/packageSummary';
import {
isRepositoryReady,
RepositoryContentDetails,
Expand Down Expand Up @@ -71,29 +73,6 @@ const getActions = (
);
};

const getPublishedPackages = (packages: PackageSummary[]): PackageSummary[] => {
return packages.filter(summary => !!summary.latestPublishedRevision);
};

const getProposedPackages = (packages: PackageSummary[]): PackageSummary[] => {
return packages.filter(
summary =>
summary.latestRevision.spec.lifecycle ===
PackageRevisionLifecycle.PROPOSED,
);
};

const getDraftPackages = (packages: PackageSummary[]): PackageSummary[] => {
return packages.filter(
summary =>
summary.latestRevision.spec.lifecycle === PackageRevisionLifecycle.DRAFT,
);
};

const getUpgradePackages = (packages: PackageSummary[]): PackageSummary[] => {
return packages.filter(summary => summary.isUpgradeAvailable);
};

export const ContentInfoCard = ({
contentType,
repositories,
Expand All @@ -109,10 +88,12 @@ export const ContentInfoCard = ({
repository => !isRepositoryReady(repository),
);

const published = getPublishedPackages(packages).length;
const upgradesAvailable = getUpgradePackages(packages).length;
const pendingReview = getDraftPackages(packages).length;
const drafts = getProposedPackages(packages).length;
const published = filterPackageSummaries(packages, { isPublished: true });
const upgradesAvailable = filterPackageSummaries(packages, {
isUpgradeAvailable: true,
});
const pendingReview = filterPackageSummaries(packages, { isProposed: true });
const drafts = filterPackageSummaries(packages, { isDraft: true });

const subheader = `${repositories.length} repositories registered`;

Expand All @@ -137,7 +118,7 @@ export const ContentInfoCard = ({

{repositories.length > 0 && (
<Alert severity="success">
{published} {contentTypeLowerCase}s published
{published.length} {contentTypeLowerCase}s published
</Alert>
)}

Expand All @@ -147,19 +128,23 @@ export const ContentInfoCard = ({
</Alert>
))}

{upgradesAvailable > 0 && (
{upgradesAvailable.length > 0 && (
<Alert severity="info">
{upgradesAvailable} {contentTypeLowerCase}s with upgrades available
{upgradesAvailable.length} {contentTypeLowerCase}s with upgrades
available
</Alert>
)}

{pendingReview > 0 && (
{pendingReview.length > 0 && (
<Alert severity="info">
{pendingReview} {contentTypeLowerCase} revisions pending review
{pendingReview.length} {contentTypeLowerCase} revisions pending
review
</Alert>
)}

{drafts > 0 && <Alert severity="info">{drafts} draft revisions</Alert>}
{drafts.length > 0 && (
<Alert severity="info">{drafts.length} draft revisions</Alert>
)}
</div>
</InfoCard>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@
* limitations under the License.
*/

import { makeStyles } from '@material-ui/core';
import { Card, CardContent, makeStyles } from '@material-ui/core';
import Alert from '@material-ui/lab/Alert';
import React, { Fragment } from 'react';
import React, { Fragment, useState } from 'react';
import { Function } from '../../../types/Function';
import { Repository, RepositoryContent } from '../../../types/Repository';
import { isConfigSyncEnabled } from '../../../utils/featureFlags';
import { PackageSummary } from '../../../utils/packageSummary';
import {
filterPackageSummaries,
PackageSummary,
} from '../../../utils/packageSummary';
import {
isReadOnlyRepository,
RepositoryContentDetails,
} from '../../../utils/repository';
import { toLowerCase } from '../../../utils/string';
import { Chip } from '../../Controls';
import { PackagesTable } from '../../PackagesTable';
import { FunctionsTable } from '../components/FunctionsTable';

Expand All @@ -38,12 +42,40 @@ type PackagesTabContentProps = {
oneRepositoryFocus?: boolean;
};

enum Display {
ALL = 'all',
PUBLISHED = 'published',
PROPOSED = 'proposed',
UPGRADE = 'upgrade',
DRAFT = 'draft',
}

const useStyles = makeStyles({
messageBanner: {
marginBottom: '16px',
root: {
'& > *:not(:last-child)': {
marginBottom: '16px',
},
},
});

const getDisplapyPackages = (
packages: PackageSummary[],
display: string,
): PackageSummary[] => {
switch (display) {
case Display.PUBLISHED:
return filterPackageSummaries(packages, { isPublished: true });
case Display.PROPOSED:
return filterPackageSummaries(packages, { isProposed: true });
case Display.UPGRADE:
return filterPackageSummaries(packages, { isUpgradeAvailable: true });
case Display.DRAFT:
return filterPackageSummaries(packages, { isDraft: true });
default:
return packages;
}
};

export const PackagesTabContent = ({
packageDescriptor,
repositories,
Expand All @@ -53,6 +85,17 @@ export const PackagesTabContent = ({
oneRepositoryFocus,
}: PackagesTabContentProps) => {
const classes = useStyles();

const [display, setDisplay] = useState<string>(Display.ALL);

const getChip = (label: string, value: string): JSX.Element => (
<Chip
label={label}
selected={display === value}
onClick={() => setDisplay(value)}
/>
);

const pluralPackageDescriptor = `${packageDescriptor}s`;
const pluralPackageDescriptorLowerCase = toLowerCase(pluralPackageDescriptor);

Expand All @@ -64,14 +107,16 @@ export const PackagesTabContent = ({
const showPackagesTable = repositoryContent === RepositoryContent.PACKAGE;
const showFunctionsTable = repositoryContent === RepositoryContent.FUNCTION;

const displayPackages = getDisplapyPackages(packages, display);

if (packagesError) {
return <Alert severity="error">{packagesError.message}</Alert>;
}

return (
<Fragment>
<div className={classes.root}>
{isReadOnly && (
<Alert className={classes.messageBanner} severity="info">
<Alert severity="info">
{oneRepositoryFocus && (
<Fragment>
This repository is read-only. You will not be able to add or make
Expand All @@ -91,23 +136,36 @@ export const PackagesTabContent = ({
)}

{showPackagesTable && (
<PackagesTable
title={pluralPackageDescriptor}
packages={packages}
showRepositoryColumn={!oneRepositoryFocus}
showSyncStatusColumn={
isConfigSyncEnabled() && !!contentDetails.isDeployment
}
/>
)}
<Fragment>
<Card>
<CardContent>
<div>
{getChip(`Show All ${pluralPackageDescriptor}`, Display.ALL)}
{getChip('Published', Display.PUBLISHED)}
{getChip('Upgrade Available', Display.UPGRADE)}
{getChip('Pending Review', Display.PROPOSED)}
{getChip('Draft', Display.DRAFT)}
</div>
</CardContent>
</Card>

<PackagesTable
title={pluralPackageDescriptor}
packages={displayPackages}
showRepositoryColumn={!oneRepositoryFocus}
showSyncStatusColumn={
isConfigSyncEnabled() && !!contentDetails.isDeployment
}
/>
</Fragment>
)}
{showFunctionsTable && (
<FunctionsTable
title={pluralPackageDescriptor}
functions={functions}
showLatestVersionOnly
/>
)}
</Fragment>
</div>
);
};
39 changes: 36 additions & 3 deletions plugins/cad/src/utils/packageSummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
*/

import { groupBy } from 'lodash';
import { PackageRevision } from '../types/PackageRevision';
import {
PackageRevision,
PackageRevisionLifecycle,
} from '../types/PackageRevision';
import { Repository } from '../types/Repository';
import { RepositorySummary } from '../types/RepositorySummary';
import { RootSync } from '../types/RootSync';
Expand Down Expand Up @@ -180,9 +183,39 @@ export const updatePackageSummariesSyncStatus = (

export const filterPackageSummaries = (
packageSummaries: PackageSummary[],
{ repository }: { repository: Repository },
{
repository,
isPublished,
isProposed,
isDraft,
isUpgradeAvailable,
}: {
repository?: Repository;
isPublished?: boolean;
isProposed?: boolean;
isDraft?: boolean;
isUpgradeAvailable?: boolean;
},
): PackageSummary[] => {
const repositoryFilter = (summary: PackageSummary): boolean =>
!repository || summary.repository === repository;
const publishedFilter = (summary: PackageSummary): boolean =>
!isPublished || !!summary.latestPublishedRevision;
const proposedFilter = (summary: PackageSummary): boolean =>
!isProposed ||
summary.latestRevision.spec.lifecycle === PackageRevisionLifecycle.PROPOSED;
const draftFilter = (summary: PackageSummary): boolean =>
!isDraft ||
summary.latestRevision.spec.lifecycle === PackageRevisionLifecycle.DRAFT;
const upgradeAvailableFilter = (summary: PackageSummary): boolean =>
!isUpgradeAvailable || !!summary.isUpgradeAvailable;

return packageSummaries.filter(
packageSummary => packageSummary.repository === repository,
summary =>
repositoryFilter(summary) &&
publishedFilter(summary) &&
proposedFilter(summary) &&
draftFilter(summary) &&
upgradeAvailableFilter(summary),
);
};

0 comments on commit 39c80e9

Please sign in to comment.