Skip to content

chore: Add Audit Log components and service to load from the API #3782

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

Merged
merged 31 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b8fa378
Add basic auditXService code
BrunoQuaresma Aug 30, 2022
38955a8
Add base audit log component
BrunoQuaresma Aug 30, 2022
785f67b
Add basic diff
BrunoQuaresma Aug 31, 2022
7479538
Check emtpy diffs
BrunoQuaresma Aug 31, 2022
b30165a
Improve human readable message
BrunoQuaresma Aug 31, 2022
f9a7ed7
Move types
BrunoQuaresma Aug 31, 2022
9db3385
Extract components and add storybook
BrunoQuaresma Aug 31, 2022
294dceb
Fix status pill
BrunoQuaresma Aug 31, 2022
1b0ed59
Add tests to check if the audit logs are showing
BrunoQuaresma Aug 31, 2022
6cf89a4
Address PR review
BrunoQuaresma Aug 31, 2022
a5da88b
Add i18n
BrunoQuaresma Aug 31, 2022
0267d4e
Merge branch 'main' of github.com:coder/coder into bq/feat-3251
BrunoQuaresma Aug 31, 2022
a0ce84e
Fix audit log row to match the new API types
BrunoQuaresma Aug 31, 2022
b7ccb0f
Fix types and minor issues on mobile
BrunoQuaresma Aug 31, 2022
03eadb6
Handle errors
BrunoQuaresma Sep 1, 2022
77fa647
Add pagination
BrunoQuaresma Sep 1, 2022
dc1543c
Fix table alignment
BrunoQuaresma Sep 1, 2022
901c5f2
Add handler for /count
BrunoQuaresma Sep 1, 2022
ebe2792
Update site/src/xServices/audit/auditXService.ts
BrunoQuaresma Sep 1, 2022
75f19b5
Merge branch 'main' of github.com:coder/coder into bq/feat-3251
BrunoQuaresma Sep 7, 2022
cfe9d7d
Fix types
BrunoQuaresma Sep 7, 2022
f1ba4ac
Fix empty state
BrunoQuaresma Sep 7, 2022
8f1bce7
Display user agent info
BrunoQuaresma Sep 7, 2022
b2fd91b
Merge branch 'bq/feat-3251' of github.com:coder/coder into bq/feat-3251
BrunoQuaresma Sep 7, 2022
b72c3a9
Fix audit log pagination
BrunoQuaresma Sep 7, 2022
0e052ae
Remove console log
BrunoQuaresma Sep 7, 2022
acaa45a
Fix handlers and format
BrunoQuaresma Sep 7, 2022
168cb16
Remove one test
BrunoQuaresma Sep 7, 2022
c48a72e
Update user agent on mocks
BrunoQuaresma Sep 7, 2022
c398be2
Fix switch color on workspace schedule form
BrunoQuaresma Sep 7, 2022
6d09dfa
Fix button
BrunoQuaresma Sep 7, 2022
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
Prev Previous commit
Next Next commit
Add pagination
  • Loading branch information
BrunoQuaresma committed Sep 1, 2022
commit 77fa647a1a70e55659d46a5151a53d8c9867ed87
24 changes: 10 additions & 14 deletions site/src/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { RequirePermission } from "components/RequirePermission/RequirePermissio
import { SetupPage } from "pages/SetupPage/SetupPage"
import { TemplateSettingsPage } from "pages/TemplateSettingsPage/TemplateSettingsPage"
import { FC, lazy, Suspense, useContext } from "react"
import { Navigate, Route, Routes } from "react-router-dom"
import { Route, Routes } from "react-router-dom"
import { selectPermissions } from "xServices/auth/authSelectors"
import { selectFeatureVisibility } from "xServices/entitlements/entitlementsSelectors"
import { XServiceContext } from "xServices/StateContext"
Expand Down Expand Up @@ -139,19 +139,15 @@ export const AppRouter: FC = () => {
<Route
index
element={
process.env.NODE_ENV === "production" ? (
<Navigate to="/workspaces" />
) : (
<AuthAndFrame>
<RequirePermission
isFeatureVisible={
featureVisibility[FeatureNames.AuditLog] && !!permissions?.viewAuditLog
}
>
<AuditPage />
</RequirePermission>
</AuthAndFrame>
)
<AuthAndFrame>
<RequirePermission
isFeatureVisible={
featureVisibility[FeatureNames.AuditLog] && !!permissions?.viewAuditLog
}
>
<AuditPage />
</RequirePermission>
</AuthAndFrame>
}
></Route>
</Route>
Expand Down
14 changes: 12 additions & 2 deletions site/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,17 @@ export const getEntitlements = async (): Promise<TypesGen.Entitlements> => {
return response.data
}

export const getAuditLogs = async (): Promise<TypesGen.AuditLog[]> => {
const response = await axios.get("/api/v2/audit")
interface GetAuditLogsOptions {
limit: number
offset: number
}

export const getAuditLogs = async (options: GetAuditLogsOptions): Promise<TypesGen.AuditLog[]> => {
const response = await axios.get(`/api/v2/audit?limit=${options}&offset=${options.offset}`)
return response.data
}

export const getAuditLogsCount = async (): Promise<number> => {
const response = await axios.get(`/api/v2/audit/count`)
return response.data
}
27 changes: 24 additions & 3 deletions site/src/pages/AuditPage/AuditPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,31 @@ import { auditMachine } from "xServices/audit/auditXService"
import { AuditPageView } from "./AuditPageView"

const AuditPage: FC = () => {
const [auditState] = useMachine(auditMachine)
const { auditLogs } = auditState.context
const [auditState, auditSend] = useMachine(auditMachine, {
context: {
page: 1,
limit: 25,
},
})
const { auditLogs, count, page, limit } = auditState.context

return <AuditPageView auditLogs={auditLogs} />
return (
<AuditPageView
auditLogs={auditLogs}
count={count}
page={page}
limit={limit}
onNext={() => {
auditSend("NEXT")
}}
onPrevious={() => {
auditSend("PREVIOUS")
}}
onGoToPage={(page) => {
auditSend("GO_TO_PAGE", { page })
}}
/>
)
}

export default AuditPage
13 changes: 11 additions & 2 deletions site/src/pages/AuditPage/AuditPageView.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import { ComponentMeta, Story } from "@storybook/react"
import { MockAuditLog, MockAuditLog2 } from "testHelpers/entities"
import { AuditPageView } from "./AuditPageView"
import { AuditPageView, AuditPageViewProps } from "./AuditPageView"

export default {
title: "pages/AuditPageView",
component: AuditPageView,
} as ComponentMeta<typeof AuditPageView>

const Template: Story = (args) => <AuditPageView {...args} />
const Template: Story<AuditPageViewProps> = (args) => <AuditPageView {...args} />

export const AuditPage = Template.bind({})
AuditPage.args = {
auditLogs: [MockAuditLog, MockAuditLog2],
count: 1000,
page: 1,
limit: 25,
}

export const AuditPageSmallViewport = Template.bind({})
AuditPageSmallViewport.args = {
auditLogs: [MockAuditLog, MockAuditLog2],
count: 1000,
page: 1,
limit: 25,
}
AuditPageSmallViewport.parameters = {
chromatic: { viewports: [600] },
}
38 changes: 36 additions & 2 deletions site/src/pages/AuditPage/AuditPageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AuditLogRow } from "components/AuditLogRow/AuditLogRow"
import { CodeExample } from "components/CodeExample/CodeExample"
import { Margins } from "components/Margins/Margins"
import { PageHeader, PageHeaderSubtitle, PageHeaderTitle } from "components/PageHeader/PageHeader"
import { PaginationWidget } from "components/PaginationWidget/PaginationWidget"
import { Stack } from "components/Stack/Stack"
import { TableLoader } from "components/TableLoader/TableLoader"
import { AuditHelpTooltip } from "components/Tooltips"
Expand All @@ -20,7 +21,27 @@ export const Language = {
tooltipTitle: "Copy to clipboard and try the Coder CLI",
}

export const AuditPageView: FC<{ auditLogs?: AuditLog[] }> = ({ auditLogs }) => {
export interface AuditPageViewProps {
auditLogs?: AuditLog[]
count?: number
page: number
limit: number
onNext: () => void
onPrevious: () => void
onGoToPage: (page: number) => void
}

export const AuditPageView: FC<AuditPageViewProps> = ({
auditLogs,
count,
page,
limit,
onNext,
onPrevious,
onGoToPage,
}) => {
const isReady = auditLogs && count

return (
<Margins>
<PageHeader
Expand All @@ -45,14 +66,27 @@ export const AuditPageView: FC<{ auditLogs?: AuditLog[] }> = ({ auditLogs }) =>
</TableRow>
</TableHead>
<TableBody>
{auditLogs ? (
{isReady ? (
auditLogs.map((auditLog) => <AuditLogRow auditLog={auditLog} key={auditLog.id} />)
) : (
<TableLoader />
)}
</TableBody>
</Table>
</TableContainer>

{isReady && count > limit && (
<PaginationWidget
prevLabel=""
nextLabel=""
onPrevClick={onPrevious}
onNextClick={onNext}
onPageClick={onGoToPage}
numRecords={count}
activePage={page}
numRecordsPerPage={limit}
/>
)}
</Margins>
)
}
11 changes: 7 additions & 4 deletions site/src/testHelpers/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -704,14 +704,14 @@ export const MockAuditLog: TypesGen.AuditLog = {
user_agent: "browser",
resource_type: "workspace",
resource_id: "ef8d1cf4-82de-4fd9-8980-047dad6d06b5",
resource_target: "Bruno's Org",
resource_target: "bruno-dev",
resource_icon: "",
action: "create",
diff: {},
status_code: 200,
additional_fields: {},
description: "Colin Adler updated the organization Bruno's Org",
additional_fields: "",
description: "Colin Adler updated the workspace bruno-dev",
user: MockUser,
resource: MockWorkspace,
}

export const MockAuditLog2: TypesGen.AuditLog = {
Expand All @@ -722,14 +722,17 @@ export const MockAuditLog2: TypesGen.AuditLog = {
workspace_name: {
old: "old-workspace-name",
new: MockWorkspace.name,
secret: false,
},
workspace_auto_off: {
old: true,
new: false,
secret: false,
},
template_version_id: {
old: "fbd2116a-8961-4954-87ae-e4575bd29ce0",
new: "53bded77-7b9d-4e82-8771-991a34d759f9",
secret: false,
},
},
}
6 changes: 6 additions & 0 deletions site/src/theme/overrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,16 @@ export const getOverrides = ({ palette, breakpoints }: Theme): Overrides => {
boxShadow: "none",
color: palette.text.primary,
backgroundColor: colors.gray[17],

"&:hover": {
boxShadow: "none",
backgroundColor: "#000000",
},

"&.Mui-disabled": {
backgroundColor: palette.background.paper,
color: palette.secondary.main,
},
},
sizeSmall: {
padding: `0 12px`,
Expand Down
2 changes: 1 addition & 1 deletion site/src/theme/palettes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const darkPalette: PaletteOptions = {
dark: colors.blue[9],
},
secondary: {
main: colors.green[11],
main: colors.gray[11],
contrastText: colors.gray[3],
dark: colors.indigo[7],
},
Expand Down
91 changes: 76 additions & 15 deletions site/src/xServices/audit/auditXService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getAuditLogs } from "api/api"
import { getAuditLogs, getAuditLogsCount } from "api/api"
import { getErrorMessage } from "api/errors"
import { displayError } from "components/GlobalSnackbar/utils"
import { assign, createMachine } from "xstate"
Expand All @@ -9,31 +9,70 @@ export const auditMachine = createMachine(
{
id: "auditMachine",
schema: {
context: {} as { auditLogs?: AuditLogs },
context: {} as { auditLogs?: AuditLogs; count?: number; page: number; limit: number },
services: {} as {
loadAuditLogs: {
data: AuditLogs
}
loadAuditLogsCount: {
data: number
}
},
events: {} as
| {
type: "NEXT"
}
| {
type: "PREVIOUS"
}
| {
type: "GO_TO_PAGE"
page: number
},
},
tsTypes: {} as import("./auditXService.typegen").Typegen0,
initial: "loadingLogs",
initial: "loading",
states: {
loadingLogs: {
invoke: {
src: "loadAuditLogs",
onDone: {
target: "success",
actions: ["assignAuditLogs"],
loading: {
invoke: [
{
src: "loadAuditLogs",
onDone: {
actions: ["assignAuditLogs"],
},
onError: {
target: "error",
actions: ["displayLoadAuditLogsError"],
},
},
onError: {
target: "error",
actions: ["displayLoadAuditLogsError"],
{
src: "loadAuditLogsCount",
onDone: {
actions: ["assignCount"],
},
onError: {
target: "error",
actions: ["displayLoadAuditLogsCountError"],
},
},
},
],
onDone: "success",
},
success: {
type: "final",
on: {
NEXT: {
actions: ["assignNextPage"],
target: "loading",
},
PREVIOUS: {
actions: ["assignPreviousPage"],
target: "loading",
},
GO_TO_PAGE: {
actions: ["assignPage"],
target: "loading",
},
},
},
error: {
type: "final",
Expand All @@ -45,13 +84,35 @@ export const auditMachine = createMachine(
assignAuditLogs: assign({
auditLogs: (_, event) => event.data,
}),
assignCount: assign({
count: (_, event) => event.data,
}),
assignNextPage: assign({
page: ({ page }) => page + 1,
}),
assignPreviousPage: assign({
page: ({ page }) => page - 1,
}),
assignPage: assign({
page: ({ page }) => page,
}),
displayLoadAuditLogsError: (_, event) => {
const message = getErrorMessage(event.data, "Error on loading audit logs.")
displayError(message)
},
displayLoadAuditLogsCountError: (_, event) => {
const message = getErrorMessage(event.data, "Error on loading audit logs count.")
displayError(message)
},
},
services: {
loadAuditLogs: () => getAuditLogs(),
loadAuditLogs: ({ page, limit }, _) =>
getAuditLogs({
// The page in the API starts at 0
offset: (page - 1) * limit,
limit,
}),
loadAuditLogsCount: () => getAuditLogsCount(),
},
},
)