Skip to content

Commit

Permalink
Migrate changelog component to MUI. Partially realizes #9796.
Browse files Browse the repository at this point in the history
  • Loading branch information
fniessink committed Nov 15, 2024
1 parent e96a6f6 commit 23ea63e
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 61 deletions.
7 changes: 0 additions & 7 deletions components/frontend/src/changelog/ChangeLog.css

This file was deleted.

61 changes: 24 additions & 37 deletions components/frontend/src/changelog/ChangeLog.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
import "./ChangeLog.css"

import UpdateIcon from "@mui/icons-material/Update"
import { Button, List, ListItem, ListItemAvatar, ListItemText, Typography } from "@mui/material"
import { string } from "prop-types"
import React, { useEffect, useState } from "react"
import { Icon } from "semantic-ui-react"

import { get_changelog } from "../api/changelog"
import { Button, Feed, Form, Header, Segment } from "../semantic_ui_react_wrappers"
import { Avatar } from "../widgets/Avatar"
import { TimeAgoWithDate } from "../widgets/TimeAgoWithDate"
import { showMessage } from "../widgets/toast"

function Event({ description, email, timestamp }) {
return (
<Feed.Event>
<Feed.Label>
<ListItem sx={{ padding: "0px" }}>
<ListItemAvatar>
<Avatar email={email} />
</Feed.Label>
<Feed.Content>
<Feed.Summary>
{description}
<Feed.Date>
<TimeAgoWithDate date={timestamp} />
</Feed.Date>
</Feed.Summary>
</Feed.Content>
</Feed.Event>
</ListItemAvatar>
<ListItemText primary={description} secondary={<TimeAgoWithDate date={timestamp} />} />
</ListItem>
)
}
Event.propTypes = {
Expand Down Expand Up @@ -79,27 +70,23 @@ function ChangeLogWithoutMemo({ report_uuid, subject_uuid, metric_uuid, source_u
}

return (
<Form>
<Header size="small">
{scope}
<Header.Subheader>Most recent first</Header.Subheader>
</Header>
<Segment>
<Feed size="small">
{changes.map((change) => (
<Event
key={change.timestamp + change.delta}
description={change.delta}
email={change.email}
timestamp={change.timestamp}
/>
))}
</Feed>
<Button basic icon primary size="small" onClick={() => setNrChanges(nrChanges + 10)}>
<Icon name="refresh" /> Load more changes
</Button>
</Segment>
</Form>
<>
<Typography variant="subtitle1">{scope}</Typography>
<Typography variant="subtitle2">Most recent first</Typography>
<List dense>
{changes.map((change) => (
<Event
key={change.timestamp + change.delta}
description={change.delta}
email={change.email}
timestamp={change.timestamp}
/>
))}
</List>
<Button variant="outlined" onClick={() => setNrChanges(nrChanges + 10)} startIcon={<UpdateIcon />}>
Load more changes
</Button>
</>
)
}
ChangeLogWithoutMemo.propTypes = {
Expand Down
65 changes: 48 additions & 17 deletions components/frontend/src/changelog/ChangeLog.test.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,83 @@
import { act, render } from "@testing-library/react"
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react"

import * as changelog_api from "../api/changelog"
import * as toast from "../widgets/toast"
import { ChangeLog } from "./ChangeLog"

jest.mock("../api/changelog.js")
let result
jest.mock("../widgets/toast.js")

beforeEach(() => {
jest.resetAllMocks()
})

function expectNrEventsToBe(nr) {
// Assert that the change log contains nr events
const rows = document.querySelectorAll(".MuiListItem-root")
expect(rows.length).toBe(nr)
}

it("renders no changes", async () => {
changelog_api.get_changelog.mockImplementation(() => Promise.resolve({ changelog: [] }))
await act(async () => {
result = render(<ChangeLog />)
render(<ChangeLog />)
})
const rows = result.container.querySelectorAll("div.event")
expect(rows.length).toBe(0)
expectNrEventsToBe(0)
})

it("renders one report change", async () => {
changelog_api.get_changelog.mockImplementation(() => Promise.resolve({ changelog: [{ timestamp: "2020-01-01" }] }))
await act(async () => {
result = render(<ChangeLog report_uuid="uuid" />)
render(<ChangeLog report_uuid="uuid" />)
})
const rows = result.container.querySelectorAll("div.event")
expect(rows.length).toBe(1)
expectNrEventsToBe(1)
})

it("renders one subject change", async () => {
changelog_api.get_changelog.mockImplementation(() => Promise.resolve({ changelog: [{ timestamp: "2020-01-01" }] }))
await act(async () => {
result = render(<ChangeLog subject_uuid="uuid" />)
render(<ChangeLog subject_uuid="uuid" />)
})
const rows = result.container.querySelectorAll("div.event")
expect(rows.length).toBe(1)
expectNrEventsToBe(1)
})

it("renders one metric change", async () => {
changelog_api.get_changelog.mockImplementation(() => Promise.resolve({ changelog: [{ timestamp: "2020-01-01" }] }))
await act(async () => {
result = render(<ChangeLog metric_uuid="uuid" />)
render(<ChangeLog metric_uuid="uuid" />)
})
const rows = result.container.querySelectorAll("div.event")
expect(rows.length).toBe(1)
expectNrEventsToBe(1)
})

it("renders one source change", async () => {
changelog_api.get_changelog.mockImplementation(() => Promise.resolve({ changelog: [{ timestamp: "2020-01-01" }] }))
await act(async () => {
result = render(<ChangeLog source_uuid="uuid" />)
render(<ChangeLog source_uuid="uuid" />)
})
expectNrEventsToBe(1)
})

it("loads more changes", async () => {
changelog_api.get_changelog.mockImplementation(() => Promise.resolve({ changelog: [{ timestamp: "2020-01-01" }] }))
await act(async () => {
render(<ChangeLog source_uuid="uuid" />)
})
changelog_api.get_changelog.mockImplementation(() =>
Promise.resolve({ changelog: [{ timestamp: "2020-01-01" }, { timestamp: "2020-01-02" }] }),
)
await act(async () => fireEvent.click(screen.getByText(/Load more changes/)))
expectNrEventsToBe(2)
})

it("shows error when loading more changes fails", async () => {
changelog_api.get_changelog.mockImplementation(() => Promise.resolve({ changelog: [] }))
await act(async () => {
render(<ChangeLog source_uuid="uuid" />)
})
changelog_api.get_changelog.mockImplementation(() => Promise.reject(new Error("Couldn't retrieve changelog")))
await act(async () => fireEvent.click(screen.getByText(/Load more changes/)))
await waitFor(() => {
expect(toast.showMessage).toHaveBeenCalledTimes(1)
})
const rows = result.container.querySelectorAll("div.event")
expect(rows.length).toBe(1)
expectNrEventsToBe(0)
})

0 comments on commit 23ea63e

Please sign in to comment.