Skip to content

Commit b8801ef

Browse files
authored
Add Summary Tables to Organisation Details (canada-ca#646)
* added summary tables to orgDetails * updated faker * updated faker
1 parent 5b43470 commit b8801ef

11 files changed

Lines changed: 284 additions & 104 deletions

frontend/src/App.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@ export default function App() {
6464
<Trans>Sign In</Trans>
6565
</Link>
6666
)}
67-
{/* <Link to="/user-list">
68-
<Trans>User List</Trans>
69-
</Link> */}
7067

7168
<Link to="/dmarc-report">
7269
<Trans>Report</Trans>

frontend/src/LandingPage.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react'
22
import { Trans } from '@lingui/macro'
33
import { Layout } from './Layout'
4-
import { Heading, Text, Stack } from '@chakra-ui/core'
4+
import { Heading, Text, Stack, Divider } from '@chakra-ui/core'
55
import { SummaryGroup } from './SummaryGroup'
66

77
export function LandingPage() {
@@ -27,6 +27,7 @@ export function LandingPage() {
2727
<SummaryGroup name="dashboard" />
2828
</Stack>
2929
</Stack>
30+
<Divider />
3031
<Text>
3132
<Trans>
3233
*All data represented is mocked for demonstration purposes

frontend/src/Organization.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ export function Organization({ name, slug, domainCount, ...rest }) {
88
return (
99
<ListItem {...rest}>
1010
<Stack spacing={4} padding={[1, 2, 3]} flexWrap="wrap">
11-
<Link as={RouteLink} to={`${path}/${slug}`}>
12-
<Text fontWeight="bold">{name}</Text>
13-
</Link>
11+
<Stack isInline>
12+
<Link as={RouteLink} to={`${path}/${slug}`}>
13+
<Text fontWeight="bold" fontSize="xl">
14+
{name}
15+
</Text>
16+
</Link>
17+
</Stack>
1418
<Text>
1519
<Trans>Internet facing services: {domainCount}</Trans>
1620
</Text>

frontend/src/OrganizationDetails.js

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@ import React from 'react'
22
import { useQuery } from '@apollo/react-hooks'
33
import { t, Trans } from '@lingui/macro'
44
import { Layout } from './Layout'
5-
import { ListOf } from './ListOf'
6-
import { Domain } from './Domain'
7-
import { Link, Icon, Heading, Stack, useToast } from '@chakra-ui/core'
5+
import {
6+
Link,
7+
Icon,
8+
Heading,
9+
Stack,
10+
useToast,
11+
Divider,
12+
Text,
13+
} from '@chakra-ui/core'
814
import { ORGANIZATION_BY_SLUG } from './graphql/queries'
915
import { useLingui } from '@lingui/react'
1016
import { useUserState } from './UserState'
1117
import { Link as ReactRouterLink, useParams } from 'react-router-dom'
18+
import SummaryTable from './SummaryTable'
19+
import makeSummaryTableData from './makeSummaryTableData'
1220

1321
export default function OrganizationDetails() {
1422
const { i18n } = useLingui()
@@ -34,9 +42,9 @@ export default function OrganizationDetails() {
3442
},
3543
})
3644

37-
let domains = []
45+
let domainName = ''
3846
if (data && data.organization.domains.edges) {
39-
domains = data.organization.domains.edges.map((e) => e.node)
47+
domainName = data.organization.name
4048
}
4149

4250
if (loading) {
@@ -46,10 +54,55 @@ export default function OrganizationDetails() {
4654
</p>
4755
)
4856
}
57+
58+
const columns = [
59+
{
60+
Header: i18n._(t`Domain`),
61+
accessor: 'host_domain',
62+
},
63+
{
64+
Header: 'HTTPS',
65+
accessor: 'https_result',
66+
},
67+
{
68+
Header: 'HSTS',
69+
accessor: 'hsts_result',
70+
},
71+
{
72+
Header: i18n._(t`HSTS Preloaded`),
73+
accessor: 'preloaded_result',
74+
},
75+
{
76+
Header: 'SSL',
77+
accessor: 'ssl_result',
78+
},
79+
{
80+
Header: i18n._(t`Protocols & Ciphers`),
81+
accessor: 'protocol_cipher_result',
82+
},
83+
{
84+
Header: i18n._(t`Certificate Use`),
85+
accessor: 'cert_use_result',
86+
},
87+
{
88+
Header: 'SPF',
89+
accessor: 'spf_result',
90+
},
91+
{
92+
Header: 'DKIM',
93+
accessor: 'dkim_result',
94+
},
95+
{
96+
Header: 'DMARC',
97+
accessor: 'dmarc_result',
98+
},
99+
]
100+
101+
const tableEntries = Math.floor(Math.random() * 20)
49102
return (
50103
<Layout>
51104
<Stack spacing={10} shouldWrapChildren>
52-
<Stack isInline>
105+
<Stack isInline align="center">
53106
<Link as={ReactRouterLink} to={'/organizations'}>
54107
<Icon
55108
alt={i18n._(t`back to organizations`)}
@@ -59,26 +112,25 @@ export default function OrganizationDetails() {
59112
/>
60113
</Link>
61114
<Heading as="h1">
62-
<Trans>{data.organization.name}</Trans>
115+
<Trans>{domainName}</Trans>
63116
</Heading>
64117
</Stack>
65-
<Stack direction="row" spacing={4}>
66-
<Stack spacing={4} flexWrap="wrap">
67-
<ListOf
68-
elements={domains}
69-
ifEmpty={() => <Trans>No domains yet.</Trans>}
70-
>
71-
{({ url, lastRan }, index) => (
72-
<Domain
73-
key={'domaindetail' + index}
74-
url={url}
75-
lastRan={lastRan}
76-
/>
77-
)}
78-
</ListOf>
79-
</Stack>
118+
<Stack>
119+
{tableEntries > 0 ? (
120+
<SummaryTable
121+
data={makeSummaryTableData(tableEntries)}
122+
columns={columns}
123+
/>
124+
) : (
125+
<Text fontSize="2xl" fontWeight="bold">
126+
<Trans>No domains yet.</Trans>
127+
</Text>
128+
)}
129+
130+
<Divider />
80131
</Stack>
81132
</Stack>
133+
<Trans>*All data represented is mocked for demonstration purposes</Trans>
82134
</Layout>
83135
)
84136
}

frontend/src/Organizations.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useQuery } from '@apollo/react-hooks'
33
import { Trans } from '@lingui/macro'
44
import { Layout } from './Layout'
55
import { ListOf } from './ListOf'
6-
import { Heading, Stack, useToast } from '@chakra-ui/core'
6+
import { Heading, Stack, useToast, Box, Divider } from '@chakra-ui/core'
77
import { ORGANIZATIONS } from './graphql/queries'
88
import { useUserState } from './UserState'
99
import { Organization } from './Organization'
@@ -55,12 +55,15 @@ export default function Organisations() {
5555
ifEmpty={() => <Trans>No Organizations</Trans>}
5656
>
5757
{({ name, slug, domainCount }, index) => (
58-
<Organization
59-
key={'org' + index}
60-
slug={slug}
61-
name={name}
62-
domainCount={domainCount}
63-
/>
58+
<Box>
59+
<Organization
60+
key={'org' + index}
61+
slug={slug}
62+
name={name}
63+
domainCount={domainCount}
64+
/>
65+
<Divider borderColor="gray.900" />
66+
</Box>
6467
)}
6568
</ListOf>
6669
</Stack>

frontend/src/SummaryTable.js

Lines changed: 71 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ import React from 'react'
22
import styled from '@emotion/styled'
33
import { useTable, usePagination } from 'react-table'
44
import { array } from 'prop-types'
5-
import { Box, Text, Button, Stack, Select, Input } from '@chakra-ui/core'
6-
5+
import { Trans } from '@lingui/macro'
6+
import { Box, Text, Stack, Select, Input, IconButton } from '@chakra-ui/core'
77
import WithPseudoBox from './withPseudoBox'
88

9-
// TODO: replace with values from the theme
109
const Table = styled.table`
1110
& {
1211
width: 100%;
@@ -24,6 +23,10 @@ const Table = styled.table`
2423
text-align: center;
2524
}
2625
26+
.pagination {
27+
padding: 0.5rem;
28+
}
29+
2730
.title {
2831
text-align: center;
2932
}
@@ -75,6 +78,10 @@ const Table = styled.table`
7578

7679
function SummaryTable({ ...props }) {
7780
const { data, columns } = props
81+
const defaultPageSize = window.matchMedia('screen and (max-width: 760px)')
82+
.matches
83+
? 5
84+
: 10
7885

7986
const {
8087
getTableProps,
@@ -96,18 +103,14 @@ function SummaryTable({ ...props }) {
96103
{
97104
columns,
98105
data,
99-
initialState: { pageIndex: 0 },
106+
initialState: { pageIndex: 0, pageSize: defaultPageSize },
100107
},
101108
usePagination,
102109
)
103110

104111
return (
105-
<Stack align="center">
106-
<Box overflowX="auto">
107-
<Text fontWeight="bold" fontSize="3xl" textAlign={['center']}>
108-
Domain Summary Table
109-
</Text>
110-
<br />
112+
<Box>
113+
<Box width="100%" overflowX="auto">
111114
<Table {...getTableProps()} flatHeaders={flatHeaders}>
112115
<thead>
113116
{headerGroups.map((headerGroup, idx) => (
@@ -142,46 +145,64 @@ function SummaryTable({ ...props }) {
142145
</tbody>
143146
</Table>
144147
</Box>
145-
<Stack className="pagination" isInline>
146-
<Button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
147-
{'<<'}
148-
</Button>{' '}
149-
<Button onClick={() => previousPage()} disabled={!canPreviousPage}>
150-
{'<'}
151-
</Button>{' '}
152-
<Button onClick={() => nextPage()} disabled={!canNextPage}>
153-
{'>'}
154-
</Button>{' '}
155-
<Button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
156-
{'>>'}
157-
</Button>{' '}
158-
<Text fontWeight="semibold">
159-
Page {pageIndex + 1} of {pageOptions.length}{' '}
160-
</Text>
161-
<Text>| Go to page: </Text>
162-
<Input
163-
width="60px"
164-
type="number"
165-
onChange={(e) => {
166-
const page = e.target.value ? Number(e.target.value) - 1 : 0
167-
gotoPage(page)
168-
}}
169-
/>{' '}
170-
<Select
171-
w="30"
172-
value={pageSize}
173-
onChange={(e) => {
174-
setPageSize(Number(e.target.value))
175-
}}
176-
>
177-
{[10, 20, 30, 40, 50].map((pageSize) => (
178-
<option key={pageSize} value={pageSize}>
179-
Show {pageSize}
180-
</option>
181-
))}
182-
</Select>
183-
</Stack>
184-
</Stack>
148+
<Box className="pagination">
149+
<Stack isInline align="center" flexWrap="wrap" justify="space-between">
150+
<Stack spacing="1em" isInline align="center" flexWrap="wrap">
151+
<IconButton
152+
icon="arrow-left"
153+
onClick={() => gotoPage(0)}
154+
disabled={!canPreviousPage}
155+
/>
156+
<IconButton
157+
icon="chevron-left"
158+
onClick={() => previousPage()}
159+
disabled={!canPreviousPage}
160+
/>
161+
<IconButton
162+
icon="chevron-right"
163+
onClick={() => nextPage()}
164+
disabled={!canNextPage}
165+
/>
166+
<IconButton
167+
icon="arrow-right"
168+
onClick={() => gotoPage(pageCount - 1)}
169+
disabled={!canNextPage}
170+
/>
171+
<Text fontWeight="semibold">
172+
<Trans>Page</Trans> {pageIndex + 1} <Trans>of</Trans>{' '}
173+
{pageOptions.length}{' '}
174+
</Text>
175+
</Stack>
176+
<Stack spacing="1em" isInline align="center" flexWrap="wrap">
177+
<Text fontWeight="semibold">
178+
<Trans>Go to page: </Trans>
179+
</Text>
180+
<Input
181+
variant="outline"
182+
width="60px"
183+
type="number"
184+
onChange={(e) => {
185+
const page = e.target.value ? Number(e.target.value) - 1 : 0
186+
gotoPage(page)
187+
}}
188+
/>{' '}
189+
<Select
190+
w="30"
191+
value={pageSize}
192+
onChange={(e) => {
193+
setPageSize(Number(e.target.value))
194+
}}
195+
>
196+
{[5, 10, 20].map((pageSize) => (
197+
<option key={pageSize} value={pageSize}>
198+
Show {pageSize}
199+
</option>
200+
))}
201+
</Select>
202+
</Stack>
203+
</Stack>
204+
</Box>
205+
</Box>
185206
)
186207
}
187208

frontend/src/__tests__/OrganizationDetails.test.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ describe('<OrganizationDetails />', () => {
4242
},
4343
},
4444
]
45+
46+
Object.defineProperty(window, 'matchMedia', {
47+
writable: true,
48+
value: jest.fn().mockImplementation((query) => ({
49+
matches: false,
50+
media: query,
51+
})),
52+
})
53+
4554
const { getByText } = render(
4655
<ThemeProvider theme={theme}>
4756
<I18nProvider i18n={setupI18n()}>
@@ -67,7 +76,6 @@ describe('<OrganizationDetails />', () => {
6776

6877
await waitFor(() => {
6978
expect(getByText(name)).toBeInTheDocument()
70-
expect(getByText(/2020-06-18T00:42:12.414Z/)).toBeInTheDocument()
7179
})
7280
})
7381
})

0 commit comments

Comments
 (0)