This brings an initial E2E test (really, an integration test - it's only running the server locally, as opposed to against a deployment - but it'd be easy to point playwright to a deployment).
Demo gif:
![test2](https://user-images.githubusercontent.com/88213859/156078517-6cb4ef84-337b-4e16-a8bc-aea7d06dcbcb.gif)
This test exercises a minimal flow for login:
- Run the `coderd` binary to start a server on 3000
- Create an initial user as part of setup
- Go through the login flow and verify we land on the projects page
It will be useful to have to ensure that #360 doesn't introduce a regression in the login flow
Future E2E tests that would be useful:
- Create a project & verify it shows in the UI
- Create a workspace and verify it shows in the UI
While going through the create projects flow, I realized there's a typo on the projects page.
The command should read `coder projects create`, but instead it is currently showing `coder project create`:
<img width="466" alt="Screen Shot 2022-03-01 at 5 31 19 PM" src="https://user-images.githubusercontent.com/88213859/156277646-6fc03977-6dda-4db4-9fce-e48b4b5efba3.png">
Fixing this typo will alleviate some confusion as we on-board developers to v2
Noticed while running through the build steps (`make build`) that we were getting some lint warnings that weren't blocking build:
```sh
./pages/workspaces/[user]/[workspace].tsx
32:58 Warning: Unexpected any. Specify a different type. @typescript-eslint/no-explicit-any
32:96 Warning: Unexpected any. Specify a different type. @typescript-eslint/no-explicit-any
./components/Form/FormCloseButton.tsx
26:6 Warning: React Hook useEffect has a missing dependency: 'onClose'. Either include it or remove the dependency array. If 'onClose' changes too often, find the parent component that defines it and wrap that definition in useCallback. react-hooks/exhaustive-deps
./components/Navbar/UserDropdown.tsx
38:14 Warning: Unnecessary conditional, value is always truthy. @typescript-eslint/no-unnecessary-condition
68:10 Warning: Unnecessary conditional, value is always truthy. @typescript-eslint/no-unnecessary-condition
./components/Redirect.tsx
20:6 Warning: React Hook useEffect has missing dependencies: 'router' and 'to'. Either include them or remove the dependency array. react-hooks/exhaustive-deps
./components/SignIn/SignInForm.tsx
126:19 Warning: Unnecessary optional chain on a non-nullish value. @typescript-eslint/no-unnecessary-condition
```
It turns out our ESLint config wasn't being picked up, so I fixed that (it wasn't properly named). This PR turns warnings-as-errors on, fixes the issues, and also removes the "Project Create" page, because it isn't used at this time.
Wanted to clean this up before on-boarding more FE developers
* Switch from memfs to built-in fstest.MapFS
* Ensure httptest servers are closed during test cleanup
* Swap ordering of expected/actual values in assertion functions
* Use http.StatusOK constants for status codes
* Add a 1-second context timeout for each request
* Use the test httptest.Server.Client() so that we can handle
TLS server certificates if desired
Fixes#210 - this isPR implements `coder login` in the case where the default user is already created.
This change adds:
- A prompt in the case where there is not an initial user that opens the server URL + requests a session token
- This ports over some code from v1 for the `openURL` and `isWSL` functions to support opening the browser
- A `/api/v2/api-keys` endpoint that can be `POST`'d to in order to request a new api key for a user
- This route was inspired by the v1 functionality
- A `cli-auth` route + page that shows the generated api key
- Tests for the new code + storybook for the new UI
The `/cli-auth` route, like in v1, is very minimal:
<img width="624" alt="Screen Shot 2022-02-16 at 5 05 07 PM" src="https://user-images.githubusercontent.com/88213859/154384627-78ab9841-27bf-490f-9bbe-23f8173c9e97.png">
And the terminal UX looks like this:
![2022-02-16 17 13 29](https://user-images.githubusercontent.com/88213859/154385225-509c78d7-840c-4cab-8f1e-074fede8f97e.gif)
This is just a quick fix so that the redirection is correct after creating a workspace - so that we make it to our minimal 'workspaces' page. Mainly so we have a path for testing / onboarding more people.
Unfortunately the NextJS pages are a bit tricky to test - we don't have infra for it because of the special pathing requirements - we can potentially bring in a library like [next-page-tester](https://github.com/next-page-tester/next-page-tester) and create a separate test directory like `pages_test` - but since we may pick up the RFC to move away from Next, it doesn't seem like a useful effort.
With this, creating a project lands on our minimal workspaces page, and the links on the Projects page correctly navigate to the minimal workspaces page.
Fixes#304
Unblocks #298
After logging in, the login flow should redirect to a whatever path is specified by the `?redirect` query parameter. This is important for cases like #298 - where we need to set `?redirect=%2Fcli_auth`, but also really any case where the user is linked and might have to go back to the login screen.
The fix is simple - just check if the `redirect` query parameter is set, and if it is, use that as the path to redirect to on success. Also adds a test case - we had one checking that we redirect to the default (root `/`) url, but not one of the `?redirect` param
In v1, we had a quick and easy way to leave creation forms - an escape button (and key handler) in the top right corner.
This was especially helpful in cases where the form was long enough that the 'Cancel' button was off-screen.
This ports over that component into v2 and hooks up into our two existing forms:
<img width="977" alt="Screen Shot 2022-02-09 at 5 48 03 PM" src="https://user-images.githubusercontent.com/88213859/153321503-af957f2b-d674-4ebf-9ac5-97939cb9153f.png">
In addition, this adds test cases + a storybook story for it.
Fixes#244
- Adds `jest-junit`
- Configures `jest-junit` to output `junit.xml` in `site/test_results`
- Uploads the emitted `junit.xml` to datadog as part of the `test/js` workflow
While working on the projects page, I noticed the `/projects` endpoint would return 'null' instead of an empty array. An empty array would simplify the behavior on the client page.
There were already tests in place for this, but they only validated that the item's length is 0... and it turns out `len(nil)` is also `0`.
So this does a couple things:
- Updates the empty-project tests to check for `NotNil` as well
- Update the project endpoints to return an empty array if no rows are returned
- Remove the hack in `/projects` page for populating data, as it is no longer needed
An issue came up last week... our `embed.go` strategy doesn't handle dynamic NextJS-style routes! This is a blocker, because I'm aiming to set up CD on Monday, and the v2 UI makes heavy use of dynamic routing.
As a potential solution, this implements a go pkg `nextrouter` that serves `html` files, but respecting the dynamic routing behavior of NextJS:
- Files that have square brackets - ie `[providers]` provide a single-level dynamic route
- Files that have `[[...` prefix - ie `[[...any]]` - are catch-all routes.
- Files should be preferred over folders (ie, `providers.html` is preferred over `/providers`)
- Fixes the trailing-slash bug we hit in the previous `embed` strategy
This also integrates with `slog.Logger` for tracing, and handles injecting template parameters - a feature we need in v1 and v2 to be able to inject stuff like CSRF tokens.
This implements testing by using an in-memory file-system, so that we can exercise all of these cases.
In addition, this adjust V2's `embed.go` strategy to use `nextrouter`, which simplifies that file considerably. I'm tempted to factor out the `secureheaders` logic into a separate package, too.
If this works OK, it could be used for V1 too (although that scenario is more complex due to our hybrid-routing strategy). Based on our FE variety meeting, there's always a chance we could move away from NextJS in v1 - if that's the case, this router will still work and be more tested than our previous strategy (it just won't make use of dynamic routing). So I figured this was worth doing to make sure we can make forward progress in V2.
Enforces a consistent test package layout.
This makes it difficult to test internal
functionality, which I believe promotes
healthy decomposition, and minimal package
exports.
This hooks up `storybook`, which the front-end team has enjoyed using in the v1 codebase - it makes it quick and easy to view and test components in isolation.
The `<LoadingButton />` has a simple story added now, so if you run `yarn storybook`, you can preview it in various states:
![2022-01-31 19 24 24](https://user-images.githubusercontent.com/88213859/151908656-27dac0a8-9c6e-4353-ad25-3eafee979bd4.gif)
This will be helpful as we bring more front-end devs to help build v2 out.
Unfortunately along with #133 I missed one other item in moving files to `/site` in #128 - ignoring new configuration files (and other folders) in our `jest.config.js`.
This caused our coverage numbers in front-end code to dip, because files that shouldn't be included (and previously weren't included) were now being tracked for coverage.
This refactors the front-end collateral to all live within `site` - so no `package.json` at the root.
The reason we had this initially is that the jest test run and NextJS actually require having _two_ different `tsconfig`s - Next needs `jsx:"preserve"`, while jest needs `jsx:"react"` - we were using `tsconfig`s at different levels at the hierarchy to manage this.
I changed this behavior to still use two different `tsconfig.json`s, which is mandatory - but just side-by-side in `site`.
Once that's fixed, it was easy to move everything into `site`
Follow up from: https://github.com/coder/coder/pull/118#discussion_r796244577
Previously, there was a pseudo-workspaces page that was leftover from prototyping, but doesn't make sense in the revised flow.
Now, we have a `/projects` page, and after logging in, the user should be taken to that page:
![2022-01-25 20 13 58](https://user-images.githubusercontent.com/88213859/151102949-e756c995-eb43-42db-948d-931c2f0a1fca.gif)
This implements a client-side redirect to land on our `/projects` route.
Prompted from discussion here: https://github.com/coder/coder/pull/60/files#r792124373
Our current FormTextField implementation requires a [higher-order component](https://reactjs.org/docs/higher-order-components.html), which can be complicated to understand.
This experiments with moving it to not require being a HoC.
The only difference in usage is that sometimes, you need to provide the type like `<FormTextField<FormValues> form={form} formFieldName="some-field-in-form" />` - but it doesn't require special construction.
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`
#37 implemented the Sign-_in_ flow, but there wasn't a Sign-_out_ flow as part of that PR (aside from letting the cookie expire... or manually deleting the cookie...), which is obviously not ideal.
This PR implements a basic sign-out flow, along with a very simple user dropdown:
![2022-01-21 18 09 14](https://user-images.githubusercontent.com/88213859/150620847-94e4d22f-1dcf-451e-8b4a-cec24702ea6c.gif)
Bringing in a few pruned down components for the `<UserDropdown />` to integrate into the `<NavBar />`.
In addition, this also implements a simple back-end API for `/logout` which just clears the session token.
* feat: Add organizations endpoint for users
This moves the /user endpoint to /users/me instead. This
will reduce code duplication.
This adds /users/<name>/organizations to list organizations
a user has access to. It doesn't contain the permissions a
user has over the organizations, but that will come in a future
contribution.
* Fix requested changes
* Fix tests
* Fix timeout
* Add test for UserOrgs
* Add test for userparam getting
* Add test for NoUser
While I was testing the Sign-out functionality in #46 , I found a bug on login.
Sometimes, intermittently, the login wouldn't 'take' even though the login POST was successful and the subsequent GET to `/api/v2/user` was successful - the user would still be brought to the `/login` screen a second time:
![2022-01-21 19 52 31](https://user-images.githubusercontent.com/88213859/150623831-7ce33fca-97d5-4ea8-8301-9149def1ee40.gif)
^ I log-in, and then the login screen just resets, and logging in a second time works 🤔
I tracked this down and found it is a new race condition that I inadvertently introduced when I migrated to SWR in #46. Because SWR caches responses based on the API path - we have to invalidate the cache for `/api/v2/user` when the user logins, otherwise we'll continue to serve the user-not-found error until SWR decides to retry.
However, we weren't waiting for that cache-invalidation to go through - so there was the chance that an `/api/v2/user` request was still in-flight while we were redirecting after a successful login. If the request made it back prior to the redirect - login would work on the first try. If the request took longer - SWR would serve the stale, erroneous user from the cache.
Luckily the fix is simple - `mutate` in the SWR API returns a promise, so we can just wait for that to go through before redirecting. Unfortunately, though, this is tricky to exercise in a unit test because with the SWR model, the login logic is spread between `_app.tsx`, `UserContext.tsx`, and `SignInForm.tsx`, and the race condition involves an integration of all of those places.
I found that there is a lint rule that can help protect us from making this mistake - [`typescript-eslint/no-floating-promises`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md) (it's a lint rule we wanted to turn on in `coder/m`, too, actually - just a lot of work to clean up the code for it!), so I turned it on as part of this PR, and it caught a couple extra places to check.
This just implements a basic sign-in flow, using the new endpoints in #29 :
![2022-01-20 12 35 30](https://user-images.githubusercontent.com/88213859/150418044-85900d1f-8890-4c60-baae-234342de71fa.gif)
This brings over several dependencies that are necessary:
- `formik`
- `yep`
Ports over some v1 code to bootstrap it:
- `FormTextField`
- `PasswordField`
- `CoderIcon`
And implements basic sign-in:
Fixes#37Fixes#43
This does not implement it navbar integration (importantly - there is no way to sign out yet, unless you manually delete your `session_token`). I'll do that in the next PR - figured this was big enough to get reviewed.
* chore: Fix golangci-lint configuration and patch errors
Due to misconfiguration of a linting rules directory, our linter has not been
working properly. This change fixes the configuration issue, and all remaining
linting errors.
* Fix race in peer logging
* Fix race and return
* Lock on bufferred amount low
* Fix mutex lock
While starting on the create workspace flow - I noticed some weird CSS issues.
In particular, intermittently, the web UI would render like this:
![image](https://user-images.githubusercontent.com/88213859/150072041-f1c6b9b2-941c-41a8-ad84-b7b163b3504f.png)
...and when that happened, there'd be an accompanying error in the console:
![image](https://user-images.githubusercontent.com/88213859/150072101-d98cb714-d133-4532-8a02-a7642d242a02.png)
The issue is that NextJS is trying to render the page on the server and use the styles - and sometimes the classnames mismatch between server-side and client-side rendering. We actually worked around this in `cdr/m` with a `<SafeHydration />` component and a custom `_document.tsx`
This change ports over both the component and custom `_document.tsx`. I noticed, in addition, I missed the favicons when switching to NextJS, so I brought those over too.
This change bundles the static assets like we have for v1 - using the [`embed`](https://pkg.go.dev/embed) go package. Fixes#22
In addition, it sets up a development script that runs `coderd` locally and serves the front-end, with hot-reloading. The script used is `./develop.sh`:
![2022-01-14 17 30 14](https://user-images.githubusercontent.com/88213859/149603926-f673d3d3-ba12-4eda-bcdd-427252405480.gif)
> NOTE: The UI is still placeholder, of course. Need to start testing out a simple, placeholder flow for the new v2 world as a next step
Summary of changes:
- Add build steps for `go` in the `Makefile`
- Add a step for production build, in which we use the `embed` tag
- Add a step for development, which doesn't need the `embed` tag - so we don't need to build the front-end twice
- Add `next export` build step to output front-end artifacts in `out`
- Add a `site` package for `go`
- Add `embed_static.go` and `embed.go`. This is mostly brought in as-is from v1, except removing some intercom/sentry CSP entries that we aren't using.
- Add a [next development server](https://nextjs.org/docs/advanced-features/custom-server)
- Add a `v2-dev` script, that runs `coderd` and the `next` dev server side-by-side
- Use the `site` package as the fallback handler.
- Add `.gitignore` entries for additional build collateral