Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: Add Create Workspace Form#73

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
bryphe-coder merged 11 commits intomainfrombryphe/feat/38/create-workspace-page
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
11 commits
Select commitHold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletionssite/api.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,6 +67,11 @@ export namespace Project {
}
}

export interface CreateWorkspaceRequest {
name: string
project_id: string
}

// Must be kept in sync with backend Workspace struct
export interface Workspace {
id: string
Expand All@@ -77,6 +82,31 @@ export interface Workspace {
name: string
}

export namespace Workspace {
export const create = async (request: CreateWorkspaceRequest): Promise<Workspace> => {
const response = await fetch(`/api/v2/workspaces/me`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(request),
})

const body = await response.json()
if (!response.ok) {
throw new Error(body.message)
}

// Let SWR know that both the /api/v2/workspaces/* and /api/v2/projects/*
// endpoints will need to fetch new data.
const mutateWorkspacesPromise = mutate("/api/v2/workspaces")
const mutateProjectsPromise = mutate("/api/v2/projects")
await Promise.all([mutateWorkspacesPromise, mutateProjectsPromise])

return body
}
}

export const login = async (email: string, password: string): Promise<LoginResponse> => {
const response = await fetch("/api/v2/login", {
method: "POST",
Expand Down
20 changes: 20 additions & 0 deletionssite/forms/CreateWorkspaceForm.test.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
import { render, screen } from "@testing-library/react"
import React from "react"
import { CreateWorkspaceForm } from "./CreateWorkspaceForm"
import { MockProject, MockWorkspace } from "./../test_helpers"

describe("CreateWorkspaceForm", () => {
it("renders", async () => {
// Given
const onSubmit = () => Promise.resolve(MockWorkspace)
const onCancel = () => Promise.resolve()

// When
render(<CreateWorkspaceForm project={MockProject} onSubmit={onSubmit} onCancel={onCancel} />)

// Then
// Simple smoke test to verify form renders
const element = await screen.findByText("Create Workspace")
expect(element).toBeDefined()
})
})
97 changes: 97 additions & 0 deletionssite/forms/CreateWorkspaceForm.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
import Button from "@material-ui/core/Button"
import { makeStyles } from "@material-ui/core/styles"
import { FormikContextType, useFormik } from "formik"
import React from "react"
import * as Yup from "yup"

import { FormTextField, FormTitle, FormSection } from "../components/Form"
import { LoadingButton } from "../components/Button"
import { Project, Workspace, CreateWorkspaceRequest } from "../api"

export interface CreateWorkspaceForm {
project: Project
onSubmit: (request: CreateWorkspaceRequest) => Promise<Workspace>
onCancel: () => void
}

const validationSchema = Yup.object({
name: Yup.string().required("Name is required"),
})

export const CreateWorkspaceForm: React.FC<CreateWorkspaceForm> = ({ project, onSubmit, onCancel }) => {
const styles = useStyles()

const form: FormikContextType<{ name: string }> = useFormik<{ name: string }>({
initialValues: {
name: "",
},
enableReinitialize: true,
validationSchema: validationSchema,
onSubmit: ({ name }) => {
return onSubmit({
project_id: project.id,
name: name,
})
},
})

return (
<div className={styles.root}>
<FormTitle
title="Create Workspace"
detail={
<span>
for project <strong>{project.name}</strong>
</span>
}
/>
<FormSection title="Name">
<FormTextField
form={form}
formFieldName="name"
fullWidth
helperText="A unique name describing your workspace."
label="Workspace Name"
placeholder="my-workspace"
required
/>
</FormSection>

<div className={styles.footer}>
<Button className={styles.button} onClick={onCancel} variant="outlined">
Cancel
</Button>
<LoadingButton
loading={form.isSubmitting}
className={styles.button}
onClick={form.submitForm}
variant="contained"
color="primary"
type="submit"
>
Submit
</LoadingButton>
</div>
</div>
)
}

const useStyles = makeStyles(() => ({
root: {
maxWidth: "1380px",
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
},
footer: {
display: "flex",
flex: "0",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},
button: {
margin: "1em",
},
}))
56 changes: 56 additions & 0 deletionssite/pages/projects/[organization]/[project]/create.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
import React from "react"
import { makeStyles } from "@material-ui/core/styles"
import { useRouter } from "next/router"
import useSWR from "swr"

import * as API from "../../../../api"
import { useUser } from "../../../../contexts/UserContext"
import { ErrorSummary } from "../../../../components/ErrorSummary"
import { FullScreenLoader } from "../../../../components/Loader/FullScreenLoader"
import { CreateWorkspaceForm } from "../../../../forms/CreateWorkspaceForm"

const CreateWorkspacePage: React.FC = () => {
const router = useRouter()
const styles = useStyles()
const { me } = useUser(/* redirectOnError */ true)
const { organization, project: projectName } = router.query
const { data: project, error: projectError } = useSWR<API.Project, Error>(
`/api/v2/projects/${organization}/${projectName}`,
)

if (projectError) {
return <ErrorSummary error={projectError} />
}

if (!me || !project) {
return <FullScreenLoader />
}

const onCancel = async () => {
await router.push(`/projects/${organization}/${project}`)
}

const onSubmit = async (req: API.CreateWorkspaceRequest) => {
const workspace = await API.Workspace.create(req)
await router.push(`/workspaces/${workspace.id}`)
return workspace
}

return (
<div className={styles.root}>
<CreateWorkspaceForm onCancel={onCancel} onSubmit={onSubmit} project={project} />
</div>
)
}

const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexDirection: "column",
alignItems: "center",
height: "100vh",
backgroundColor: theme.palette.background.paper,
},
}))

export default CreateWorkspacePage

[8]ページ先頭

©2009-2025 Movatter.jp