mirror of
https://github.com/ansible/awx.git
synced 2026-03-13 23:17:32 -02:30
add patternfly tables; add PaginatedTable
This commit is contained in:
52
awx/ui_next/package-lock.json
generated
52
awx/ui_next/package-lock.json
generated
@@ -3194,6 +3194,58 @@
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.7.22.tgz",
|
||||
"integrity": "sha512-ojNuSNJx6CkNtsSFseZ2SJEVyzPMFYh0jOs204ICzYM1+fn9acsIi3Co0bcskFRzw8F6e2/x+8uVNx6QI8elxg=="
|
||||
},
|
||||
"@patternfly/react-table": {
|
||||
"version": "4.19.15",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.19.15.tgz",
|
||||
"integrity": "sha512-WeeiOlJs96QfT7/TChpaCUAsl0hsWsLelJIR68b0LA+gzTEJzaXn0m5NL9ht4LL3edT4hwMz0jVz98xkStmvBg==",
|
||||
"requires": {
|
||||
"@patternfly/patternfly": "4.59.1",
|
||||
"@patternfly/react-core": "^4.75.10",
|
||||
"@patternfly/react-icons": "^4.7.16",
|
||||
"@patternfly/react-styles": "^4.7.13",
|
||||
"@patternfly/react-tokens": "^4.9.16",
|
||||
"lodash": "^4.17.19",
|
||||
"tslib": "1.13.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@patternfly/react-core": {
|
||||
"version": "4.79.2",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.79.2.tgz",
|
||||
"integrity": "sha512-TCWi5Hu8+gpqFVAL4ZMXCRLbRfayM7wJ8+/Ob4rfhC61qm36CZNAcqWOmuV8bghOzB29INUMNShggtuiUa5mkg==",
|
||||
"requires": {
|
||||
"@patternfly/react-icons": "^4.7.18",
|
||||
"@patternfly/react-styles": "^4.7.16",
|
||||
"@patternfly/react-tokens": "^4.9.18",
|
||||
"focus-trap": "4.0.2",
|
||||
"react-dropzone": "9.0.0",
|
||||
"tippy.js": "5.1.2",
|
||||
"tslib": "1.13.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@patternfly/react-icons": {
|
||||
"version": "4.7.18",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.7.18.tgz",
|
||||
"integrity": "sha512-Kd0JjeVCESpMJGb5ZkLXvAdCuklV9dYGUkcTO18WMyXQ57s9+xXjVA77wojmp6Ru1ZCWOP5bLXZOKmwVnOfUpQ=="
|
||||
},
|
||||
"@patternfly/react-tokens": {
|
||||
"version": "4.9.18",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.9.18.tgz",
|
||||
"integrity": "sha512-zQfqwKtoz1hDngyiGnF6oHeESDtgNY6C79Db97JxMMuRBV7i+5f6uC/DrYhcqNtqHA7mxrVJg0SM1xnPSAW9lA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@patternfly/react-styles": {
|
||||
"version": "4.7.16",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.7.16.tgz",
|
||||
"integrity": "sha512-bJmRrYKXgHGPPwLHg/gy1tDb/qEV6JpFLgkelLuz38czXeBnPpAUn9yKry3wNr95VQGERT6FcLsWjXKPY1x42Q=="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@patternfly/react-tokens": {
|
||||
"version": "4.9.22",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.9.22.tgz",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"@patternfly/patternfly": "4.70.2",
|
||||
"@patternfly/react-core": "4.84.3",
|
||||
"@patternfly/react-icons": "4.7.22",
|
||||
"@patternfly/react-table": "^4.19.15",
|
||||
"ansi-to-html": "^0.6.11",
|
||||
"axios": "^0.18.1",
|
||||
"codemirror": "^5.47.0",
|
||||
|
||||
33
awx/ui_next/src/components/PaginatedTable/ActionsTd.jsx
Normal file
33
awx/ui_next/src/components/PaginatedTable/ActionsTd.jsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import 'styled-components/macro';
|
||||
import React from 'react';
|
||||
import { Td } from '@patternfly/react-table';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
// table cells will automatically grow beyond specified width to accomodate
|
||||
// multiple action buttons
|
||||
const ActionsGrid = styled.div`
|
||||
display: grid;
|
||||
grid-gap: 16px;
|
||||
align-items: center;
|
||||
|
||||
${props => {
|
||||
const columns = '40px '.repeat(props.numActions || 1);
|
||||
return css`
|
||||
grid-template-columns: ${columns};
|
||||
`;
|
||||
}}
|
||||
`;
|
||||
|
||||
export default function ActionsTd({ numActions = 1, children }) {
|
||||
const width = numActions * 40;
|
||||
return (
|
||||
<Td
|
||||
css={`
|
||||
text-align: right;
|
||||
--pf-c-table--cell--Width: ${width}px;
|
||||
`}
|
||||
>
|
||||
<ActionsGrid numActions={numActions}>{children}</ActionsGrid>
|
||||
</Td>
|
||||
);
|
||||
}
|
||||
227
awx/ui_next/src/components/PaginatedTable/PaginatedTable.jsx
Normal file
227
awx/ui_next/src/components/PaginatedTable/PaginatedTable.jsx
Normal file
@@ -0,0 +1,227 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { TableComposable, Tbody } from '@patternfly/react-table';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import ListHeader from '../ListHeader';
|
||||
import ContentEmpty from '../ContentEmpty';
|
||||
import ContentError from '../ContentError';
|
||||
import ContentLoading from '../ContentLoading';
|
||||
import Pagination from '../Pagination';
|
||||
import DataListToolbar from '../DataListToolbar';
|
||||
|
||||
import {
|
||||
encodeNonDefaultQueryString,
|
||||
parseQueryString,
|
||||
replaceParams,
|
||||
} from '../../util/qs';
|
||||
|
||||
import { QSConfig, SearchColumns, SortColumns } from '../../types';
|
||||
|
||||
import PaginatedTableRow from './PaginatedTableRow';
|
||||
|
||||
class PaginatedTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleSetPage = this.handleSetPage.bind(this);
|
||||
this.handleSetPageSize = this.handleSetPageSize.bind(this);
|
||||
this.handleListItemSelect = this.handleListItemSelect.bind(this);
|
||||
}
|
||||
|
||||
handleListItemSelect = (id = 0) => {
|
||||
const { items, onRowClick } = this.props;
|
||||
const match = items.find(item => item.id === Number(id));
|
||||
onRowClick(match);
|
||||
};
|
||||
|
||||
handleSetPage(event, pageNumber) {
|
||||
const { history, qsConfig } = this.props;
|
||||
const { search } = history.location;
|
||||
const oldParams = parseQueryString(qsConfig, search);
|
||||
this.pushHistoryState(replaceParams(oldParams, { page: pageNumber }));
|
||||
}
|
||||
|
||||
handleSetPageSize(event, pageSize, page) {
|
||||
const { history, qsConfig } = this.props;
|
||||
const { search } = history.location;
|
||||
const oldParams = parseQueryString(qsConfig, search);
|
||||
this.pushHistoryState(
|
||||
replaceParams(oldParams, { page_size: pageSize, page })
|
||||
);
|
||||
}
|
||||
|
||||
pushHistoryState(params) {
|
||||
const { history, qsConfig } = this.props;
|
||||
const { pathname } = history.location;
|
||||
const encodedParams = encodeNonDefaultQueryString(qsConfig, params);
|
||||
history.push(encodedParams ? `${pathname}?${encodedParams}` : pathname);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
contentError,
|
||||
hasContentLoading,
|
||||
emptyStateControls,
|
||||
items,
|
||||
itemCount,
|
||||
qsConfig,
|
||||
headerRow,
|
||||
renderRow,
|
||||
toolbarSearchColumns,
|
||||
toolbarSearchableKeys,
|
||||
toolbarRelatedSearchableKeys,
|
||||
toolbarSortColumns,
|
||||
pluralizedItemName,
|
||||
showPageSizeOptions,
|
||||
location,
|
||||
i18n,
|
||||
renderToolbar,
|
||||
} = this.props;
|
||||
const searchColumns = toolbarSearchColumns.length
|
||||
? toolbarSearchColumns
|
||||
: [
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true,
|
||||
},
|
||||
];
|
||||
const sortColumns = toolbarSortColumns.length
|
||||
? toolbarSortColumns
|
||||
: [
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
},
|
||||
];
|
||||
const queryParams = parseQueryString(qsConfig, location.search);
|
||||
|
||||
const dataListLabel = i18n._(t`${pluralizedItemName} List`);
|
||||
const emptyContentMessage = i18n._(
|
||||
t`Please add ${pluralizedItemName} to populate this list `
|
||||
);
|
||||
const emptyContentTitle = i18n._(t`No ${pluralizedItemName} Found `);
|
||||
|
||||
let Content;
|
||||
if (hasContentLoading && items.length <= 0) {
|
||||
Content = <ContentLoading />;
|
||||
} else if (contentError) {
|
||||
Content = <ContentError error={contentError} />;
|
||||
} else if (items.length <= 0) {
|
||||
Content = (
|
||||
<ContentEmpty title={emptyContentTitle} message={emptyContentMessage} />
|
||||
);
|
||||
} else {
|
||||
Content = (
|
||||
<TableComposable
|
||||
aria-label={dataListLabel}
|
||||
onSelectDataListItem={id => this.handleListItemSelect(id)}
|
||||
>
|
||||
{headerRow}
|
||||
<Tbody>{items.map(renderRow)}</Tbody>
|
||||
</TableComposable>
|
||||
);
|
||||
}
|
||||
|
||||
const ToolbarPagination = (
|
||||
<Pagination
|
||||
isCompact
|
||||
dropDirection="down"
|
||||
itemCount={itemCount}
|
||||
page={queryParams.page || 1}
|
||||
perPage={queryParams.page_size}
|
||||
perPageOptions={
|
||||
showPageSizeOptions
|
||||
? [
|
||||
{ title: '5', value: 5 },
|
||||
{ title: '10', value: 10 },
|
||||
{ title: '20', value: 20 },
|
||||
{ title: '50', value: 50 },
|
||||
]
|
||||
: []
|
||||
}
|
||||
onSetPage={this.handleSetPage}
|
||||
onPerPageSelect={this.handleSetPageSize}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ListHeader
|
||||
itemCount={itemCount}
|
||||
renderToolbar={renderToolbar}
|
||||
emptyStateControls={emptyStateControls}
|
||||
searchColumns={searchColumns}
|
||||
sortColumns={sortColumns}
|
||||
searchableKeys={toolbarSearchableKeys}
|
||||
relatedSearchableKeys={toolbarRelatedSearchableKeys}
|
||||
qsConfig={qsConfig}
|
||||
pagination={ToolbarPagination}
|
||||
/>
|
||||
{Content}
|
||||
{items.length ? (
|
||||
<Pagination
|
||||
variant="bottom"
|
||||
itemCount={itemCount}
|
||||
page={queryParams.page || 1}
|
||||
perPage={queryParams.page_size}
|
||||
perPageOptions={
|
||||
showPageSizeOptions
|
||||
? [
|
||||
{ title: '5', value: 5 },
|
||||
{ title: '10', value: 10 },
|
||||
{ title: '20', value: 20 },
|
||||
{ title: '50', value: 50 },
|
||||
]
|
||||
: []
|
||||
}
|
||||
onSetPage={this.handleSetPage}
|
||||
onPerPageSelect={this.handleSetPageSize}
|
||||
/>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const Item = PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
name: PropTypes.string,
|
||||
});
|
||||
|
||||
PaginatedTable.propTypes = {
|
||||
items: PropTypes.arrayOf(Item).isRequired,
|
||||
itemCount: PropTypes.number.isRequired,
|
||||
pluralizedItemName: PropTypes.string,
|
||||
qsConfig: QSConfig.isRequired,
|
||||
renderRow: PropTypes.func,
|
||||
toolbarSearchColumns: SearchColumns,
|
||||
toolbarSearchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
toolbarRelatedSearchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
toolbarSortColumns: SortColumns,
|
||||
showPageSizeOptions: PropTypes.bool,
|
||||
renderToolbar: PropTypes.func,
|
||||
hasContentLoading: PropTypes.bool,
|
||||
contentError: PropTypes.shape(),
|
||||
onRowClick: PropTypes.func,
|
||||
};
|
||||
|
||||
PaginatedTable.defaultProps = {
|
||||
hasContentLoading: false,
|
||||
contentError: null,
|
||||
toolbarSearchColumns: [],
|
||||
toolbarSearchableKeys: [],
|
||||
toolbarRelatedSearchableKeys: [],
|
||||
toolbarSortColumns: [],
|
||||
pluralizedItemName: 'Items',
|
||||
showPageSizeOptions: true,
|
||||
renderRow: item => <PaginatedTableRow key={item.id} item={item} />,
|
||||
renderToolbar: props => <DataListToolbar {...props} />,
|
||||
onRowClick: () => null,
|
||||
};
|
||||
|
||||
export { PaginatedTable as _PaginatedTable };
|
||||
export default withI18n()(withRouter(PaginatedTable));
|
||||
@@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
DataListItem,
|
||||
DataListItemRow,
|
||||
DataListItemCells,
|
||||
TextContent,
|
||||
} from '@patternfly/react-core';
|
||||
import styled from 'styled-components';
|
||||
import DataListCell from '../DataListCell';
|
||||
|
||||
const DetailWrapper = styled(TextContent)`
|
||||
display: grid;
|
||||
grid-template-columns:
|
||||
minmax(70px, max-content)
|
||||
repeat(auto-fit, minmax(60px, max-content));
|
||||
grid-gap: 10px;
|
||||
`;
|
||||
|
||||
export default function PaginatedDataListItem({ item }) {
|
||||
return (
|
||||
<DataListItem
|
||||
aria-labelledby={`items-list-item-${item.id}`}
|
||||
key={item.id}
|
||||
id={`${item.id}`}
|
||||
>
|
||||
<DataListItemRow>
|
||||
<DataListItemCells
|
||||
dataListCells={[
|
||||
<DataListCell key="name">
|
||||
<DetailWrapper>
|
||||
<Link to={{ pathname: item.url }}>
|
||||
<b id={`items-list-item-${item.id}`}>{item.name}</b>
|
||||
</Link>
|
||||
</DetailWrapper>
|
||||
</DataListCell>,
|
||||
]}
|
||||
/>
|
||||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
);
|
||||
}
|
||||
5
awx/ui_next/src/components/PaginatedTable/index.js
Normal file
5
awx/ui_next/src/components/PaginatedTable/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export { default } from './PaginatedTable';
|
||||
export { default as PaginatedTableRow } from './PaginatedTableRow';
|
||||
export { default as ActionsTd } from './ActionsTd';
|
||||
// export { default as ToolbarDeleteButton } from './ToolbarDeleteButton';
|
||||
// export { default as ToolbarAddButton } from './ToolbarAddButton';
|
||||
@@ -3,16 +3,18 @@ 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 { Thead, Tr, Th } from '@patternfly/react-table';
|
||||
|
||||
import { OrganizationsAPI } from '../../../api';
|
||||
import useRequest, { useDeleteItems } from '../../../util/useRequest';
|
||||
import AlertModal from '../../../components/AlertModal';
|
||||
import DataListToolbar from '../../../components/DataListToolbar';
|
||||
import ErrorDetail from '../../../components/ErrorDetail';
|
||||
import PaginatedDataList, {
|
||||
import {
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
} from '../../../components/PaginatedDataList';
|
||||
import PaginatedTable from '../../../components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from '../../../util/qs';
|
||||
import OrganizationListItem from './OrganizationListItem';
|
||||
|
||||
@@ -117,7 +119,7 @@ function OrganizationsList({ i18n }) {
|
||||
<>
|
||||
<PageSection>
|
||||
<Card>
|
||||
<PaginatedDataList
|
||||
<PaginatedTable
|
||||
contentError={contentError}
|
||||
hasContentLoading={hasContentLoading}
|
||||
items={organizations}
|
||||
@@ -152,12 +154,27 @@ function OrganizationsList({ i18n }) {
|
||||
]}
|
||||
toolbarSearchableKeys={searchableKeys}
|
||||
toolbarRelatedSearchableKeys={relatedSearchableKeys}
|
||||
headerRow={
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th
|
||||
select={{
|
||||
onSelect: handleSelectAll,
|
||||
isSelected: isAllSelected,
|
||||
}}
|
||||
/>
|
||||
<Th>{i18n._(t`Name`)}</Th>
|
||||
<Th>{i18n._(t`Members`)}</Th>
|
||||
<Th>{i18n._(t`Teams`)}</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
}
|
||||
renderToolbar={props => (
|
||||
<DataListToolbar
|
||||
{...props}
|
||||
showSelectAll
|
||||
isAllSelected={isAllSelected}
|
||||
onSelectAll={handleSelectAll}
|
||||
// showSelectAll
|
||||
// isAllSelected={isAllSelected}
|
||||
// onSelectAll={handleSelectAll}
|
||||
qsConfig={QS_CONFIG}
|
||||
additionalControls={[
|
||||
...(canAdd
|
||||
@@ -172,10 +189,11 @@ function OrganizationsList({ i18n }) {
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
renderItem={o => (
|
||||
renderRow={(o, index) => (
|
||||
<OrganizationListItem
|
||||
key={o.id}
|
||||
organization={o}
|
||||
rowIndex={index}
|
||||
detailUrl={`${match.url}/${o.id}`}
|
||||
isSelected={selected.some(row => row.id === o.id)}
|
||||
onSelect={() => handleSelect(o)}
|
||||
|
||||
@@ -2,105 +2,57 @@ import React from 'react';
|
||||
import { string, bool, func } from 'prop-types';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import {
|
||||
Badge as PFBadge,
|
||||
Button,
|
||||
DataListAction as _DataListAction,
|
||||
DataListCheck,
|
||||
DataListItem,
|
||||
DataListItemCells,
|
||||
DataListItemRow,
|
||||
Tooltip,
|
||||
} from '@patternfly/react-core';
|
||||
|
||||
import { Button, Tooltip } from '@patternfly/react-core';
|
||||
import { Tr, Td } from '@patternfly/react-table';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import { PencilAltIcon } from '@patternfly/react-icons';
|
||||
import DataListCell from '../../../components/DataListCell';
|
||||
import { ActionsTd } from '../../../components/PaginatedTable';
|
||||
|
||||
import { Organization } from '../../../types';
|
||||
|
||||
const Badge = styled(PFBadge)`
|
||||
margin-left: 8px;
|
||||
`;
|
||||
|
||||
const ListGroup = styled.span`
|
||||
margin-left: 24px;
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const DataListAction = styled(_DataListAction)`
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-gap: 16px;
|
||||
grid-template-columns: 40px;
|
||||
`;
|
||||
|
||||
function OrganizationListItem({
|
||||
organization,
|
||||
isSelected,
|
||||
onSelect,
|
||||
rowIndex,
|
||||
detailUrl,
|
||||
i18n,
|
||||
}) {
|
||||
const labelId = `check-action-${organization.id}`;
|
||||
return (
|
||||
<DataListItem
|
||||
key={organization.id}
|
||||
aria-labelledby={labelId}
|
||||
id={`${organization.id}`}
|
||||
>
|
||||
<DataListItemRow>
|
||||
<DataListCheck
|
||||
id={`select-organization-${organization.id}`}
|
||||
checked={isSelected}
|
||||
onChange={onSelect}
|
||||
aria-labelledby={labelId}
|
||||
/>
|
||||
<DataListItemCells
|
||||
dataListCells={[
|
||||
<DataListCell key="name" id={labelId}>
|
||||
<Link to={`${detailUrl}`}>
|
||||
<b>{organization.name}</b>
|
||||
</Link>
|
||||
</DataListCell>,
|
||||
<DataListCell key="related-field-counts">
|
||||
<ListGroup>
|
||||
{i18n._(t`Members`)}
|
||||
<Badge isRead>
|
||||
{organization.summary_fields.related_field_counts.users}
|
||||
</Badge>
|
||||
</ListGroup>
|
||||
<ListGroup>
|
||||
{i18n._(t`Teams`)}
|
||||
<Badge isRead>
|
||||
{organization.summary_fields.related_field_counts.teams}
|
||||
</Badge>
|
||||
</ListGroup>
|
||||
</DataListCell>,
|
||||
]}
|
||||
/>
|
||||
<DataListAction aria-label="actions" aria-labelledby={labelId}>
|
||||
{organization.summary_fields.user_capabilities.edit ? (
|
||||
<Tooltip content={i18n._(t`Edit Organization`)} position="top">
|
||||
<Button
|
||||
aria-label={i18n._(t`Edit Organization`)}
|
||||
variant="plain"
|
||||
component={Link}
|
||||
to={`/organizations/${organization.id}/edit`}
|
||||
>
|
||||
<PencilAltIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</DataListAction>
|
||||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
<Tr id={`${organization.id}`}>
|
||||
<Td
|
||||
select={{
|
||||
rowIndex,
|
||||
isSelected,
|
||||
onSelect,
|
||||
disable: false,
|
||||
}}
|
||||
/>
|
||||
<Td id={labelId}>
|
||||
<Link to={`${detailUrl}`}>
|
||||
<b>{organization.name}</b>
|
||||
</Link>
|
||||
</Td>
|
||||
<Td>{organization.summary_fields.related_field_counts.users}</Td>
|
||||
<Td>{organization.summary_fields.related_field_counts.teams}</Td>
|
||||
<ActionsTd numActions={2}>
|
||||
{organization.summary_fields.user_capabilities.edit ? (
|
||||
<Tooltip content={i18n._(t`Edit Organization`)} position="top">
|
||||
<Button
|
||||
aria-label={i18n._(t`Edit Organization`)}
|
||||
variant="plain"
|
||||
component={Link}
|
||||
to={`/organizations/${organization.id}/edit`}
|
||||
>
|
||||
<PencilAltIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</ActionsTd>
|
||||
</Tr>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user