Files
coder/site/pages/projects/index.tsx
Bryan b964cb0380 feat: Initial Projects listing page (#58)
This implements a simple Project listing page at `/projects` - just a table for a list of projects:

![image](https://user-images.githubusercontent.com/88213859/150906058-bbc49cfc-cb42-4252-bade-b8d48a986280.png)

...and an empty state:

![image](https://user-images.githubusercontent.com/88213859/150906882-03b0ace5-77c6-4806-b530-008769948867.png)

There isn't too much data to show at the moment. It'll be nice in the future to show the following fields and improve the UI with it:
- An icon
- A list of users using the project
- A description

However, this brings in a lot of scaffolding to make it easier to build pages like this (`/organizations`, `/workspaces`, etc).

In particular, I brought over a few things from v1:
- The `Hero` / `Header` component at the top of pages + sub-components
- A `Table` component for help rendering table-like UI + sub-components
- Additional palette settings that the `Hero`
2022-01-25 07:41:59 -08:00

95 lines
2.4 KiB
TypeScript

import React from "react"
import { makeStyles } from "@material-ui/core/styles"
import Paper from "@material-ui/core/Paper"
import { useRouter } from "next/router"
import Link from "next/link"
import { EmptyState } from "../../components"
import { ErrorSummary } from "../../components/ErrorSummary"
import { Navbar } from "../../components/Navbar"
import { Header } from "../../components/Header"
import { Footer } from "../../components/Page"
import { Column, Table } from "../../components/Table"
import { useUser } from "../../contexts/UserContext"
import { FullScreenLoader } from "../../components/Loader/FullScreenLoader"
import { Project } from "./../../api"
import useSWR from "swr"
const ProjectsPage: React.FC = () => {
const styles = useStyles()
const router = useRouter()
const { me, signOut } = useUser(true)
const { data, error } = useSWR<Project[] | null, Error>("/api/v2/projects")
// TODO: The API call is currently returning `null`, which isn't ideal
// - it breaks checking for data presence with SWR.
const projects = data || []
if (error) {
return <ErrorSummary error={error} />
}
if (!me || !projects) {
return <FullScreenLoader />
}
const createProject = () => {
void router.push("/projects/create")
}
const action = {
text: "Create Project",
onClick: createProject,
}
const columns: Column<Project>[] = [
{
key: "name",
name: "Name",
renderer: (nameField: string, data: Project) => {
return <Link href={`/projects/${data.organization_id}/${data.id}`}>{nameField}</Link>
},
},
]
const emptyState = (
<EmptyState
button={{
children: "Create Project",
onClick: createProject,
}}
message="No projects have been created yet"
description="Create a project to get started."
/>
)
const tableProps = {
title: "All Projects",
columns: columns,
emptyState: emptyState,
data: projects,
}
const subTitle = `${projects.length} total`
return (
<div className={styles.root}>
<Navbar user={me} onSignOut={signOut} />
<Header title="Projects" subTitle={subTitle} action={action} />
<Paper style={{ maxWidth: "1380px", margin: "1em auto", width: "100%" }}>
<Table {...tableProps} />
</Paper>
<Footer />
</div>
)
}
const useStyles = makeStyles(() => ({
root: {
display: "flex",
flexDirection: "column",
},
}))
export default ProjectsPage