mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-15 01:16:22 +02:00
feat: empty state application list improvements (#6579)
This commit is contained in:
parent
45634689f8
commit
59ee0b3bbe
@ -1,201 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Avatar, CircularProgress, Icon, Link } from '@mui/material';
|
||||
import Warning from '@mui/icons-material/Warning';
|
||||
import { styles as themeStyles } from 'component/common';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
import useApplications from 'hooks/api/getters/useApplications/useApplications';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { Search } from 'component/common/Search/Search';
|
||||
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||
import {
|
||||
SortableTableHeader,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
} from 'component/common/Table';
|
||||
import { useGlobalFilter, useSortBy, useTable } from 'react-table';
|
||||
import { sortTypes } from 'utils/sortTypes';
|
||||
import { IconCell } from 'component/common/Table/cells/IconCell/IconCell';
|
||||
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
||||
import { ApplicationUsageCell } from './ApplicationUsageCell/ApplicationUsageCell';
|
||||
import { ApplicationSchema } from 'openapi';
|
||||
|
||||
export const ApplicationList = () => {
|
||||
const { applications: data, loading } = useApplications();
|
||||
|
||||
const renderNoApplications = () => (
|
||||
<>
|
||||
<section style={{ textAlign: 'center' }}>
|
||||
<Warning titleAccess='Warning' /> <br />
|
||||
<br />
|
||||
Oh snap, it does not seem like you have connected any
|
||||
applications. To connect your application to Unleash you will
|
||||
require a Client SDK.
|
||||
<br />
|
||||
<br />
|
||||
You can read more about how to use Unleash in your application
|
||||
in the{' '}
|
||||
<Link href='https://docs.getunleash.io/docs/sdks/'>
|
||||
documentation.
|
||||
</Link>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
|
||||
const initialState = useMemo(
|
||||
() => ({
|
||||
sortBy: [{ id: 'name', desc: false }],
|
||||
hiddenColumns: ['description', 'sortOrder'],
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'Icon',
|
||||
Cell: ({
|
||||
row: {
|
||||
original: { icon },
|
||||
},
|
||||
}: any) => (
|
||||
<IconCell
|
||||
icon={
|
||||
<Avatar>
|
||||
<Icon>{icon || 'apps'}</Icon>
|
||||
</Avatar>
|
||||
}
|
||||
/>
|
||||
),
|
||||
disableGlobalFilter: true,
|
||||
},
|
||||
{
|
||||
Header: 'Name',
|
||||
accessor: 'appName',
|
||||
width: '50%',
|
||||
Cell: ({
|
||||
row: {
|
||||
original: { appName, description },
|
||||
},
|
||||
}: any) => (
|
||||
<LinkCell
|
||||
title={appName}
|
||||
to={`/applications/${appName}`}
|
||||
subtitle={description}
|
||||
/>
|
||||
),
|
||||
sortType: 'alphanumeric',
|
||||
},
|
||||
{
|
||||
Header: 'Project(environment)',
|
||||
accessor: 'usage',
|
||||
width: '50%',
|
||||
Cell: ({
|
||||
row: { original },
|
||||
}: {
|
||||
row: { original: ApplicationSchema };
|
||||
}) => <ApplicationUsageCell usage={original.usage} />,
|
||||
sortType: 'alphanumeric',
|
||||
},
|
||||
{
|
||||
accessor: 'description',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
accessor: 'sortOrder',
|
||||
disableGlobalFilter: true,
|
||||
sortType: 'number',
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
const {
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
headerGroups,
|
||||
rows,
|
||||
prepareRow,
|
||||
state: { globalFilter },
|
||||
setGlobalFilter,
|
||||
} = useTable(
|
||||
{
|
||||
columns: columns as any[], // TODO: fix after `react-table` v8 update
|
||||
data,
|
||||
initialState,
|
||||
sortTypes,
|
||||
autoResetGlobalFilter: false,
|
||||
autoResetSortBy: false,
|
||||
disableSortRemove: true,
|
||||
},
|
||||
useGlobalFilter,
|
||||
useSortBy,
|
||||
);
|
||||
|
||||
if (!data) {
|
||||
return <CircularProgress variant='indeterminate' />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageContent
|
||||
header={
|
||||
<PageHeader
|
||||
title={`Applications (${rows.length})`}
|
||||
actions={
|
||||
<Search
|
||||
initialValue={globalFilter}
|
||||
onChange={setGlobalFilter}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className={themeStyles.fullwidth}>
|
||||
<ConditionallyRender
|
||||
condition={data.length > 0}
|
||||
show={
|
||||
<SearchHighlightProvider value={globalFilter}>
|
||||
<Table {...getTableProps()}>
|
||||
<SortableTableHeader
|
||||
headerGroups={headerGroups}
|
||||
/>
|
||||
<TableBody {...getTableBodyProps()}>
|
||||
{rows.map((row) => {
|
||||
prepareRow(row);
|
||||
return (
|
||||
<TableRow
|
||||
hover
|
||||
{...row.getRowProps()}
|
||||
>
|
||||
{row.cells.map((cell) => (
|
||||
<TableCell
|
||||
{...cell.getCellProps()}
|
||||
>
|
||||
{cell.render(
|
||||
'Cell',
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</SearchHighlightProvider>
|
||||
}
|
||||
elseShow={
|
||||
<ConditionallyRender
|
||||
condition={loading}
|
||||
show={<div>...loading</div>}
|
||||
elseShow={renderNoApplications()}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</PageContent>
|
||||
</>
|
||||
);
|
||||
};
|
@ -28,9 +28,9 @@ test('Display applications list', async () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('Display no applications', async () => {
|
||||
test('Display no applications connected', async () => {
|
||||
setupApi([]);
|
||||
render(<PaginatedApplicationList />);
|
||||
|
||||
await screen.findByText('Warning');
|
||||
await screen.findByText(/To connect your application to Unleash/);
|
||||
});
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Avatar, Icon, Link } from '@mui/material';
|
||||
import Warning from '@mui/icons-material/Warning';
|
||||
import { Avatar, Icon, Link, styled } from '@mui/material';
|
||||
import { styles as themeStyles } from 'component/common';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
@ -26,23 +25,34 @@ import { withTableState } from 'utils/withTableState';
|
||||
import useLoading from 'hooks/useLoading';
|
||||
import mapValues from 'lodash.mapvalues';
|
||||
|
||||
const renderNoApplications = () => (
|
||||
<>
|
||||
<section style={{ textAlign: 'center' }}>
|
||||
<Warning titleAccess='Warning' /> <br />
|
||||
<br />
|
||||
Oh snap, it does not seem like you have connected any applications.
|
||||
To connect your application to Unleash you will require a Client
|
||||
SDK.
|
||||
<br />
|
||||
const InfoMessage = styled('div')(({ theme }) => ({
|
||||
textAlign: 'center',
|
||||
padding: theme.spacing(9, 0, 9, 0),
|
||||
minHeight: '150px',
|
||||
}));
|
||||
|
||||
const renderNoResults = (query: string | null | undefined) => {
|
||||
if (typeof query === 'string' && query.length > 0) {
|
||||
return renderNoMatchingSearch(query);
|
||||
}
|
||||
return (
|
||||
<InfoMessage>
|
||||
You don't have have any connected applications. To connect your
|
||||
application to Unleash you will require a{' '}
|
||||
<Link href='https://docs.getunleash.io/docs/sdks/'>Client SDK</Link>
|
||||
.
|
||||
<br />
|
||||
You can read more about how to use Unleash in your application in
|
||||
the{' '}
|
||||
<Link href='https://docs.getunleash.io/docs/sdks/'>
|
||||
documentation.
|
||||
</Link>
|
||||
</section>
|
||||
</>
|
||||
</InfoMessage>
|
||||
);
|
||||
};
|
||||
|
||||
const renderNoMatchingSearch = (query: string) => (
|
||||
<InfoMessage>No application found matching "{query}"</InfoMessage>
|
||||
);
|
||||
|
||||
const columnHelper = createColumnHelper<ApplicationSchema>();
|
||||
@ -125,8 +135,6 @@ export const PaginatedApplicationList = () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const rows = table.getRowModel().rows;
|
||||
|
||||
const { offset, limit, query, sortBy, sortOrder, ...filterState } =
|
||||
tableState;
|
||||
|
||||
@ -165,7 +173,7 @@ export const PaginatedApplicationList = () => {
|
||||
</div>
|
||||
</SearchHighlightProvider>
|
||||
}
|
||||
elseShow={renderNoApplications()}
|
||||
elseShow={renderNoResults(query)}
|
||||
/>
|
||||
</div>
|
||||
</PageContent>
|
||||
|
Loading…
Reference in New Issue
Block a user