Skip to content

Commit

Permalink
Migrate components from SUIR to MUI.
Browse files Browse the repository at this point in the history
  • Loading branch information
fniessink committed Dec 21, 2024
1 parent eeaa82f commit e5f9932
Show file tree
Hide file tree
Showing 58 changed files with 1,100 additions and 1,049 deletions.
7 changes: 4 additions & 3 deletions components/frontend/src/fields/DateInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ import "./DateInput.css"
import { bool, func, string } from "prop-types"

import { ReadOnlyOrEditable } from "../context/Permissions"
import { Form, Icon, Label } from "../semantic_ui_react_wrappers"
import { Form, Label } from "../semantic_ui_react_wrappers"
import { labelPropType, permissionsPropType } from "../sharedPropTypes"
import { toISODateStringInCurrentTZ } from "../utils"
import { DatePicker } from "../widgets/DatePicker"
import { CalendarIcon } from "../widgets/icons"
import { ReadOnlyInput } from "./ReadOnlyInput"

function EditableDateInput({ ariaLabelledBy, label, placeholder, required, set_value, value }) {
value = value ? new Date(value) : null
return (
<Form.Input error={required && !value} label={label} labelPosition="left" required={required}>
<Label>
<Icon fitted name="calendar" />
<Label style={{ padding: "8px" }}>
<CalendarIcon />
</Label>
<DatePicker
ariaLabelledBy={ariaLabelledBy}
Expand Down
11 changes: 5 additions & 6 deletions components/frontend/src/issue/IssuesRows.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { ErrorMessage } from "../errorMessage"
import { MultipleChoiceInput } from "../fields/MultipleChoiceInput"
import { metricPropType, reportPropType } from "../sharedPropTypes"
import { getMetricIssueIds } from "../utils"
import { ActionButton } from "../widgets/Button"
import { ActionButton } from "../widgets/buttons/ActionButton"
import { AddItemIcon } from "../widgets/icons"
import { LabelWithHelp } from "../widgets/LabelWithHelp"
import { showMessage } from "../widgets/toast"

Expand All @@ -18,8 +19,7 @@ function CreateIssueButton({ issueTrackerConfigured, issueTrackerInstruction, me
<ActionButton
action="Create new"
disabled={!issueTrackerConfigured}
fluid
icon="plus"
icon={<AddItemIcon />}
itemType="issue"
onClick={() => add_metric_issue(metric_uuid, reload)}
popup={
Expand All @@ -28,7 +28,6 @@ function CreateIssueButton({ issueTrackerConfigured, issueTrackerInstruction, me
tracked issue identifiers.{issueTrackerInstruction}
</>
}
position="top center"
/>
)
}
Expand Down Expand Up @@ -127,7 +126,7 @@ export function IssuesRows({ metric, metric_uuid, reload, report, target }) {
}
editableComponent={
<>
<Grid.Column width={3} verticalAlign="bottom">
<Grid.Column width={2} verticalAlign="bottom">
<CreateIssueButton
issueTrackerConfigured={issueTrackerConfigured}
issueTrackerInstruction={issueTrackerInstruction}
Expand All @@ -136,7 +135,7 @@ export function IssuesRows({ metric, metric_uuid, reload, report, target }) {
reload={reload}
/>
</Grid.Column>
<Grid.Column width={13}>
<Grid.Column width={14}>
<IssueIdentifiers {...issueIdentifiersProps} />
</Grid.Column>
</>
Expand Down
10 changes: 6 additions & 4 deletions components/frontend/src/measurement/MeasurementValue.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { bool, string } from "prop-types"
import { useContext } from "react"

import { DataModel } from "../context/DataModel"
import { Icon, Label, Message, Popup } from "../semantic_ui_react_wrappers"
import { Label, Message, Popup } from "../semantic_ui_react_wrappers"
import { datePropType, measurementPropType, metricPropType } from "../sharedPropTypes"
import { IGNORABLE_SOURCE_ENTITY_STATUSES, SOURCE_ENTITY_STATUS_NAME } from "../source/source_entity_status"
import {
Expand All @@ -17,13 +17,14 @@ import {
isMeasurementStale,
sum,
} from "../utils"
import { IgnoreIcon, LoadingIcon } from "../widgets/icons"
import { TimeAgoWithDate } from "../widgets/TimeAgoWithDate"
import { WarningMessage } from "../widgets/WarningMessage"

function measurementValueLabel(hasIgnoredEntities, stale, updating, value) {
const measurementValue = hasIgnoredEntities ? (
<>
<Icon name="hide" /> {value}
<IgnoreIcon /> {value}
</>
) : (
value
Expand All @@ -34,7 +35,8 @@ function measurementValueLabel(hasIgnoredEntities, stale, updating, value) {
if (updating) {
return (
<Label color="yellow">
<Icon loading name="hourglass" /> {measurementValue}
<LoadingIcon />
{measurementValue}
</Label>
)
}
Expand Down Expand Up @@ -124,7 +126,7 @@ export function MeasurementValue({ metric, reportDate }) {
info
header={
<span>
<Icon name="hide" /> {`Ignored ${unit}`}
<IgnoreIcon /> {`Ignored ${unit}`}
</span>
}
content={ignoredEntitiesMessage(metric.latest_measurement, unit)}
Expand Down
5 changes: 3 additions & 2 deletions components/frontend/src/measurement/MeasurementValue.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ it("renders an outdated value", async () => {
})
const measurementValue = screen.getByText(/1/)
expect(measurementValue.className).toContain("yellow")
expect(measurementValue.children[0].className).toContain("loading")
expect(screen.getAllByTestId("LoopIcon").length).toBe(1)
await userEvent.hover(measurementValue)
await waitFor(() => {
expect(screen.queryByText(/Latest measurement out of date/)).not.toBe(null)
Expand All @@ -74,7 +74,7 @@ it("renders a value for which a measurement was requested", async () => {
})
const measurementValue = screen.getByText(/1/)
expect(measurementValue.className).toContain("yellow")
expect(measurementValue.children[0].className).toContain("loading")
expect(screen.getAllByTestId("LoopIcon").length).toBe(1)
await userEvent.hover(measurementValue)
await waitFor(() => {
expect(screen.queryByText(/Measurement requested/)).not.toBe(null)
Expand All @@ -90,6 +90,7 @@ it("renders a value for which a measurement was requested, but which is now up t
})
const measurementValue = screen.getByText(/1/)
expect(measurementValue.className).not.toContain("yellow")
expect(screen.queryAllByTestId("LoopIcon").length).toBe(0)
await userEvent.hover(measurementValue)
await waitFor(() => {
expect(screen.queryByText(/Measurement requested/)).toBe(null)
Expand Down
42 changes: 28 additions & 14 deletions components/frontend/src/metric/MetricDetails.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import MoneyIcon from "@mui/icons-material/Money"
import ShowChartIcon from "@mui/icons-material/ShowChart"
import StorageIcon from "@mui/icons-material/Storage"
import { bool, func, string } from "prop-types"
import { useContext, useEffect, useState } from "react"

Expand All @@ -20,7 +23,12 @@ import { Logo } from "../source/Logo"
import { SourceEntities } from "../source/SourceEntities"
import { Sources } from "../source/Sources"
import { getSourceName, isMeasurementRequested } from "../utils"
import { ActionButton, DeleteButton, PermLinkButton, ReorderButtonGroup } from "../widgets/Button"
import { ButtonRow } from "../widgets/ButtonRow"
import { ActionButton } from "../widgets/buttons/ActionButton"
import { DeleteButton } from "../widgets/buttons/DeleteButton"
import { PermLinkButton } from "../widgets/buttons/PermLinkButton"
import { ReorderButtonGroup } from "../widgets/buttons/ReorderButtonGroup"
import { RefreshIcon } from "../widgets/icons"
import { changelogTabPane, configurationTabPane, tabPane } from "../widgets/TabPane"
import { showMessage } from "../widgets/toast"
import { MetricConfigurationParameters } from "./MetricConfigurationParameters"
Expand All @@ -34,7 +42,7 @@ function RequestMeasurementButton({ metric, metric_uuid, reload }) {
<ActionButton
action="Measure"
disabled={measurementRequested}
icon="refresh"
icon={<RefreshIcon />}
itemType="metric"
loading={measurementRequested}
onClick={() => set_metric_attribute(metric_uuid, "measurement_requested", new Date().toISOString(), reload)}
Expand All @@ -48,12 +56,21 @@ RequestMeasurementButton.propTypes = {
reload: func,
}

function Buttons({ isFirstMetric, isLastMetric, metric, metric_uuid, reload, stopFilteringAndSorting, url }) {
function MetricDetailsButtonRow({
isFirstMetric,
isLastMetric,
metric,
metric_uuid,
reload,
stopFilteringAndSorting,
url,
}) {
const deleteButton = <DeleteButton itemType="metric" onClick={() => delete_metric(metric_uuid, reload)} />
return (
<ReadOnlyOrEditable
requiredPermissions={[EDIT_REPORT_PERMISSION]}
editableComponent={
<div style={{ marginTop: "20px" }}>
<ButtonRow rightButton={deleteButton}>
<ReorderButtonGroup
first={isFirstMetric}
last={isLastMetric}
Expand All @@ -66,13 +83,12 @@ function Buttons({ isFirstMetric, isLastMetric, metric, metric_uuid, reload, sto
/>
<PermLinkButton itemType="metric" url={url} />
<RequestMeasurementButton metric={metric} metric_uuid={metric_uuid} reload={reload} />
<DeleteButton itemType="metric" onClick={() => delete_metric(metric_uuid, reload)} />
</div>
</ButtonRow>
}
/>
)
}
Buttons.propTypes = {
MetricDetailsButtonRow.propTypes = {
isFirstMetric: bool,
isLastMetric: bool,
metric: metricPropType,
Expand Down Expand Up @@ -131,9 +147,7 @@ export function MetricDetails({
let anyWarning = Object.values(metric.sources).some((source) => dataModel.sources[source.type].deprecated)
anyError =
anyError ||
Object.values(metric.sources ?? {}).some(
(source) => !dataModel.metrics[metric.type].sources.includes(source.type),
)
Object.values(metric.sources).some((source) => !dataModel.metrics[metric.type].sources.includes(source.type))
const metricUrl = `${window.location.href.split("#")[0]}#${metric_uuid}`
let panes = []
panes.push(
Expand All @@ -157,18 +171,18 @@ export function MetricDetails({
changed_fields={changed_fields}
reload={reload}
/>,
{ iconName: "server", error: Boolean(anyError), warning: Boolean(anyWarning) },
{ icon: <StorageIcon />, error: Boolean(anyError), warning: Boolean(anyWarning) },
),
tabPane(
"Technical debt",
<MetricDebtParameters metric={metric} metric_uuid={metric_uuid} report={report} reload={reload} />,
{ iconName: "money" },
{ icon: <MoneyIcon /> },
),
changelogTabPane(<ChangeLog timestamp={report.timestamp} metric_uuid={metric_uuid} />),
tabPane(
"Trend graph",
<TrendGraph metric={metric} measurements={measurements} loading={measurementsStatus} />,
{ iconName: "linegraph" },
{ icon: <ShowChartIcon /> },
),
)
Object.entries(metric.sources).forEach(([source_uuid, source]) => {
Expand Down Expand Up @@ -198,7 +212,7 @@ export function MetricDetails({
onTabChange={tabChangeHandler(expandedItems, metric_uuid)}
panes={panes}
/>
<Buttons
<MetricDetailsButtonRow
metric={metric}
metric_uuid={metric_uuid}
isFirstMetric={isFirstMetric}
Expand Down
10 changes: 5 additions & 5 deletions components/frontend/src/metric/MetricDetails.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,20 @@ const report = {
type: "violations",
sources: {
source_uuid: {
type: "source_type",
type: "sonarqube",
entities: [],
},
},
},
metric_uuid2: {},
metric_uuid2: { name: "Metric 2", sources: {} },
},
},
},
}

const dataModel = {
sources: {
source_type: {
sonarqube: {
name: "The source",
deprecated: true,
parameters: {},
Expand All @@ -54,7 +54,7 @@ const dataModel = {
entities: { violations: { name: "Attribute", attributes: [] } },
},
},
metrics: { violations: { direction: "<", tags: [], sources: ["source_type"] } },
metrics: { violations: { direction: "<", tags: [], sources: ["sonarqube"] } },
subjects: { subject_type: { metrics: ["violations"] } },
}

Expand Down Expand Up @@ -175,7 +175,7 @@ it("displays whether sources have warnings", async () => {
it("moves the metric", async () => {
const mockCallback = jest.fn()
await renderMetricDetails(mockCallback)
await act(async () => fireEvent.click(screen.getByLabelText(/Move metric to the last row/)))
await act(async () => fireEvent.click(screen.getByRole("button", { name: /Move metric to the last row/ })))
expect(mockCallback).toHaveBeenCalled()
expect(measurement_api.get_metric_measurements).toHaveBeenCalled()
})
Expand Down
9 changes: 7 additions & 2 deletions components/frontend/src/metric/MetricType.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import { Stack, Typography } from "@mui/material"
import { func, string } from "prop-types"
import { useContext } from "react"

import { set_metric_attribute } from "../api/metric"
import { DataModel } from "../context/DataModel"
import { EDIT_REPORT_PERMISSION } from "../context/Permissions"
import { SingleChoiceInput } from "../fields/SingleChoiceInput"
import { Header } from "../semantic_ui_react_wrappers"
import { getSubjectTypeMetrics } from "../utils"

export function metricTypeOption(key, metricType) {
return {
key: key,
text: metricType.name,
value: key,
content: <Header as="h4" content={metricType.name} subheader={metricType.description} />,
content: (
<Stack direction="column">
{metricType.name}
<Typography variant="body2">{metricType.description}</Typography>
</Stack>
),
}
}

Expand Down
9 changes: 2 additions & 7 deletions components/frontend/src/metric/MetricTypeHeader.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Icon } from "semantic-ui-react"

import { Header } from "../semantic_ui_react_wrappers"
import { metricTypePropType } from "../sharedPropTypes"
import { slugify } from "../utils"
import { HyperLink } from "../widgets/HyperLink"
import { ReadTheDocsLink } from "../widgets/ReadTheDocsLink"

export function MetricTypeHeader({ metricType }) {
const url = `https://quality-time.readthedocs.io/en/v${process.env.REACT_APP_VERSION}/reference.html${slugify(metricType.name)}`
Expand All @@ -15,10 +13,7 @@ export function MetricTypeHeader({ metricType }) {
<Header.Content>
{metricType.name}
<Header.Subheader>
{metricType.description}{" "}
<HyperLink url={url}>
Read the Docs <Icon name="external" link />
</HyperLink>
{metricType.description} <ReadTheDocsLink url={url} />
{howToConfigure}
</Header.Subheader>
</Header.Content>
Expand Down
Loading

0 comments on commit e5f9932

Please sign in to comment.