1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
import Link from 'next/link'
import {
Gallery,
Bullseye,
EmptyState,
EmptyStateIcon,
Card,
CardTitle,
CardActions,
DropdownItem,
CardHeader,
Dropdown,
KebabToggle,
CardBody,
CardHeaderMain,
TextVariants,
Text,
TextContent,
Tooltip,
Button,
Label,
} from '@patternfly/react-core'
import { PlusIcon, FolderIcon, TrashIcon } from '@patternfly/react-icons'
import PropTypes from 'prop-types'
import React, { useReducer, useMemo } from 'react'
import { Project, Status } from '../../shapes'
import { parseAndFormatDateTime } from '../../util/date-time'
import { AUTH_DESCRIPTION_MAP, AUTH_ICON_MAP, AUTH_NAME_MAP } from '../../util/authorizations'
import TableEmptyState from '../util/TableEmptyState'
function ProjectCard({ project, onDelete }) {
const [isKebabOpen, toggleKebab] = useReducer((t) => !t, false)
const { id, role, name, updatedAt } = project
const Icon = AUTH_ICON_MAP[role]
return (
<Card
isCompact
isRounded
isFlat
className="pf-u-min-height"
style={{ '--pf-u-min-height--MinHeight': '175px' }}
>
<CardHeader className="pf-u-flex-grow-1">
<CardHeaderMain className="pf-u-align-self-flex-start">
<FolderIcon />
</CardHeaderMain>
<CardActions>
<Tooltip content={AUTH_DESCRIPTION_MAP[role]}>
<Label icon={<Icon />}>{AUTH_NAME_MAP[role]}</Label>
</Tooltip>
<Dropdown
isPlain
position="right"
toggle={<KebabToggle className="pf-u-px-0" onToggle={toggleKebab} />}
isOpen={isKebabOpen}
dropdownItems={[
<DropdownItem
key="trash"
onClick={() => {
onDelete()
toggleKebab()
}}
position="right"
icon={<TrashIcon />}
>
Delete
</DropdownItem>,
]}
/>
</CardActions>
</CardHeader>
<CardTitle component={Link} className="pf-u-pb-0" href={`/projects/${id}`}>
{name}
</CardTitle>
<CardBody isFilled={false}>
<TextContent>
<Text component={TextVariants.small}>Last modified {parseAndFormatDateTime(updatedAt)}</Text>
</TextContent>
</CardBody>
</Card>
)
}
function ProjectCollection({ status, projects, onDelete, onCreate, isFiltering }) {
const sortedProjects = useMemo(() => {
const res = [...projects]
res.sort((a, b) => (new Date(a.updatedAt) < new Date(b.updatedAt) ? 1 : -1))
return res
}, [projects])
if (sortedProjects.length === 0) {
return (
<TableEmptyState
status={status}
isFiltering={isFiltering}
loadingTitle="Loading Projects"
emptyTitle="No projects"
emptyText="You have not created any projects yet. Create a new project to get started quickly."
emptyAction={
<Button icon={<PlusIcon />} onClick={onCreate}>
Create Project
</Button>
}
/>
)
}
return (
<Gallery hasGutter aria-label="Available projects">
{sortedProjects.map((project) => (
<ProjectCard key={project.id} project={project} onDelete={() => onDelete(project)} />
))}
<Card isCompact isFlat isRounded style={{ borderStyle: 'dotted' }}>
<Bullseye>
<EmptyState>
<Button isBlock variant="link" onClick={onCreate}>
<EmptyStateIcon icon={PlusIcon} />
<br />
Create Project
</Button>
</EmptyState>
</Bullseye>
</Card>
</Gallery>
)
}
ProjectCollection.propTypes = {
status: Status.isRequired,
isFiltering: PropTypes.bool,
projects: PropTypes.arrayOf(Project).isRequired,
onDelete: PropTypes.func,
onCreate: PropTypes.func,
}
export default ProjectCollection
|