From 19876a7657894e919647ef1b9ec1acfd9ab5d3bb Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Thu, 3 Nov 2022 15:33:31 +0000 Subject: [PATCH 1/9] Use empty page message on workspaces page --- .../WorkspacesTable/WorkspacesTableBody.tsx | 97 ++++++++++--------- site/src/i18n/en/index.ts | 2 + site/src/i18n/en/workspacesPage.json | 7 ++ 3 files changed, 58 insertions(+), 48 deletions(-) create mode 100644 site/src/i18n/en/workspacesPage.json diff --git a/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx b/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx index ca4d588127cbc..c6bdb1ff0810c 100644 --- a/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx +++ b/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx @@ -3,22 +3,16 @@ import Link from "@material-ui/core/Link" import TableCell from "@material-ui/core/TableCell" import TableRow from "@material-ui/core/TableRow" import AddCircleOutline from "@material-ui/icons/AddCircleOutline" +import { ChooseOne, Cond } from "components/Conditionals/ChooseOne" import { FC } from "react" -import { Link as RouterLink } from "react-router-dom" +import { useTranslation } from "react-i18next" +import { Link as RouterLink, useSearchParams } from "react-router-dom" import { workspaceFilterQuery } from "../../util/filters" import { WorkspaceItemMachineRef } from "../../xServices/workspaces/workspacesXService" import { EmptyState } from "../EmptyState/EmptyState" import { TableLoader } from "../TableLoader/TableLoader" import { WorkspacesRow } from "./WorkspacesRow" -export const Language = { - emptyCreateWorkspaceMessage: "Create your first workspace", - emptyCreateWorkspaceDescription: - "Start editing your source code and building your software.", - createFromTemplateButton: "Create from template", - emptyResultsMessage: "No results matched your search", -} - interface TableBodyProps { isLoading?: boolean workspaceRefs?: WorkspaceItemMachineRef[] @@ -28,46 +22,53 @@ interface TableBodyProps { export const WorkspacesTableBody: FC< React.PropsWithChildren > = ({ isLoading, workspaceRefs, filter }) => { - if (isLoading) { - return - } - - if (!workspaceRefs || workspaceRefs.length === 0) { - return ( - <> - {filter === workspaceFilterQuery.me || - filter === workspaceFilterQuery.all ? ( - - - - - - } - /> - - - ) : ( - - - - - - )} - - ) - } + const [searchParams, _] = useSearchParams() + const page = parseInt(searchParams.get("page") ?? "1") + const { t } = useTranslation("workspacesPage") + console.log(searchParams.get("page"), page) return ( - <> - {workspaceRefs.map((workspaceRef) => ( - - ))} - + + + + + + + + + 1}> + + + + + + + } + /> + + + + + + + + + + {workspaceRefs && + workspaceRefs.map((workspaceRef) => ( + + ))} + + ) } diff --git a/site/src/i18n/en/index.ts b/site/src/i18n/en/index.ts index 653ac3ed8553b..2d7ff490c0d16 100644 --- a/site/src/i18n/en/index.ts +++ b/site/src/i18n/en/index.ts @@ -6,6 +6,7 @@ import templatesPage from "./templatesPage.json" import workspacePage from "./workspacePage.json" import agent from "./agent.json" import buildPage from "./buildPage.json" +import workspacesPage from "./workspacesPage.json" export const en = { common, @@ -16,4 +17,5 @@ export const en = { createWorkspacePage, agent, buildPage, + workspacesPage } diff --git a/site/src/i18n/en/workspacesPage.json b/site/src/i18n/en/workspacesPage.json new file mode 100644 index 0000000000000..1bcb1b6f77c1b --- /dev/null +++ b/site/src/i18n/en/workspacesPage.json @@ -0,0 +1,7 @@ +{ + "emptyCreateWorkspaceMessage": "Create your first workspace", + "emptyCreateWorkspaceDescription": "Start editing your source code and building your software.", + "createFromTemplateButton": "Create from template", + "emptyResultsMessage": "No results matched your search", + "emptyPageMessage": "No results on this page" +} From 609e7c228412b86613ca57ca91343e24da014f59 Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Thu, 3 Nov 2022 16:54:32 +0000 Subject: [PATCH 2/9] Add prop for story --- site/src/components/PaginationWidget/utils.ts | 6 ++++++ .../components/WorkspacesTable/WorkspacesTable.tsx | 4 +++- .../WorkspacesTable/WorkspacesTableBody.tsx | 11 +++++------ site/src/pages/WorkspacesPage/WorkspacesPage.tsx | 3 ++- .../WorkspacesPage/WorkspacesPageView.stories.tsx | 11 +++++++++++ site/src/pages/WorkspacesPage/WorkspacesPageView.tsx | 3 +++ 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/site/src/components/PaginationWidget/utils.ts b/site/src/components/PaginationWidget/utils.ts index 5d48660b05e0f..22826c5680d1e 100644 --- a/site/src/components/PaginationWidget/utils.ts +++ b/site/src/components/PaginationWidget/utils.ts @@ -102,3 +102,9 @@ export const createPaginationRef = ( ): PaginationMachineRef => { return spawn(paginationMachine.withContext(context)) } + +export const isNonInitialPage = (searchParams: URLSearchParams): boolean => { + const page = searchParams.get("page") + const numberPage = page ? Number(page) : 1 + return numberPage > 1 +} diff --git a/site/src/components/WorkspacesTable/WorkspacesTable.tsx b/site/src/components/WorkspacesTable/WorkspacesTable.tsx index 0d20841d10580..07b0e91de2c20 100644 --- a/site/src/components/WorkspacesTable/WorkspacesTable.tsx +++ b/site/src/components/WorkspacesTable/WorkspacesTable.tsx @@ -21,11 +21,12 @@ export interface WorkspacesTableProps { isLoading?: boolean workspaceRefs?: WorkspaceItemMachineRef[] filter?: string + isNonInitialPage: boolean } export const WorkspacesTable: FC< React.PropsWithChildren -> = ({ isLoading, workspaceRefs, filter }) => { +> = ({ isLoading, workspaceRefs, filter, isNonInitialPage }) => { return ( @@ -44,6 +45,7 @@ export const WorkspacesTable: FC< isLoading={isLoading} workspaceRefs={workspaceRefs} filter={filter} + isNonInitialPage={isNonInitialPage} />
diff --git a/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx b/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx index c6bdb1ff0810c..093ff474b110f 100644 --- a/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx +++ b/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx @@ -6,7 +6,7 @@ import AddCircleOutline from "@material-ui/icons/AddCircleOutline" import { ChooseOne, Cond } from "components/Conditionals/ChooseOne" import { FC } from "react" import { useTranslation } from "react-i18next" -import { Link as RouterLink, useSearchParams } from "react-router-dom" +import { Link as RouterLink } from "react-router-dom" import { workspaceFilterQuery } from "../../util/filters" import { WorkspaceItemMachineRef } from "../../xServices/workspaces/workspacesXService" import { EmptyState } from "../EmptyState/EmptyState" @@ -17,15 +17,14 @@ interface TableBodyProps { isLoading?: boolean workspaceRefs?: WorkspaceItemMachineRef[] filter?: string + isNonInitialPage: boolean } export const WorkspacesTableBody: FC< React.PropsWithChildren -> = ({ isLoading, workspaceRefs, filter }) => { - const [searchParams, _] = useSearchParams() - const page = parseInt(searchParams.get("page") ?? "1") +> = ({ isLoading, workspaceRefs, filter, isNonInitialPage }) => { const { t } = useTranslation("workspacesPage") - console.log(searchParams.get("page"), page) + console.log(isNonInitialPage) return ( @@ -36,7 +35,7 @@ export const WorkspacesTableBody: FC< - 1}> + diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx index c8204c2f9ee40..0af06d38f4638 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx @@ -1,5 +1,5 @@ import { useMachine } from "@xstate/react" -import { getPaginationContext } from "components/PaginationWidget/utils" +import { getPaginationContext, isNonInitialPage } from "components/PaginationWidget/utils" import { FC } from "react" import { Helmet } from "react-helmet-async" import { useSearchParams } from "react-router-dom" @@ -49,6 +49,7 @@ const WorkspacesPage: FC = () => { }) }} paginationRef={paginationRef} + isNonInitialPage={isNonInitialPage(searchParams)} /> ) diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx index 2b06e238e6791..166f14b2a2474 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx @@ -112,6 +112,7 @@ AllStates.args = { ...Object.values(additionalWorkspaces), ], count: 14, + isNonInitialPage: false } export const OwnerHasNoWorkspaces = Template.bind({}) @@ -119,6 +120,7 @@ OwnerHasNoWorkspaces.args = { workspaceRefs: [], filter: workspaceFilterQuery.me, count: 0, + isNonInitialPage: false } export const NoResults = Template.bind({}) @@ -126,4 +128,13 @@ NoResults.args = { workspaceRefs: [], filter: "searchtearmwithnoresults", count: 0, + isNonInitialPage: false +} + +export const EmptyPage = Template.bind({}) +EmptyPage.args = { + workspaceRefs: [], + filter: workspaceFilterQuery.me, + count: 0, + isNonInitialPage: true } diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx index 0b403d01de7cf..881c0d9965138 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx @@ -36,6 +36,7 @@ export interface WorkspacesPageViewProps { filter?: string onFilter: (query: string) => void paginationRef: PaginationMachineRef + isNonInitialPage: boolean } export const WorkspacesPageView: FC< @@ -49,6 +50,7 @@ export const WorkspacesPageView: FC< filter, onFilter, paginationRef, + isNonInitialPage }) => { const presetFilters = [ { query: workspaceFilterQuery.me, name: Language.yourWorkspacesButton }, @@ -105,6 +107,7 @@ export const WorkspacesPageView: FC< isLoading={isLoading} workspaceRefs={workspaceRefs} filter={filter} + isNonInitialPage={isNonInitialPage} /> From 52f4a1b4ba98ee74b54f46b1e068a0c1864c7e4e Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Thu, 3 Nov 2022 22:11:17 +0000 Subject: [PATCH 3/9] AuditPage --- .../WorkspacesTable/WorkspacesTableBody.tsx | 7 ++- site/src/i18n/en/auditLog.json | 4 ++ site/src/i18n/en/index.ts | 2 +- site/src/pages/AuditPage/AuditPage.tsx | 6 ++- .../pages/AuditPage/AuditPageView.stories.tsx | 20 +++++++ site/src/pages/AuditPage/AuditPageView.tsx | 54 +++++++++++++------ .../pages/WorkspacesPage/WorkspacesPage.tsx | 5 +- .../WorkspacesPageView.stories.tsx | 8 +-- .../WorkspacesPage/WorkspacesPageView.tsx | 2 +- 9 files changed, 82 insertions(+), 26 deletions(-) diff --git a/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx b/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx index 093ff474b110f..9c858f5694707 100644 --- a/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx +++ b/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx @@ -38,7 +38,12 @@ export const WorkspacesTableBody: FC< - + { auditSend("FILTER", { filter }) }} paginationRef={paginationRef} + isNonInitialPage={isNonInitialPage(searchParams)} /> ) diff --git a/site/src/pages/AuditPage/AuditPageView.stories.tsx b/site/src/pages/AuditPage/AuditPageView.stories.tsx index d02275f2b45b9..a645039e427ac 100644 --- a/site/src/pages/AuditPage/AuditPageView.stories.tsx +++ b/site/src/pages/AuditPage/AuditPageView.stories.tsx @@ -25,6 +25,26 @@ const Template: Story = (args) => ( export const AuditPage = Template.bind({}) +export const Loading = Template.bind({}) +Loading.args = { + auditLogs: undefined, + count: undefined, + isNonInitialPage: false, +} + +export const EmptyPage = Template.bind({}) +EmptyPage.args = { + auditLogs: [], + isNonInitialPage: true, +} + +export const NoLogs = Template.bind({}) +NoLogs.args = { + auditLogs: [], + count: 0, + isNonInitialPage: false, +} + export const AuditPageSmallViewport = Template.bind({}) AuditPageSmallViewport.parameters = { chromatic: { viewports: [600] }, diff --git a/site/src/pages/AuditPage/AuditPageView.tsx b/site/src/pages/AuditPage/AuditPageView.tsx index 8ab90b8420db0..60e731c0082cf 100644 --- a/site/src/pages/AuditPage/AuditPageView.tsx +++ b/site/src/pages/AuditPage/AuditPageView.tsx @@ -5,6 +5,7 @@ import TableContainer from "@material-ui/core/TableContainer" import TableRow from "@material-ui/core/TableRow" import { AuditLog } from "api/typesGenerated" import { AuditLogRow } from "components/AuditLogRow/AuditLogRow" +import { ChooseOne, Cond } from "components/Conditionals/ChooseOne" import { EmptyState } from "components/EmptyState/EmptyState" import { Margins } from "components/Margins/Margins" import { @@ -19,6 +20,7 @@ import { TableLoader } from "components/TableLoader/TableLoader" import { Timeline } from "components/Timeline/Timeline" import { AuditHelpTooltip } from "components/Tooltips" import { FC } from "react" +import { useTranslation } from "react-i18next" import { PaginationMachineRef } from "xServices/pagination/paginationXService" export const Language = { @@ -43,6 +45,7 @@ export interface AuditPageViewProps { filter: string onFilter: (filter: string) => void paginationRef: PaginationMachineRef + isNonInitialPage: boolean } export const AuditPageView: FC = ({ @@ -51,7 +54,9 @@ export const AuditPageView: FC = ({ filter, onFilter, paginationRef, + isNonInitialPage, }) => { + const { t } = useTranslation("auditLog") const isLoading = auditLogs === undefined || count === undefined const isEmpty = !isLoading && auditLogs.length === 0 @@ -77,23 +82,38 @@ export const AuditPageView: FC = ({ - {isLoading && } - - {auditLogs && ( - new Date(log.time)} - row={(log) => } - /> - )} - - {isEmpty && ( - - - - - - )} + + + + + + + + + + + + + + + + + + + + + + + + {auditLogs && ( + new Date(log.time)} + row={(log) => } + /> + )} + +
diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx index 0af06d38f4638..d86c569d85631 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx @@ -1,5 +1,8 @@ import { useMachine } from "@xstate/react" -import { getPaginationContext, isNonInitialPage } from "components/PaginationWidget/utils" +import { + getPaginationContext, + isNonInitialPage, +} from "components/PaginationWidget/utils" import { FC } from "react" import { Helmet } from "react-helmet-async" import { useSearchParams } from "react-router-dom" diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx index 166f14b2a2474..18dbc66405a51 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx @@ -112,7 +112,7 @@ AllStates.args = { ...Object.values(additionalWorkspaces), ], count: 14, - isNonInitialPage: false + isNonInitialPage: false, } export const OwnerHasNoWorkspaces = Template.bind({}) @@ -120,7 +120,7 @@ OwnerHasNoWorkspaces.args = { workspaceRefs: [], filter: workspaceFilterQuery.me, count: 0, - isNonInitialPage: false + isNonInitialPage: false, } export const NoResults = Template.bind({}) @@ -128,7 +128,7 @@ NoResults.args = { workspaceRefs: [], filter: "searchtearmwithnoresults", count: 0, - isNonInitialPage: false + isNonInitialPage: false, } export const EmptyPage = Template.bind({}) @@ -136,5 +136,5 @@ EmptyPage.args = { workspaceRefs: [], filter: workspaceFilterQuery.me, count: 0, - isNonInitialPage: true + isNonInitialPage: true, } diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx index 881c0d9965138..7eeafb6f514b7 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx @@ -50,7 +50,7 @@ export const WorkspacesPageView: FC< filter, onFilter, paginationRef, - isNonInitialPage + isNonInitialPage, }) => { const presetFilters = [ { query: workspaceFilterQuery.me, name: Language.yourWorkspacesButton }, From 9f1bd8fae2338ad09d198a4339dd0b7beb0c91db Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Thu, 3 Nov 2022 22:48:23 +0000 Subject: [PATCH 4/9] UsersPage --- site/src/components/PaginationWidget/utils.ts | 2 +- site/src/components/UsersTable/UsersTable.tsx | 3 + .../components/UsersTable/UsersTableBody.tsx | 253 ++++++++++-------- site/src/i18n/en/index.ts | 2 + site/src/i18n/en/usersPage.json | 9 + site/src/pages/AuditPage/AuditPage.tsx | 4 +- site/src/pages/UsersPage/UsersPage.tsx | 6 +- .../pages/UsersPage/UsersPageView.stories.tsx | 28 +- site/src/pages/UsersPage/UsersPageView.tsx | 3 + .../pages/WorkspacesPage/WorkspacesPage.tsx | 4 +- 10 files changed, 179 insertions(+), 135 deletions(-) create mode 100644 site/src/i18n/en/usersPage.json diff --git a/site/src/components/PaginationWidget/utils.ts b/site/src/components/PaginationWidget/utils.ts index 22826c5680d1e..a2cd41880ef2c 100644 --- a/site/src/components/PaginationWidget/utils.ts +++ b/site/src/components/PaginationWidget/utils.ts @@ -103,7 +103,7 @@ export const createPaginationRef = ( return spawn(paginationMachine.withContext(context)) } -export const isNonInitialPage = (searchParams: URLSearchParams): boolean => { +export const nonInitialPage = (searchParams: URLSearchParams): boolean => { const page = searchParams.get("page") const numberPage = page ? Number(page) : 1 return numberPage > 1 diff --git a/site/src/components/UsersTable/UsersTable.tsx b/site/src/components/UsersTable/UsersTable.tsx index 05eb6b501fbee..1226d8591fbf0 100644 --- a/site/src/components/UsersTable/UsersTable.tsx +++ b/site/src/components/UsersTable/UsersTable.tsx @@ -32,6 +32,7 @@ export interface UsersTableProps { user: TypesGen.User, roles: TypesGen.Role["name"][], ) => void + isNonInitialPage: boolean } export const UsersTable: FC> = ({ @@ -46,6 +47,7 @@ export const UsersTable: FC> = ({ isUpdatingUserRoles, canEditUsers, isLoading, + isNonInitialPage, }) => { return ( @@ -78,6 +80,7 @@ export const UsersTable: FC> = ({ onResetUserPassword={onResetUserPassword} onSuspendUser={onSuspendUser} onUpdateUserRoles={onUpdateUserRoles} + isNonInitialPage={isNonInitialPage} /> diff --git a/site/src/components/UsersTable/UsersTableBody.tsx b/site/src/components/UsersTable/UsersTableBody.tsx index de1a6573b8898..b97dbc05c2e7e 100644 --- a/site/src/components/UsersTable/UsersTableBody.tsx +++ b/site/src/components/UsersTable/UsersTableBody.tsx @@ -2,8 +2,10 @@ import Box from "@material-ui/core/Box" import { makeStyles } from "@material-ui/core/styles" import TableCell from "@material-ui/core/TableCell" import TableRow from "@material-ui/core/TableRow" +import { ChooseOne, Cond } from "components/Conditionals/ChooseOne" import { LastUsed } from "components/LastUsed/LastUsed" import { FC } from "react" +import { useTranslation } from "react-i18next" import * as TypesGen from "../../api/typesGenerated" import { combineClasses } from "../../util/combineClasses" import { AvatarData } from "../AvatarData/AvatarData" @@ -12,15 +14,6 @@ import { RoleSelect } from "../RoleSelect/RoleSelect" import { TableLoader } from "../TableLoader/TableLoader" import { TableRowMenu } from "../TableRowMenu/TableRowMenu" -export const Language = { - emptyMessage: "No users found", - suspendMenuItem: "Suspend", - deleteMenuItem: "Delete", - listWorkspacesMenuItem: "View workspaces", - activateMenuItem: "Activate", - resetPasswordMenuItem: "Reset password", -} - interface UsersTableBodyProps { users?: TypesGen.User[] roles?: TypesGen.AssignableRoles[] @@ -36,6 +29,7 @@ interface UsersTableBodyProps { user: TypesGen.User, roles: TypesGen.Role["name"][], ) => void + isNonInitialPage: boolean } export const UsersTableBody: FC< @@ -52,121 +46,144 @@ export const UsersTableBody: FC< isUpdatingUserRoles, canEditUsers, isLoading, + isNonInitialPage, }) => { const styles = useStyles() - - if (isLoading) { - return - } - - if (!users || users.length === 0) { - return ( - - - - - - - - ) - } + const { t } = useTranslation("usersPage") return ( - <> - {users.map((user) => { - // When the user has no role we want to show they are a Member - const fallbackRole: TypesGen.Role = { - name: "member", - display_name: "Member", - } - const userRoles = user.roles.length === 0 ? [fallbackRole] : user.roles + + + + + + + + + + + + + + + + + + + + + + + + + + + + <> + {users && + users.map((user) => { + // When the user has no role we want to show they are a Member + const fallbackRole: TypesGen.Role = { + name: "member", + display_name: "Member", + } + const userRoles = + user.roles.length === 0 ? [fallbackRole] : user.roles - return ( - - - + + + ) : null + } /> - ) : null - } - /> - - - {user.status} - - - - - - {canEditUsers ? ( - { - // Remove the fallback role because it is only for the UI - roles = roles.filter((role) => role !== fallbackRole.name) - onUpdateUserRoles(user, roles) - }} - /> - ) : ( - <>{userRoles.map((role) => role.display_name).join(", ")} - )} - - {canEditUsers && ( - - - - )} - - ) - })} - +
+ + {user.status} + + + + + + {canEditUsers ? ( + { + // Remove the fallback role because it is only for the UI + roles = roles.filter( + (role) => role !== fallbackRole.name, + ) + onUpdateUserRoles(user, roles) + }} + /> + ) : ( + <> + {userRoles.map((role) => role.display_name).join(", ")} + + )} + + {canEditUsers && ( + + + + )} +
+ ) + })} + + +
) } diff --git a/site/src/i18n/en/index.ts b/site/src/i18n/en/index.ts index 40cf10974703e..3b710390cafd2 100644 --- a/site/src/i18n/en/index.ts +++ b/site/src/i18n/en/index.ts @@ -7,6 +7,7 @@ import workspacePage from "./workspacePage.json" import agent from "./agent.json" import buildPage from "./buildPage.json" import workspacesPage from "./workspacesPage.json" +import usersPage from "./usersPage.json" export const en = { common, @@ -18,4 +19,5 @@ export const en = { agent, buildPage, workspacesPage, + usersPage, } diff --git a/site/src/i18n/en/usersPage.json b/site/src/i18n/en/usersPage.json new file mode 100644 index 0000000000000..e1f84b93df7f5 --- /dev/null +++ b/site/src/i18n/en/usersPage.json @@ -0,0 +1,9 @@ +{ + "emptyMessage": "No users found", + "emptyPageMessage": "No users found on this page", + "suspendMenuItem": "Suspend", + "deleteMenuItem": "Delete", + "listWorkspacesMenuItem": "View workspaces", + "activateMenuItem": "Activate", + "resetPasswordMenuItem": "Reset password" +} diff --git a/site/src/pages/AuditPage/AuditPage.tsx b/site/src/pages/AuditPage/AuditPage.tsx index 013c8a7c50835..ff43d0e065888 100644 --- a/site/src/pages/AuditPage/AuditPage.tsx +++ b/site/src/pages/AuditPage/AuditPage.tsx @@ -1,7 +1,7 @@ import { useMachine } from "@xstate/react" import { getPaginationContext, - isNonInitialPage, + nonInitialPage, } from "components/PaginationWidget/utils" import { FC } from "react" import { Helmet } from "react-helmet-async" @@ -41,7 +41,7 @@ const AuditPage: FC = () => { auditSend("FILTER", { filter }) }} paginationRef={paginationRef} - isNonInitialPage={isNonInitialPage(searchParams)} + isNonInitialPage={nonInitialPage(searchParams)} /> ) diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx index 66303ebb033c5..ef4e9de025286 100644 --- a/site/src/pages/UsersPage/UsersPage.tsx +++ b/site/src/pages/UsersPage/UsersPage.tsx @@ -1,7 +1,10 @@ import { useActor, useMachine } from "@xstate/react" import { User } from "api/typesGenerated" import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog" -import { getPaginationContext } from "components/PaginationWidget/utils" +import { + getPaginationContext, + nonInitialPage, +} from "components/PaginationWidget/utils" import { usePermissions } from "hooks/usePermissions" import { FC, ReactNode, useContext, useEffect } from "react" import { Helmet } from "react-helmet-async" @@ -127,6 +130,7 @@ export const UsersPage: FC<{ children?: ReactNode }> = () => { usersSend({ type: "UPDATE_FILTER", query }) }} paginationRef={paginationRef} + isNonInitialPage={nonInitialPage(searchParams)} /> @@ -22,29 +34,23 @@ const Template: Story = (args) => ( ) export const Admin = Template.bind({}) -Admin.args = { - users: [MockUser, MockUser2], - roles: MockAssignableSiteRoles, - canEditUsers: true, -} export const SmallViewport = Template.bind({}) -SmallViewport.args = { - ...Admin.args, -} SmallViewport.parameters = { chromatic: { viewports: [600] }, } export const Member = Template.bind({}) -Member.args = { ...Admin.args, canEditUsers: false } +Member.args = { canEditUsers: false } export const Empty = Template.bind({}) -Empty.args = { ...Admin.args, users: [] } +Empty.args = { users: [] } + +export const EmptyPage = Template.bind({}) +EmptyPage.args = { users: [], isNonInitialPage: true } export const Error = Template.bind({}) Error.args = { - ...Admin.args, users: undefined, error: { response: { diff --git a/site/src/pages/UsersPage/UsersPageView.tsx b/site/src/pages/UsersPage/UsersPageView.tsx index 9a80140a1d048..886818fc610ff 100644 --- a/site/src/pages/UsersPage/UsersPageView.tsx +++ b/site/src/pages/UsersPage/UsersPageView.tsx @@ -29,6 +29,7 @@ export interface UsersPageViewProps { ) => void onFilter: (query: string) => void paginationRef: PaginationMachineRef + isNonInitialPage: boolean } export const UsersPageView: FC> = ({ @@ -47,6 +48,7 @@ export const UsersPageView: FC> = ({ filter, onFilter, paginationRef, + isNonInitialPage, }) => { const presetFilters = [ { query: userFilterQuery.active, name: Language.activeUsersFilterName }, @@ -74,6 +76,7 @@ export const UsersPageView: FC> = ({ isUpdatingUserRoles={isUpdatingUserRoles} canEditUsers={canEditUsers} isLoading={isLoading} + isNonInitialPage={isNonInitialPage} /> diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx index d86c569d85631..1171cc99cbf46 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx @@ -1,7 +1,7 @@ import { useMachine } from "@xstate/react" import { getPaginationContext, - isNonInitialPage, + nonInitialPage, } from "components/PaginationWidget/utils" import { FC } from "react" import { Helmet } from "react-helmet-async" @@ -52,7 +52,7 @@ const WorkspacesPage: FC = () => { }) }} paginationRef={paginationRef} - isNonInitialPage={isNonInitialPage(searchParams)} + isNonInitialPage={nonInitialPage(searchParams)} /> ) From 749ce32311b919e58f9582f86ffb13d33985c3e4 Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Tue, 8 Nov 2022 14:36:02 +0000 Subject: [PATCH 5/9] Lint and format --- .../components/WorkspacesTable/WorkspacesTableBody.tsx | 1 - site/src/pages/UsersPage/UsersPageView.stories.tsx | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx b/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx index 9c858f5694707..d5172901485b4 100644 --- a/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx +++ b/site/src/components/WorkspacesTable/WorkspacesTableBody.tsx @@ -24,7 +24,6 @@ export const WorkspacesTableBody: FC< React.PropsWithChildren > = ({ isLoading, workspaceRefs, filter, isNonInitialPage }) => { const { t } = useTranslation("workspacesPage") - console.log(isNonInitialPage) return ( diff --git a/site/src/pages/UsersPage/UsersPageView.stories.tsx b/site/src/pages/UsersPage/UsersPageView.stories.tsx index b7df8ae27ca6b..babc1c1c3fd80 100644 --- a/site/src/pages/UsersPage/UsersPageView.stories.tsx +++ b/site/src/pages/UsersPage/UsersPageView.stories.tsx @@ -15,17 +15,17 @@ export default { defaultValue: createPaginationRef({ page: 1, limit: 25 }), }, isNonInitialPage: { - defaultValue: false + defaultValue: false, }, users: { - defaultValue: [MockUser, MockUser2] + defaultValue: [MockUser, MockUser2], }, roles: { - defaultValue: MockAssignableSiteRoles + defaultValue: MockAssignableSiteRoles, }, canEditUsers: { - defaultValue: true - } + defaultValue: true, + }, }, } as ComponentMeta From 1e77742f52808eac333f821b5514d9de81ec0b0d Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Tue, 8 Nov 2022 14:54:55 +0000 Subject: [PATCH 6/9] Fix tests --- .../src/components/Conditionals/ChooseOne.tsx | 2 +- .../components/UsersTable/UsersTable.test.tsx | 1 + .../components/UsersTable/UsersTableBody.tsx | 1 + site/src/pages/UsersPage/UsersPage.test.tsx | 21 +++++++------------ .../WorkspacesPage/WorkspacesPage.test.tsx | 9 ++++---- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/site/src/components/Conditionals/ChooseOne.tsx b/site/src/components/Conditionals/ChooseOne.tsx index c61082c3656af..0f9087a94b0a8 100644 --- a/site/src/components/Conditionals/ChooseOne.tsx +++ b/site/src/components/Conditionals/ChooseOne.tsx @@ -40,7 +40,7 @@ export const ChooseOne = ({ } if (conditionedOptions.some((cond) => cond.props.condition === undefined)) { throw new Error( - "A non-final Cond in a ChooseOne does not have a condition prop.", + "A non-final Cond in a ChooseOne does not have a condition prop or the prop is undefined.", ) } const chosen = conditionedOptions.find((child) => child.props.condition) diff --git a/site/src/components/UsersTable/UsersTable.test.tsx b/site/src/components/UsersTable/UsersTable.test.tsx index 876e8f857989e..21ae5d57d5757 100644 --- a/site/src/components/UsersTable/UsersTable.test.tsx +++ b/site/src/components/UsersTable/UsersTable.test.tsx @@ -15,6 +15,7 @@ describe("AuditPage", () => { onActivateUser={() => jest.fn()} onResetUserPassword={() => jest.fn()} onUpdateUserRoles={() => jest.fn()} + isNonInitialPage={false} />, ) diff --git a/site/src/components/UsersTable/UsersTableBody.tsx b/site/src/components/UsersTable/UsersTableBody.tsx index b97dbc05c2e7e..ccb455cf24bab 100644 --- a/site/src/components/UsersTable/UsersTableBody.tsx +++ b/site/src/components/UsersTable/UsersTableBody.tsx @@ -50,6 +50,7 @@ export const UsersTableBody: FC< }) => { const styles = useStyles() const { t } = useTranslation("usersPage") + console.log(isNonInitialPage) return ( diff --git a/site/src/pages/UsersPage/UsersPage.test.tsx b/site/src/pages/UsersPage/UsersPage.test.tsx index 766581ca2dcf2..f7869c3ca85be 100644 --- a/site/src/pages/UsersPage/UsersPage.test.tsx +++ b/site/src/pages/UsersPage/UsersPage.test.tsx @@ -8,7 +8,6 @@ import { Role } from "../../api/typesGenerated" import { Language as ResetPasswordDialogLanguage } from "../../components/Dialogs/ResetPasswordDialog/ResetPasswordDialog" import { GlobalSnackbar } from "../../components/GlobalSnackbar/GlobalSnackbar" import { Language as RoleSelectLanguage } from "../../components/RoleSelect/RoleSelect" -import { Language as UsersTableBodyLanguage } from "../../components/UsersTable/UsersTableBody" import { MockAuditorRole, MockUser, @@ -39,9 +38,8 @@ const suspendUser = async (setupActionSpies: () => void) => { await user.click(firstMoreButton) const menu = await screen.findByRole("menu") - const suspendButton = within(menu).getByText( - UsersTableBodyLanguage.suspendMenuItem, - ) + const text = t("suspendMenuItem", { ns: "usersPage" }) + const suspendButton = within(menu).getByText(text) await user.click(suspendButton) @@ -72,9 +70,8 @@ const deleteUser = async (setupActionSpies: () => void) => { await user.click(selectedMoreButton) const menu = await screen.findByRole("menu") - const deleteButton = within(menu).getByText( - UsersTableBodyLanguage.deleteMenuItem, - ) + const text = t("deleteMenuItem", { ns: "usersPage" }) + const deleteButton = within(menu).getByText(text) await user.click(deleteButton) @@ -107,9 +104,8 @@ const activateUser = async (setupActionSpies: () => void) => { fireEvent.click(suspendedMoreButton) const menu = screen.getByRole("menu") - const activateButton = within(menu).getByText( - UsersTableBodyLanguage.activateMenuItem, - ) + const text = t("activateMenuItem", { ns: "usersPage" }) + const activateButton = within(menu).getByText(text) fireEvent.click(activateButton) // Check if the confirm message is displayed @@ -135,9 +131,8 @@ const resetUserPassword = async (setupActionSpies: () => void) => { fireEvent.click(firstMoreButton) const menu = screen.getByRole("menu") - const resetPasswordButton = within(menu).getByText( - UsersTableBodyLanguage.resetPasswordMenuItem, - ) + const text = t("resetPasswordMenuItem", { ns: "usersPage" }) + const resetPasswordButton = within(menu).getByText(text) fireEvent.click(resetPasswordButton) diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx index 7ba6ef88ee4a4..87d4297864bc5 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx @@ -1,11 +1,13 @@ import { screen, waitFor } from "@testing-library/react" import { rest } from "msw" import * as CreateDayString from "util/createDayString" -import { Language as WorkspacesTableBodyLanguage } from "../../components/WorkspacesTable/WorkspacesTableBody" import { MockWorkspace } from "../../testHelpers/entities" import { history, render } from "../../testHelpers/renderHelpers" import { server } from "../../testHelpers/server" import WorkspacesPage from "./WorkspacesPage" +import { i18n } from "i18n" + +const { t } = i18n describe("WorkspacesPage", () => { beforeEach(() => { @@ -27,9 +29,8 @@ describe("WorkspacesPage", () => { render() // Then - await screen.findByText( - WorkspacesTableBodyLanguage.emptyCreateWorkspaceMessage, - ) + const text = t("emptyCreateWorkspaceMessage", { ns: "workspacesPage" }) + await screen.findByText(text) }) it("renders a filled workspaces page", async () => { From cbc4388c1b062a9f8af293c3f7c81d4128f36eb6 Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Tue, 8 Nov 2022 14:55:24 +0000 Subject: [PATCH 7/9] Remove log --- site/src/components/UsersTable/UsersTableBody.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/components/UsersTable/UsersTableBody.tsx b/site/src/components/UsersTable/UsersTableBody.tsx index ccb455cf24bab..b97dbc05c2e7e 100644 --- a/site/src/components/UsersTable/UsersTableBody.tsx +++ b/site/src/components/UsersTable/UsersTableBody.tsx @@ -50,7 +50,6 @@ export const UsersTableBody: FC< }) => { const styles = useStyles() const { t } = useTranslation("usersPage") - console.log(isNonInitialPage) return ( From da59b061323507a99fdbaedaba2ebea545cad5da Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Tue, 8 Nov 2022 14:59:31 +0000 Subject: [PATCH 8/9] Try to fix story --- site/src/pages/UsersPage/UsersPageView.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/pages/UsersPage/UsersPageView.stories.tsx b/site/src/pages/UsersPage/UsersPageView.stories.tsx index babc1c1c3fd80..982d19aac0b66 100644 --- a/site/src/pages/UsersPage/UsersPageView.stories.tsx +++ b/site/src/pages/UsersPage/UsersPageView.stories.tsx @@ -44,7 +44,7 @@ export const Member = Template.bind({}) Member.args = { canEditUsers: false } export const Empty = Template.bind({}) -Empty.args = { users: [] } +Empty.args = { users: [], isNonInitialPage: false } export const EmptyPage = Template.bind({}) EmptyPage.args = { users: [], isNonInitialPage: true } From 3abc30e8e33dfc85c0f38b0c16e13374dab7f473 Mon Sep 17 00:00:00 2001 From: Presley Pizzo Date: Tue, 8 Nov 2022 15:26:21 +0000 Subject: [PATCH 9/9] Fix the right story --- .../components/UsersTable/UsersTable.stories.tsx | 15 ++++++++++----- .../src/pages/UsersPage/UsersPageView.stories.tsx | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/site/src/components/UsersTable/UsersTable.stories.tsx b/site/src/components/UsersTable/UsersTable.stories.tsx index a9641b2747635..a1f11d8e277c6 100644 --- a/site/src/components/UsersTable/UsersTable.stories.tsx +++ b/site/src/components/UsersTable/UsersTable.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta, Story } from "@storybook/react" import { - MockSiteRoles, + MockAssignableSiteRoles, MockUser, MockUser2, } from "../../testHelpers/renderHelpers" @@ -9,6 +9,11 @@ import { UsersTable, UsersTableProps } from "./UsersTable" export default { title: "components/UsersTable", component: UsersTable, + argTypes: { + isNonInitialPage: { + defaultValue: false, + }, + }, } as ComponentMeta const Template: Story = (args) => @@ -16,27 +21,27 @@ const Template: Story = (args) => export const Example = Template.bind({}) Example.args = { users: [MockUser, MockUser2], - roles: MockSiteRoles, + roles: MockAssignableSiteRoles, canEditUsers: false, } export const Editable = Template.bind({}) Editable.args = { users: [MockUser, MockUser2], - roles: MockSiteRoles, + roles: MockAssignableSiteRoles, canEditUsers: true, } export const Empty = Template.bind({}) Empty.args = { users: [], - roles: MockSiteRoles, + roles: MockAssignableSiteRoles, } export const Loading = Template.bind({}) Loading.args = { users: [], - roles: MockSiteRoles, + roles: MockAssignableSiteRoles, isLoading: true, } Loading.parameters = { diff --git a/site/src/pages/UsersPage/UsersPageView.stories.tsx b/site/src/pages/UsersPage/UsersPageView.stories.tsx index 982d19aac0b66..babc1c1c3fd80 100644 --- a/site/src/pages/UsersPage/UsersPageView.stories.tsx +++ b/site/src/pages/UsersPage/UsersPageView.stories.tsx @@ -44,7 +44,7 @@ export const Member = Template.bind({}) Member.args = { canEditUsers: false } export const Empty = Template.bind({}) -Empty.args = { users: [], isNonInitialPage: false } +Empty.args = { users: [] } export const EmptyPage = Template.bind({}) EmptyPage.args = { users: [], isNonInitialPage: true }