start notification template list

This commit is contained in:
Keith Grant 2020-07-20 16:27:38 -07:00
parent 0e730311bb
commit fbd1147cff
6 changed files with 270 additions and 21 deletions

View File

@ -0,0 +1,5 @@
import React from 'react';
export default function NotificationTemplate() {
return <div />;
}

View File

@ -0,0 +1,5 @@
import React from 'react';
export default function NotificationTemplateAdd() {
return <div />;
}

View File

@ -0,0 +1,170 @@
import React, { useCallback, useEffect } from 'react';
import { useLocation, useRouteMatch } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Card, PageSection } from '@patternfly/react-core';
import { NotificationTemplatesAPI } from '../../../api';
import PaginatedDataList, {
ToolbarAddButton,
ToolbarDeleteButton,
} from '../../../components/PaginatedDataList';
import AlertModal from '../../../components/AlertModal';
import ErrorDetail from '../../../components/ErrorDetail';
import DataListToolbar from '../../../components/DataListToolbar';
import NotificationTemplateListItem from './NotificationTemplateListItem';
import useRequest, { useDeleteItems } from '../../../util/useRequest';
import useSelected from '../../../util/useSelected';
import { getQSConfig, parseQueryString } from '../../../util/qs';
const QS_CONFIG = getQSConfig('notification-templates', {
page: 1,
page_size: 20,
order_by: 'name',
});
function NotificationTemplatesList({ i18n }) {
const location = useLocation();
const match = useRouteMatch();
const addUrl = `${match.url}/add`;
const {
result: { templates, count, actions },
error: contentError,
isLoading: isTemplatesLoading,
request: fetchTemplates,
} = useRequest(
useCallback(async () => {
const params = parseQueryString(QS_CONFIG, location.search);
const responses = await Promise.all([
NotificationTemplatesAPI.read(params),
NotificationTemplatesAPI.readOptions(),
]);
return {
templates: responses[0].data.results,
count: responses[0].data.count,
actions: responses[1].data.actions,
};
}, [location]),
{
templates: [],
count: 0,
actions: {},
}
);
useEffect(() => {
fetchTemplates();
}, [fetchTemplates]);
const { selected, isAllSelected, handleSelect, setSelected } = useSelected(
templates
);
const {
isLoading: isDeleteLoading,
deleteItems: deleteTemplates,
deletionError,
clearDeletionError,
} = useDeleteItems(
useCallback(async () => {
return Promise.all(
selected.map(({ id }) => NotificationTemplatesAPI.destroy(id))
);
}, [selected]),
{
qsConfig: QS_CONFIG,
allItemsSelected: isAllSelected,
fetchItems: fetchTemplates,
}
);
const handleDelete = async () => {
await deleteTemplates();
setSelected([]);
};
const canAdd = actions && actions.POST;
return (
<>
<PageSection>
<Card>
<PaginatedDataList
contentError={contentError}
hasContentLoading={isTemplatesLoading || isDeleteLoading}
items={templates}
itemCount={count}
pluralizedItemName={i18n._(t`Notification Templates`)}
qsConfig={QS_CONFIG}
onRowClick={handleSelect}
toolbarSearchColumns={[
{
name: i18n._(t`Name`),
key: 'name',
isDefault: true,
},
{
name: i18n._(t`Created By (Username)`),
key: 'created_by__username',
},
{
name: i18n._(t`Modified By (Username)`),
key: 'modified_by__username',
},
]}
toolbarSortColumns={[
{
name: i18n._(t`Name`),
key: 'name',
},
]}
renderToolbar={props => (
<DataListToolbar
{...props}
showSelectAll
isAllSelected={isAllSelected}
onSelectAll={() => setSelected([...templates])}
qsConfig={QS_CONFIG}
additionalControls={[
...(canAdd
? [<ToolbarAddButton key="add" linkTo={addUrl} />]
: []),
<ToolbarDeleteButton
key="delete"
onDelete={handleDelete}
itemsToDelete={selected}
pluralizedItemName="Organizations"
/>,
]}
/>
)}
renderItem={template => (
<NotificationTemplateListItem
key={template.id}
template={template}
detailUrl={`${match.url}/${template.id}`}
isSelected={selected.some(row => row.id === template.id)}
onSelect={() => handleSelect(template)}
/>
)}
emptyStateControls={
canAdd ? <ToolbarAddButton key="add" linkTo={addUrl} /> : null
}
/>
</Card>
</PageSection>
<AlertModal
isOpen={deletionError}
variant="error"
title={i18n._(t`Error!`)}
onClose={clearDeletionError}
>
{i18n._(t`Failed to delete one or more organizations.`)}
<ErrorDetail error={deletionError} />
</AlertModal>
</>
);
}
export default withI18n()(NotificationTemplatesList);

View File

@ -0,0 +1,45 @@
import React from 'react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Link } from 'react-router-dom';
import {
Badge as PFBadge,
Button,
DataListAction as _DataListAction,
DataListCheck,
DataListItem,
DataListItemCells,
DataListItemRow,
Tooltip,
} from '@patternfly/react-core';
import DataListCell from '../../../components/DataListCell';
export default function NotificationTemplatesListItem({
template,
detailUrl,
isSelected,
onSelect,
}) {
const labelId = `check-action-${template.id}`;
return (
<DataListItem key={template.id} aria-labelledby={labelId} id={template.id}>
<DataListItemRow>
<DataListCheck
id={`select-template-${template.id}`}
checked={isSelected}
onChange={onSelect}
aria-labelledby={labelId}
/>
<DataListItemCells
dataListCells={[
<DataListCell key="name" id={labelId}>
<Link to={detailUrl}>
<b>{template.name}</b>
</Link>
</DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
);
}

View File

@ -0,0 +1,4 @@
import NotificationTemplatesList from './NotificationTemplateList';
export default NotificationTemplatesList;
export { default as NotificationTemplatesListItem } from './NotificationTemplateListItem';

View File

@ -1,28 +1,48 @@
import React, { Component, Fragment } from 'react';
import React, { useState } from 'react';
import { Route, Switch, useRouteMatch } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
Title,
} from '@patternfly/react-core';
import NotificationTemplateList from './NotificationTemplateList';
import NotificationTemplateAdd from './NotificationTemplateAdd';
import NotificationTemplate from './NotificationTemplate';
import Breadcrumbs from '../../components/Breadcrumbs/Breadcrumbs';
class NotificationTemplates extends Component {
render() {
const { i18n } = this.props;
const { light } = PageSectionVariants;
function NotificationTemplates({ i18n }) {
const match = useRouteMatch();
const [breadcrumbConfig, setBreadcrumbConfig] = useState({
'/notification_templates': i18n._(t`Notification Templates`),
'/notification_templates/add': i18n._(t`Create New Notification Template`),
});
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl" headingLevel="h2">
{i18n._(t`Notification Templates`)}
</Title>
</PageSection>
<PageSection />
</Fragment>
);
}
const updateBreadcrumbConfig = notification => {
const { id } = notification;
setBreadcrumbConfig({
'/notification_templates': i18n._(t`Notification Templates`),
'/notification_templates/add': i18n._(
t`Create New Notification Template`
),
[`/notification_templates/${id}`]: notification.name,
[`/notification_templates/${id}/edit`]: i18n._(t`Edit Details`),
[`/notification_templates/${id}/details`]: i18n._(t`Details`),
});
};
return (
<>
<Breadcrumbs breadcrumbConfig={breadcrumbConfig} />
<Switch>
<Route path={`${match.url}/add`}>
<NotificationTemplateAdd />
</Route>
<Route path={`${match.url}/:id`}>
<NotificationTemplate setBreadcrumb={updateBreadcrumbConfig} />
</Route>
<Route path={`${match.url}`}>
<NotificationTemplateList />
</Route>
</Switch>
</>
);
}
export default withI18n()(NotificationTemplates);