From 028a478c38435a5b60e1f2d7136d09ced2878bf0 Mon Sep 17 00:00:00 2001 From: kylecarbs Date: Mon, 6 Jun 2022 02:42:12 +0000 Subject: [PATCH] feat: Add page titles Fixes #2069. --- site/htmlTemplates/index.html | 1 - site/package.json | 2 + .../SettingsLayout/SettingsLayout.tsx | 5 ++ site/src/pages/CliAuthPage/CliAuthPage.tsx | 5 ++ .../CreateWorkspacePage.tsx | 53 +++++++++++-------- site/src/pages/LoginPage/LoginPage.tsx | 5 ++ site/src/pages/TemplatePage/TemplatePage.tsx | 17 ++++-- .../src/pages/TemplatesPage/TemplatesPage.tsx | 17 ++++-- site/src/pages/TerminalPage/TerminalPage.tsx | 11 ++++ .../CreateUserPage/CreateUserPage.tsx | 5 ++ site/src/pages/UsersPage/UsersPage.tsx | 5 ++ .../WorkspaceBuildPage/WorkspaceBuildPage.tsx | 5 ++ .../src/pages/WorkspacePage/WorkspacePage.tsx | 5 ++ .../pages/WorkspacesPage/WorkspacesPage.tsx | 5 ++ site/src/util/page.ts | 3 ++ site/webpack.dev.ts | 2 +- site/yarn.lock | 24 ++++++++- 17 files changed, 134 insertions(+), 36 deletions(-) create mode 100644 site/src/util/page.ts diff --git a/site/htmlTemplates/index.html b/site/htmlTemplates/index.html index 78099f88007dd..3fc9d4dd41614 100644 --- a/site/htmlTemplates/index.html +++ b/site/htmlTemplates/index.html @@ -21,7 +21,6 @@ - Coder diff --git a/site/package.json b/site/package.json index f2adb1fafaf4a..932223e7b87fa 100644 --- a/site/package.json +++ b/site/package.json @@ -44,6 +44,7 @@ "history": "5.3.0", "react": "17.0.2", "react-dom": "17.0.2", + "react-helmet": "^6.1.0", "react-markdown": "8.0.3", "react-router-dom": "6.3.0", "sourcemapped-stacktrace": "1.1.11", @@ -73,6 +74,7 @@ "@types/node": "14.18.16", "@types/react": "17.0.44", "@types/react-dom": "17.0.16", + "@types/react-helmet": "^6.1.5", "@types/superagent": "4.1.15", "@types/uuid": "8.3.4", "@typescript-eslint/eslint-plugin": "5.23.0", diff --git a/site/src/components/SettingsLayout/SettingsLayout.tsx b/site/src/components/SettingsLayout/SettingsLayout.tsx index ba35c489fd419..9e1832344d8f2 100644 --- a/site/src/components/SettingsLayout/SettingsLayout.tsx +++ b/site/src/components/SettingsLayout/SettingsLayout.tsx @@ -1,6 +1,8 @@ import Box from "@material-ui/core/Box" import { FC } from "react" +import { Helmet } from "react-helmet" import { Outlet } from "react-router-dom" +import { pageTitle } from "../../util/page" import { AuthAndFrame } from "../AuthAndFrame/AuthAndFrame" import { Margins } from "../Margins/Margins" import { TabPanel } from "../TabPanel/TabPanel" @@ -22,6 +24,9 @@ export const SettingsLayout: FC = () => { return ( + + {pageTitle("Settings")} + diff --git a/site/src/pages/CliAuthPage/CliAuthPage.tsx b/site/src/pages/CliAuthPage/CliAuthPage.tsx index ed9a8b73b7cba..52633c81ac722 100644 --- a/site/src/pages/CliAuthPage/CliAuthPage.tsx +++ b/site/src/pages/CliAuthPage/CliAuthPage.tsx @@ -1,9 +1,11 @@ import { makeStyles } from "@material-ui/core/styles" import { useActor } from "@xstate/react" import React, { useContext, useEffect, useState } from "react" +import { Helmet } from "react-helmet" import { getApiKey } from "../../api/api" import { CliAuthToken } from "../../components/CliAuthToken/CliAuthToken" import { FullScreenLoader } from "../../components/Loader/FullScreenLoader" +import { pageTitle } from "../../util/page" import { XServiceContext } from "../../xServices/StateContext" export const CliAuthenticationPage: React.FC = () => { @@ -29,6 +31,9 @@ export const CliAuthenticationPage: React.FC = () => { return (
+ + {pageTitle("CLI Auth")} +
) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx index f4b41a517f11a..9749a75413adf 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx @@ -1,8 +1,10 @@ import { useMachine } from "@xstate/react" import { FC } from "react" +import { Helmet } from "react-helmet" import { useNavigate, useSearchParams } from "react-router-dom" import { Template } from "../../api/typesGenerated" import { useOrganizationId } from "../../hooks/useOrganizationId" +import { pageTitle } from "../../util/page" import { createWorkspaceMachine } from "../../xServices/createWorkspace/createWorkspaceXService" import { CreateWorkspacePageView } from "./CreateWorkspacePageView" @@ -21,29 +23,34 @@ const CreateWorkspacePage: FC = () => { }) return ( - { - navigate(preSelectedTemplateName ? "/templates" : "/workspaces") - }} - onSubmit={(request) => { - send({ - type: "CREATE_WORKSPACE", - request, - }) - }} - onSelectTemplate={(template: Template) => { - send({ - type: "SELECT_TEMPLATE", - template, - }) - }} - /> + <> + + {pageTitle("Create Workspace")} + + { + navigate(preSelectedTemplateName ? "/templates" : "/workspaces") + }} + onSubmit={(request) => { + send({ + type: "CREATE_WORKSPACE", + request, + }) + }} + onSelectTemplate={(template: Template) => { + send({ + type: "SELECT_TEMPLATE", + template, + }) + }} + /> + ) } diff --git a/site/src/pages/LoginPage/LoginPage.tsx b/site/src/pages/LoginPage/LoginPage.tsx index cc3d8eb6e6efb..02acc7311d9ab 100644 --- a/site/src/pages/LoginPage/LoginPage.tsx +++ b/site/src/pages/LoginPage/LoginPage.tsx @@ -1,10 +1,12 @@ import { makeStyles } from "@material-ui/core/styles" import { useActor } from "@xstate/react" import React, { useContext } from "react" +import { Helmet } from "react-helmet" import { Navigate, useLocation } from "react-router-dom" import { isApiError } from "../../api/errors" import { Footer } from "../../components/Footer/Footer" import { SignInForm } from "../../components/SignInForm/SignInForm" +import { pageTitle } from "../../util/page" import { retrieveRedirect } from "../../util/redirect" import { XServiceContext } from "../../xServices/StateContext" @@ -50,6 +52,9 @@ export const LoginPage: React.FC = () => { } else { return (
+ + {pageTitle("Login")} +
{ } return ( - + <> + + {pageTitle(`${template.name} · Template`)} + + + ) } diff --git a/site/src/pages/TemplatesPage/TemplatesPage.tsx b/site/src/pages/TemplatesPage/TemplatesPage.tsx index 545634172ca22..0b7559f52eb06 100644 --- a/site/src/pages/TemplatesPage/TemplatesPage.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPage.tsx @@ -1,5 +1,7 @@ import { useActor, useMachine } from "@xstate/react" import React, { useContext } from "react" +import { Helmet } from "react-helmet" +import { pageTitle } from "../../util/page" import { XServiceContext } from "../../xServices/StateContext" import { templatesMachine } from "../../xServices/templates/templatesXService" import { TemplatesPageView } from "./TemplatesPageView" @@ -10,11 +12,16 @@ const TemplatesPage: React.FC = () => { const [templatesState] = useMachine(templatesMachine) return ( - + <> + + {pageTitle("Templates")} + + + ) } diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx index 55460ecb615b8..43ea72aac3c2e 100644 --- a/site/src/pages/TerminalPage/TerminalPage.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.tsx @@ -1,6 +1,7 @@ import { makeStyles } from "@material-ui/core/styles" import { useMachine } from "@xstate/react" import { FC, useEffect, useRef, useState } from "react" +import { Helmet } from "react-helmet" import { useLocation, useNavigate, useParams } from "react-router-dom" import { v4 as uuidv4 } from "uuid" import * as XTerm from "xterm" @@ -8,6 +9,7 @@ import { FitAddon } from "xterm-addon-fit" import { WebLinksAddon } from "xterm-addon-web-links" import "xterm/css/xterm.css" import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" +import { pageTitle } from "../../util/page" import { terminalMachine } from "../../xServices/terminal/terminalXService" export const Language = { @@ -179,6 +181,15 @@ const TerminalPage: FC<{ return ( <> + + + {terminalState.context.workspace + ? pageTitle( + `Terminal · ${terminalState.context.workspace.owner_name}/${terminalState.context.workspace.name}`, + ) + : ""} + + {/* This overlay makes it more obvious that the terminal is disconnected. */} {/* It's nice for situations where Coder restarts, and they are temporarily disconnected. */}
diff --git a/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx b/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx index c5ddc98adcb3e..907835753d705 100644 --- a/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx +++ b/site/src/pages/UsersPage/CreateUserPage/CreateUserPage.tsx @@ -1,9 +1,11 @@ import { useActor, useSelector } from "@xstate/react" import React, { useContext } from "react" +import { Helmet } from "react-helmet" import { useNavigate } from "react-router" import * as TypesGen from "../../../api/typesGenerated" import { CreateUserForm } from "../../../components/CreateUserForm/CreateUserForm" import { Margins } from "../../../components/Margins/Margins" +import { pageTitle } from "../../../util/page" import { selectOrgId } from "../../../xServices/auth/authSelectors" import { XServiceContext } from "../../../xServices/StateContext" @@ -23,6 +25,9 @@ export const CreateUserPage: React.FC = () => { return ( + + {pageTitle("Create User")} + usersSend({ type: "CREATE", user })} diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx index e28b962b2b634..0aa095dc46e98 100644 --- a/site/src/pages/UsersPage/UsersPage.tsx +++ b/site/src/pages/UsersPage/UsersPage.tsx @@ -1,8 +1,10 @@ import { useActor, useSelector } from "@xstate/react" import React, { useContext, useEffect } from "react" +import { Helmet } from "react-helmet" import { useNavigate } from "react-router" import { ConfirmDialog } from "../../components/ConfirmDialog/ConfirmDialog" import { ResetPasswordDialog } from "../../components/ResetPasswordDialog/ResetPasswordDialog" +import { pageTitle } from "../../util/page" import { selectPermissions } from "../../xServices/auth/authSelectors" import { XServiceContext } from "../../xServices/StateContext" import { UsersPageView } from "./UsersPageView" @@ -48,6 +50,9 @@ export const UsersPage: React.FC = () => { return ( <> + + {pageTitle("Users")} + { @@ -34,6 +36,9 @@ export const WorkspaceBuildPage: FC = () => { return ( + + {build ? pageTitle(`Build #${build.build_number} · ${build.workspace_name}`) : ""} + Logs diff --git a/site/src/pages/WorkspacePage/WorkspacePage.tsx b/site/src/pages/WorkspacePage/WorkspacePage.tsx index 5dced78ba09e1..8d9f3d30f08ab 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.tsx @@ -1,5 +1,6 @@ import { useMachine } from "@xstate/react" import React, { useEffect } from "react" +import { Helmet } from "react-helmet" import { useNavigate, useParams } from "react-router-dom" import { DeleteWorkspaceDialog } from "../../components/DeleteWorkspaceDialog/DeleteWorkspaceDialog" import { ErrorSummary } from "../../components/ErrorSummary/ErrorSummary" @@ -8,6 +9,7 @@ import { Margins } from "../../components/Margins/Margins" import { Stack } from "../../components/Stack/Stack" import { Workspace } from "../../components/Workspace/Workspace" import { firstOrItem } from "../../util/array" +import { pageTitle } from "../../util/page" import { workspaceMachine } from "../../xServices/workspace/workspaceXService" import { workspaceScheduleBannerMachine } from "../../xServices/workspaceSchedule/workspaceScheduleBannerXService" @@ -36,6 +38,9 @@ export const WorkspacePage: React.FC = () => { } else { return ( + + {pageTitle(`${workspace.owner_name}/${workspace.name}`)} + <> { return ( + + {pageTitle("Workspaces")} + diff --git a/site/src/util/page.ts b/site/src/util/page.ts new file mode 100644 index 0000000000000..e7dcac0f78285 --- /dev/null +++ b/site/src/util/page.ts @@ -0,0 +1,3 @@ +export const pageTitle = (prefix: string): string => { + return `${prefix} – Coder` +} diff --git a/site/webpack.dev.ts b/site/webpack.dev.ts index 1e3b80f2de873..aa66120ed516c 100644 --- a/site/webpack.dev.ts +++ b/site/webpack.dev.ts @@ -63,7 +63,7 @@ const config: Configuration = { port: process.env.PORT || 8080, proxy: { "/api": { - target: "http://localhost:3000", + target: "https://dev.coder.com", ws: true, secure: false, }, diff --git a/site/yarn.lock b/site/yarn.lock index 76bbd151e9aad..ff6ce7e09aac1 100644 --- a/site/yarn.lock +++ b/site/yarn.lock @@ -3041,6 +3041,13 @@ dependencies: "@types/react" "^17" +"@types/react-helmet@^6.1.5": + version "6.1.5" + resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.5.tgz#35f89a6b1646ee2bc342a33a9a6c8777933f9083" + integrity sha512-/ICuy7OHZxR0YCAZLNg9r7I9aijWUWvxaPR6uTuyxe8tAj5RL4Sw1+R6NhXUtOsarkGYPmaHdBDvuXh2DIN/uA== + dependencies: + "@types/react" "*" + "@types/react-syntax-highlighter@11.0.5": version "11.0.5" resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.5.tgz#0d546261b4021e1f9d85b50401c0a42acb106087" @@ -11389,7 +11396,7 @@ react-fast-compare@^2.0.1: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== -react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: +react-fast-compare@^3.0.1, react-fast-compare@^3.1.1, react-fast-compare@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== @@ -11405,6 +11412,16 @@ react-helmet-async@^1.0.7: react-fast-compare "^3.2.0" shallowequal "^1.1.0" +react-helmet@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" + integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw== + dependencies: + object-assign "^4.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.1.1" + react-side-effect "^2.1.0" + react-hot-loader@4.13.0: version "4.13.0" resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.13.0.tgz#c27e9408581c2a678f5316e69c061b226dc6a202" @@ -11506,6 +11523,11 @@ react-router@6.3.0, react-router@^6.0.0: dependencies: history "^5.2.0" +react-side-effect@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3" + integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ== + react-sizeme@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-3.0.2.tgz#4a2f167905ba8f8b8d932a9e35164e459f9020e4"