From 78236299ce3c27eef3ece857bc051f983591e5eb Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Tue, 8 Mar 2022 22:50:03 +0000 Subject: [PATCH 1/5] Get routes working end-to-end --- site/api.ts | 2 +- .../[organization]/[project]/create.tsx | 4 +- .../[organization]/[project]/index.tsx | 4 +- site/pages/projects/index.tsx | 2 +- site/pages/workspaces/[user]/[workspace].tsx | 71 ------------------- site/pages/workspaces/[workspace].tsx | 61 ++++++++++++++++ 6 files changed, 67 insertions(+), 77 deletions(-) delete mode 100644 site/pages/workspaces/[user]/[workspace].tsx create mode 100644 site/pages/workspaces/[workspace].tsx diff --git a/site/api.ts b/site/api.ts index febeee6c96dd1..179bc1ce9abf9 100644 --- a/site/api.ts +++ b/site/api.ts @@ -84,7 +84,7 @@ export interface Workspace { export namespace Workspace { export const create = async (request: CreateWorkspaceRequest): Promise => { - const response = await fetch(`/api/v2/workspaces/me`, { + const response = await fetch(`/api/v2/users/me/workspaces`, { method: "POST", headers: { "Content-Type": "application/json", diff --git a/site/pages/projects/[organization]/[project]/create.tsx b/site/pages/projects/[organization]/[project]/create.tsx index 8f78206801055..a551fda63c394 100644 --- a/site/pages/projects/[organization]/[project]/create.tsx +++ b/site/pages/projects/[organization]/[project]/create.tsx @@ -15,7 +15,7 @@ const CreateWorkspacePage: React.FC = () => { const { me } = useUser(/* redirectOnError */ true) const { organization, project: projectName } = query const { data: project, error: projectError } = useSWR( - `/api/v2/projects/${organization}/${projectName}`, + `/api/v2/organizations/${organization}/projects/${projectName}`, ) const onCancel = useCallback(async () => { @@ -24,7 +24,7 @@ const CreateWorkspacePage: React.FC = () => { const onSubmit = async (req: API.CreateWorkspaceRequest) => { const workspace = await API.Workspace.create(req) - await push(`/workspaces/me/${workspace.name}`) + await push(`/workspaces/${workspace.id}`) return workspace } diff --git a/site/pages/projects/[organization]/[project]/index.tsx b/site/pages/projects/[organization]/[project]/index.tsx index 3edd8a1cf68d5..45d1928a3a3fe 100644 --- a/site/pages/projects/[organization]/[project]/index.tsx +++ b/site/pages/projects/[organization]/[project]/index.tsx @@ -24,10 +24,10 @@ const ProjectPage: React.FC = () => { const { project, organization } = router.query const { data: projectInfo, error: projectError } = useSWR( - () => `/api/v2/projects/${organization}/${project}`, + () => `/api/v2/organizations/${organization}/projects/${project}`, ) const { data: workspaces, error: workspacesError } = useSWR( - () => `/api/v2/projects/${organization}/${project}/workspaces`, + () => `/api/v2/users/me/workspaces`, ) if (projectError) { diff --git a/site/pages/projects/index.tsx b/site/pages/projects/index.tsx index a5a69af37d9e6..7525a4718233f 100644 --- a/site/pages/projects/index.tsx +++ b/site/pages/projects/index.tsx @@ -49,7 +49,7 @@ const ProjectsPage: React.FC = () => { key: "name", name: "Name", renderer: (nameField: string, data: Project) => { - return {nameField} + return {nameField} }, }, ] diff --git a/site/pages/workspaces/[user]/[workspace].tsx b/site/pages/workspaces/[user]/[workspace].tsx deleted file mode 100644 index 3540e0c317f4c..0000000000000 --- a/site/pages/workspaces/[user]/[workspace].tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React from "react" -import useSWR from "swr" -import { makeStyles } from "@material-ui/core/styles" -import { useRouter } from "next/router" -import { Navbar } from "../../../components/Navbar" -import { Footer } from "../../../components/Page" -import { useUser } from "../../../contexts/UserContext" -import { firstOrItem } from "../../../util/array" -import { ErrorSummary } from "../../../components/ErrorSummary" -import { FullScreenLoader } from "../../../components/Loader/FullScreenLoader" -import { Workspace } from "../../../components/Workspace" - -import * as API from "../../../api" - -const WorkspacesPage: React.FC = () => { - const styles = useStyles() - const router = useRouter() - const { me, signOut } = useUser(true) - - const { user: userQueryParam, workspace: workspaceQueryParam } = router.query - - const { data: workspace, error: workspaceError } = useSWR(() => { - const userParam = firstOrItem(userQueryParam, null) - const workspaceParam = firstOrItem(workspaceQueryParam, null) - - // TODO(Bryan): Getting non-personal users isn't supported yet in the backend. - // So if the user is the same as 'me', use 'me' as the parameter - const normalizedUserParam = me && userParam === me.id ? "me" : userParam - - // The SWR API expects us to 'throw' if the query isn't ready yet: - if (normalizedUserParam === null || workspaceParam === null) { - throw "Data not yet available to make API call" - } - - return `/api/v2/workspaces/${normalizedUserParam}/${workspaceParam}` - }) - - if (workspaceError) { - return - } - - if (!me || !workspace) { - return - } - - return ( -
- - -
- -
- -
-
- ) -} - -const useStyles = makeStyles(() => ({ - root: { - display: "flex", - flexDirection: "column", - }, - inner: { - maxWidth: "1380px", - margin: "1em auto", - width: "100%", - }, -})) - -export default WorkspacesPage diff --git a/site/pages/workspaces/[workspace].tsx b/site/pages/workspaces/[workspace].tsx new file mode 100644 index 0000000000000..587492618ea5b --- /dev/null +++ b/site/pages/workspaces/[workspace].tsx @@ -0,0 +1,61 @@ +import React from "react" +import useSWR from "swr" +import { makeStyles } from "@material-ui/core/styles" +import { useRouter } from "next/router" +import { Navbar } from "../../components/Navbar" +import { Footer } from "../../components/Page" +import { useUser } from "../../contexts/UserContext" +import { firstOrItem } from "../../util/array" +import { ErrorSummary } from "../../components/ErrorSummary" +import { FullScreenLoader } from "../../components/Loader/FullScreenLoader" +import { Workspace } from "../../components/Workspace" + +import * as API from "../../api" + +const WorkspacesPage: React.FC = () => { + const styles = useStyles() + const router = useRouter() + const { me, signOut } = useUser(true) + + const { workspace: workspaceQueryParam } = router.query + + const { data: workspace, error: workspaceError } = useSWR(() => { + const workspaceParam = firstOrItem(workspaceQueryParam, null) + + return `/api/v2/workspaces/${workspaceParam}` + }) + + if (workspaceError) { + return + } + + if (!me || !workspace) { + return + } + + return ( +
+ + +
+ +
+ +
+
+ ) +} + +const useStyles = makeStyles(() => ({ + root: { + display: "flex", + flexDirection: "column", + }, + inner: { + maxWidth: "1380px", + margin: "1em auto", + width: "100%", + }, +})) + +export default WorkspacesPage From fdc654e970484089b88933fc14323f355ec0c73d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Wed, 9 Mar 2022 00:01:31 +0000 Subject: [PATCH 2/5] Fix lint issues --- site/components/Workspace/Workspace.tsx | 12 ++++-- .../[organization]/[project]/create.tsx | 17 ++++++-- .../[organization]/[project]/index.tsx | 40 +++++++++++++------ site/pages/projects/index.tsx | 2 +- site/pages/workspaces/[workspace].tsx | 21 +++++++++- 5 files changed, 68 insertions(+), 24 deletions(-) diff --git a/site/components/Workspace/Workspace.tsx b/site/components/Workspace/Workspace.tsx index f7e22fbef7b49..68c64a467a387 100644 --- a/site/components/Workspace/Workspace.tsx +++ b/site/components/Workspace/Workspace.tsx @@ -10,19 +10,21 @@ import * as API from "../../api" import { WorkspaceSection } from "./WorkspaceSection" export interface WorkspaceProps { + organization: API.Organization workspace: API.Workspace + project: API.Project } /** * Workspace is the top-level component for viewing an individual workspace */ -export const Workspace: React.FC = ({ workspace }) => { +export const Workspace: React.FC = ({ organization, project, workspace }) => { const styles = useStyles() return (
- +
@@ -54,9 +56,11 @@ export const Workspace: React.FC = ({ workspace }) => { /** * Component for the header at the top of the workspace page */ -export const WorkspaceHeader: React.FC = ({ workspace }) => { +export const WorkspaceHeader: React.FC = ({ organization, project, workspace }) => { const styles = useStyles() + const projectLink = `/projects/${organization.name}/${project.name}` + return (
@@ -64,7 +68,7 @@ export const WorkspaceHeader: React.FC = ({ workspace }) => {
{workspace.name} - {workspace.project_id} + {project.name}
diff --git a/site/pages/projects/[organization]/[project]/create.tsx b/site/pages/projects/[organization]/[project]/create.tsx index a551fda63c394..71ab87e55a491 100644 --- a/site/pages/projects/[organization]/[project]/create.tsx +++ b/site/pages/projects/[organization]/[project]/create.tsx @@ -13,14 +13,19 @@ const CreateWorkspacePage: React.FC = () => { const { push, query } = useRouter() const styles = useStyles() const { me } = useUser(/* redirectOnError */ true) - const { organization, project: projectName } = query + const { organization: organizationName, project: projectName } = query + + const { data: organizationInfo, error: organizationError } = useSWR( + () => `/api/v2/users/me/organizations/${organizationName}`, + ) + const { data: project, error: projectError } = useSWR( - `/api/v2/organizations/${organization}/projects/${projectName}`, + `/api/v2/organizations/${(organizationInfo as any).id}/projects/${projectName}`, ) const onCancel = useCallback(async () => { - await push(`/projects/${organization}/${projectName}`) - }, [push, organization, projectName]) + await push(`/projects/${(organizationInfo as any).id}/${projectName}`) + }, [push, organizationInfo, projectName]) const onSubmit = async (req: API.CreateWorkspaceRequest) => { const workspace = await API.Workspace.create(req) @@ -28,6 +33,10 @@ const CreateWorkspacePage: React.FC = () => { return workspace } + if (organizationError) { + return + } + if (projectError) { return } diff --git a/site/pages/projects/[organization]/[project]/index.tsx b/site/pages/projects/[organization]/[project]/index.tsx index 45d1928a3a3fe..bdf6713940e38 100644 --- a/site/pages/projects/[organization]/[project]/index.tsx +++ b/site/pages/projects/[organization]/[project]/index.tsx @@ -5,7 +5,7 @@ import Link from "next/link" import { useRouter } from "next/router" import useSWR from "swr" -import { Project, Workspace } from "../../../../api" +import { Organization, Project, Workspace } from "../../../../api" import { Header } from "../../../../components/Header" import { FullScreenLoader } from "../../../../components/Loader/FullScreenLoader" import { Navbar } from "../../../../components/Navbar" @@ -21,15 +21,25 @@ const ProjectPage: React.FC = () => { const { me, signOut } = useUser(true) const router = useRouter() - const { project, organization } = router.query + const { project: projectName, organization: organizationName } = router.query - const { data: projectInfo, error: projectError } = useSWR( - () => `/api/v2/organizations/${organization}/projects/${project}`, + const { data: organizationInfo, error: organizationError } = useSWR( + () => `/api/v2/users/me/organizations/${organizationName}`, ) - const { data: workspaces, error: workspacesError } = useSWR( - () => `/api/v2/users/me/workspaces`, + + const { data: projectInfo, error: projectError } = useSWR( + () => `/api/v2/organizations/${(organizationInfo as any).id}/projects/${projectName}`, ) + // TODO: The workspaces endpoint was recently changed, so that we can't get + // workspaces per-project. This just grabs all workspaces... and then + // later filters them to match the current project. + const { data: workspaces, error: workspacesError } = useSWR(() => `/api/v2/users/me/workspaces`) + + if (organizationError) { + return + } + if (projectError) { return } @@ -43,7 +53,7 @@ const ProjectPage: React.FC = () => { } const createWorkspace = () => { - void router.push(`/projects/${organization}/${project}/create`) + void router.push(`/projects/${organizationName}/${projectName}/create`) } const emptyState = ( @@ -61,16 +71,20 @@ const ProjectPage: React.FC = () => { { key: "name", name: "Name", - renderer: (nameField: string) => { - return {nameField} + renderer: (nameField: string, workspace: Workspace) => { + return {nameField} }, }, ] + const perProjectWorkspaces = workspaces.filter((workspace) => { + return workspace.project_id === projectInfo.id + }) + const tableProps = { title: "Workspaces", columns, - data: workspaces, + data: perProjectWorkspaces, emptyState: emptyState, } @@ -78,9 +92,9 @@ const ProjectPage: React.FC = () => {
{ key: "name", name: "Name", renderer: (nameField: string, data: Project) => { - return {nameField} + return {nameField} }, }, ] diff --git a/site/pages/workspaces/[workspace].tsx b/site/pages/workspaces/[workspace].tsx index 587492618ea5b..919722ccaa5c6 100644 --- a/site/pages/workspaces/[workspace].tsx +++ b/site/pages/workspaces/[workspace].tsx @@ -25,11 +25,28 @@ const WorkspacesPage: React.FC = () => { return `/api/v2/workspaces/${workspaceParam}` }) + // Fetch parent project + const { data: project, error: projectError } = useSWR(() => { + return `/api/v2/projects/${(workspace as any).project_id}` + }) + + const { data: organization, error: organizationError } = useSWR(() => { + return `/api/v2/organizations/${(project as any).organization_id}` + }) + if (workspaceError) { return } - if (!me || !workspace) { + if (projectError) { + return + } + + if (organizationError) { + return + } + + if (!me || !workspace || !project || !organization) { return } @@ -38,7 +55,7 @@ const WorkspacesPage: React.FC = () => {
- +