-
Notifications
You must be signed in to change notification settings - Fork 13
Try swagger-typescript-api for real #535
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a8b0767
79d157c
9f407ed
db6236d
d7deee0
f5aba99
057a7db
d2b6ca6
a5a7816
72cec66
111d3aa
e2e6b66
b99af6b
2761532
6c49453
9863895
b564bbd
358bdc9
4fe9652
8f4836f
fbb5e82
a6fb60d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import { | |
Success16Icon, | ||
FieldTitle, | ||
} from '@oxide/ui' | ||
import type { Project } from '@oxide/api' | ||
import { useApiMutation, useApiQueryClient } from '@oxide/api' | ||
import { useParams, useToast } from '../hooks' | ||
import { getServerError } from '../util/errors' | ||
|
@@ -24,40 +25,23 @@ const ERROR_CODES = { | |
} | ||
|
||
// exists primarily so we can test it without worrying about route params | ||
export function ProjectCreateForm({ orgName }: { orgName: string }) { | ||
const navigate = useNavigate() | ||
|
||
const queryClient = useApiQueryClient() | ||
const addToast = useToast() | ||
|
||
export function ProjectCreateForm({ | ||
orgName, | ||
onSuccess, | ||
}: { | ||
orgName: string | ||
onSuccess: (p: Project) => void | ||
}) { | ||
const createProject = useApiMutation('organizationProjectsPost', { | ||
onSuccess: (data) => { | ||
// refetch list of projects in sidebar | ||
queryClient.invalidateQueries('organizationProjectsGet', { | ||
organizationName: orgName, | ||
}) | ||
// avoid the project fetch when the project page loads since we have the data | ||
queryClient.setQueryData( | ||
'organizationProjectsGetProject', | ||
{ organizationName: orgName, projectName: data.name }, | ||
data | ||
) | ||
addToast({ | ||
icon: <Success16Icon />, | ||
title: 'Success!', | ||
content: 'Your project has been created.', | ||
timeout: 5000, | ||
}) | ||
navigate(`/orgs/${orgName}/projects/${data.name}`) | ||
}, | ||
onSuccess, | ||
}) | ||
return ( | ||
<Formik | ||
initialValues={{ name: '', description: '' }} | ||
onSubmit={({ name, description }) => { | ||
createProject.mutate({ | ||
organizationName: orgName, | ||
projectCreate: { name, description }, | ||
body: { name, description }, | ||
}) | ||
}} | ||
> | ||
|
@@ -105,6 +89,10 @@ export function ProjectCreateForm({ orgName }: { orgName: string }) { | |
} | ||
|
||
export default function ProjectCreatePage() { | ||
const queryClient = useApiQueryClient() | ||
const addToast = useToast() | ||
const navigate = useNavigate() | ||
|
||
const { orgName } = useParams('orgName') | ||
return ( | ||
<> | ||
|
@@ -113,7 +101,28 @@ export default function ProjectCreatePage() { | |
Create a new project | ||
</PageTitle> | ||
</PageHeader> | ||
<ProjectCreateForm orgName={orgName} /> | ||
<ProjectCreateForm | ||
orgName={orgName} | ||
onSuccess={(project) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a function that takes the created project is a surprisingly natural interface here |
||
// refetch list of projects in sidebar | ||
queryClient.invalidateQueries('organizationProjectsGet', { | ||
organizationName: orgName, | ||
}) | ||
// avoid the project fetch when the project page loads since we have the data | ||
queryClient.setQueryData( | ||
'organizationProjectsGetProject', | ||
{ organizationName: orgName, projectName: project.name }, | ||
project | ||
) | ||
addToast({ | ||
icon: <Success16Icon />, | ||
title: 'Success!', | ||
content: 'Your project has been created.', | ||
timeout: 5000, | ||
}) | ||
navigate(`../${project.name}`) | ||
}} | ||
/> | ||
</> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,7 +76,7 @@ const ProjectsPage = () => { | |
</section> | ||
<footer className="p-4 border-t border-gray-400 text-xs"> | ||
<span className="uppercase"> | ||
{formatDistanceToNowStrict(item.timeCreated, { | ||
{formatDistanceToNowStrict(new Date(item.timeCreated), { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't parse dates by default. we fix this on the generator side by automatically parsing |
||
addSuffix: true, | ||
})} | ||
</span> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,13 +20,20 @@ const instancesUrl = `${projectUrl}/instances` | |
const disksUrl = `${projectUrl}/disks` | ||
const vpcsUrl = `${projectUrl}/vpcs` | ||
|
||
let successSpy: jest.Mock | ||
|
||
describe('InstanceCreateForm', () => { | ||
beforeEach(() => { | ||
// existing disk modal fetches disks on render even if it's not visible | ||
fetchMock.get(disksUrl, 200) | ||
fetchMock.get(vpcsUrl, 200) | ||
successSpy = jest.fn() | ||
renderWithRouter( | ||
<InstanceCreateForm orgName={org.name} projectName={project.name} /> | ||
<InstanceCreateForm | ||
orgName={org.name} | ||
projectName={project.name} | ||
onSuccess={successSpy} | ||
/> | ||
) | ||
}) | ||
|
||
|
@@ -62,7 +69,10 @@ describe('InstanceCreateForm', () => { | |
}) | ||
|
||
it('shows generic message for unknown server error', async () => { | ||
fetchMock.post(instancesUrl, 400) | ||
fetchMock.post(instancesUrl, { | ||
status: 400, | ||
body: { error_code: 'UnknownCode' }, | ||
}) | ||
|
||
fireEvent.click(submitButton()) | ||
|
||
|
@@ -89,16 +99,15 @@ describe('InstanceCreateForm', () => { | |
) | ||
}) | ||
|
||
it('navigates to project page on success', async () => { | ||
it('calls onSuccess on success', async () => { | ||
const mock = fetchMock.post(instancesUrl, { status: 201, body: instance }) | ||
|
||
const projectPath = `/orgs/${org.name}/projects/${project.name}` | ||
expect(window.location.pathname).not.toEqual(projectPath) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was never a good way to do this anyway, so I don't miss it. the problem was the location was being set by a previously run test, so this not equal was failing |
||
expect(successSpy).not.toHaveBeenCalled() | ||
|
||
fireEvent.click(submitButton()) | ||
|
||
await waitFor(() => expect(mock.called(instancesUrl)).toBeTruthy()) | ||
await waitFor(() => expect(mock.done()).toBeTruthy()) | ||
await waitFor(() => expect(window.location.pathname).toEqual(projectPath)) | ||
await waitFor(() => expect(successSpy).toHaveBeenCalled()) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I've seriously got to fix this. If the file isn't changed in the current PR, this shouldn't be ran. Why it happens anyway is a mystery to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it watches the
packer
directory, which did have changes