Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/packer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
CLOUDFLARE_TOKEN: ${{secrets.CLOUDFLARE_TOKEN}}
SSL_CERT: ${{secrets.SSL_CERT}}
SSL_KEY: ${{secrets.SSL_KEY}}
API_VERSION: 561d8d6b19c01a273b6b039628d1ff7b6b295b4e
API_VERSION: 439169b9522852b0582634b692260c7b8853eff2

# get the image information from gcloud
- name: Get image information
Expand Down
31 changes: 31 additions & 0 deletions app/docs/nexus-openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,28 @@
}
}
},
"/login": {
"post": {
"operationId": "spoof_login",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginParams"
}
}
},
"required": true
},
"responses": {}
}
Comment on lines +178 to +191
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming this eventually goes away? It seems like while we may still want the capability for dev, we definitely wouldn't want it in the public api spec.

Copy link
Collaborator Author

@david-crespo david-crespo Nov 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's correct. The demo login form is really only in the console bundle in the first place because of the convenience of using existing styles. Login will really be through the customer's IdP, but If Nexus does end up serving some kind of login form, e.g., for use by admins before the IdP is set up, I think that should be a separate bundle with minimal JS (ideally so minimal we could inline it in the HTML response) and it would not use the generated API client at all. It could even use an HTML form POST.

I'll make a comment about this in the LoginPage file.

},
"/logout": {
"post": {
"operationId": "logout",
"responses": {}
}
},
"/organizations": {
"get": {
"description": "List all organizations.",
Expand Down Expand Up @@ -3110,6 +3132,15 @@
"minLength": 1,
"maxLength": 11
},
"LoginParams": {
"type": "object",
"properties": {
"username": {
"type": "string"
}
},
"required": ["username"]
},
"Name": {
"title": "A name used in the API",
"description": "Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'.",
Expand Down
101 changes: 101 additions & 0 deletions app/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react'
import { useNavigate } from 'react-router'

import { useApiMutation } from '@oxide/api'
import { Button, Warning12Icon, Success16Icon } from '@oxide/ui'
import { useToast } from '../hooks'

/**
* Placeholder login page for demo purposes.
*
* The demo login form is only in the console bundle for the convenience of
* using existing tooling and using the generated API client. In the real rack,
* login will go through the customer's IdP; no form controlled by us will be
* involved. If Nexus *does* end up serving a login form, e.g., for use by
* admins before the IdP is set up, that will be a separate bundle with minimal
* JS (ideally so minimal we could inline it in the HTML response) and it would
* not use the generated API client at all. It could even use an HTML form POST.
*
* Login and logout endpoints are only a temporary addition to the OpenAPI spec.
*/
export default function LoginPage() {
const navigate = useNavigate()
const addToast = useToast()
const loginPost = useApiMutation('spoofLogin', {
onSuccess: () => {
addToast({
title: 'Logged in',
icon: <Success16Icon />,
timeout: 4000,
})
navigate('/')
},
onError: () => {
addToast({
title: 'Bad credentials',
icon: <Warning12Icon />,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd definitely like to update the icon apis a bit. This was the most expedient implementation, but eventually I'd like to at least have <WarningIcon size={12}/> where size is required and strictly typed.

variant: 'error',
timeout: 4000,
})
},
})

const logout = useApiMutation('logout', {
onSuccess: () => {
addToast({
title: 'Logged out',
icon: <Success16Icon />,
timeout: 4000,
})
},
})
return (
<div className="w-full justify-center flex">
<div className="my-48 w-96 space-y-4">
<h3 className="text-display-xl mb-2 text-center">Log in as</h3>
<Button
type="submit"
variant="solid"
className="w-full"
disabled={loginPost.isLoading}
onClick={() =>
loginPost.mutate({ loginParams: { username: 'privileged' } })
}
>
Privileged
</Button>
<Button
type="submit"
variant="dim"
className="w-full"
disabled={loginPost.isLoading}
onClick={() =>
loginPost.mutate({ loginParams: { username: 'unprivileged' } })
}
>
Unprivileged
</Button>
<Button
type="submit"
variant="ghost"
className="w-full"
disabled={loginPost.isLoading}
onClick={() =>
loginPost.mutate({ loginParams: { username: 'other' } })
}
>
Bad Request
</Button>
<Button
type="submit"
variant="link"
className="w-full"
disabled={loginPost.isLoading}
onClick={() => logout.mutate({})}
>
Log out
</Button>
</div>
</div>
)
}
2 changes: 1 addition & 1 deletion app/pages/OrgPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function OrgPage() {
</PageHeader>

<div className="space-x-4">
<Link to={`/orgs/${orgName}/projects/new`} className={buttonStyle()}>
<Link to="projects/new" className={buttonStyle()}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this because the link is relative to the current location?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost, it's relative to the parent node in the route tree, in this case /orgs/:orgName.

console/app/routes.tsx

Lines 71 to 73 in c1378a6

<Route path="orgs">
<Route path=":orgName" element={<RootLayout />} crumb={orgCrumb}>
<Route index element={<OrgPage />} />

Originally I did this because it made the link totally indifferent to the /c/ prefix, but even without that it's kind of cool not to have to explicitly build up the full route. On the other hand it's a layer of misdirection because in order to know where this link goes, you have to know what route is rendering this page. So I'm open to changing it back.

Create project
</Link>
</div>
Expand Down
10 changes: 2 additions & 8 deletions app/pages/ProjectsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ const ProjectsPage = () => {
<PageHeader className="mb-10">
<PageTitle icon={<Folder24Icon title="Projects" />}>Projects</PageTitle>
<div className="flex items-center">
<Link
to={`/orgs/${orgName}/projects/new`}
className={buttonStyle({ variant: 'ghost' })}
>
<Link to="new" className={buttonStyle({ variant: 'ghost' })}>
New Project
</Link>
<button className="p-3 flex items-center">
Expand All @@ -66,10 +63,7 @@ const ProjectsPage = () => {
>
<section className="p-4">
<header className="mb-12">
<Link
to={`/orgs/${orgName}/projects/${item.name}`}
className="text-display-xl"
>
<Link to={item.name} className="text-display-xl">
{item.name}
</Link>
</header>
Expand Down
3 changes: 3 additions & 0 deletions app/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ function lazyLoad(importFunc: () => Promise<{ default: React.ComponentType }>) {
)
}

import LoginPage from './pages/LoginPage'
import InstanceCreatePage from './pages/instances/create'
import InstanceStorage from './pages/instances/Storage'
// Recharts is 350 KB
Expand Down Expand Up @@ -63,6 +64,8 @@ const instanceCrumb = (m: RouteMatch) => m.params.instanceName!
/** React Router route config in JSX form */
export const routes = (
<Routes>
<Route path="login" element={<LoginPage />} />

<Route
index
element={<Navigate to="/orgs/maze-war/projects" replace={true} />}
Expand Down
1 change: 1 addition & 0 deletions libs/api/__generated__/.openapi-generator/FILES

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion libs/api/__generated__/OMICRON_VERSION

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions libs/api/__generated__/apis/DefaultApi.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 56 additions & 0 deletions libs/api/__generated__/models/LoginParams.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions libs/api/__generated__/models/index.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading