-
+
}
content={entityAttribute.help}
diff --git a/components/frontend/src/source/SourceEntities.test.js b/components/frontend/src/source/SourceEntities.test.js
index b4e341170a..31ad813d00 100644
--- a/components/frontend/src/source/SourceEntities.test.js
+++ b/components/frontend/src/source/SourceEntities.test.js
@@ -281,7 +281,7 @@ it("sorts the entities by minutes", async () => {
it("shows help", async () => {
renderSourceEntities()
- await userEvent.hover(screen.queryByRole("tooltip", { name: /help/ }))
+ await userEvent.hover(screen.queryByTestId("HelpIcon"))
await waitFor(() => {
expect(screen.queryByText(/help text/)).not.toBe(null)
})
diff --git a/components/frontend/src/source/SourceParameter.test.js b/components/frontend/src/source/SourceParameter.test.js
index e1a395dc8e..0ea0323b5f 100644
--- a/components/frontend/src/source/SourceParameter.test.js
+++ b/components/frontend/src/source/SourceParameter.test.js
@@ -152,7 +152,7 @@ it("renders a help url", () => {
it("renders a help text", async () => {
renderSourceParameter({ help: "Help text" })
- await userEvent.hover(screen.queryByTestId("help-icon"))
+ await userEvent.hover(screen.queryByTestId("HelpIcon"))
await waitFor(() => {
expect(screen.queryAllByText(/Help text/).length).toBe(1)
})
diff --git a/components/frontend/src/source/SourceTypeHeader.js b/components/frontend/src/source/SourceTypeHeader.js
index cf05d2071a..a874a54087 100644
--- a/components/frontend/src/source/SourceTypeHeader.js
+++ b/components/frontend/src/source/SourceTypeHeader.js
@@ -1,9 +1,9 @@
import { string } from "prop-types"
-import { Header, Icon, Label } from "../semantic_ui_react_wrappers"
+import { Header, Label } from "../semantic_ui_react_wrappers"
import { sourceTypePropType } from "../sharedPropTypes"
import { slugify } from "../utils"
-import { HyperLink } from "../widgets/HyperLink"
+import { ReadTheDocsLink } from "../widgets/ReadTheDocsLink"
import { Logo } from "./Logo"
import { sourceTypeDescription } from "./SourceType"
@@ -21,9 +21,7 @@ export function SourceTypeHeader({ metricTypeId, sourceTypeId, sourceType }) {
{sourceType.deprecated && }
{`${sourceTypeDescription(sourceType)} `}
-
- Read the Docs
-
+
{howToConfigure}
diff --git a/components/frontend/src/source/Sources.js b/components/frontend/src/source/Sources.js
index b88612d110..0820ac2c3b 100644
--- a/components/frontend/src/source/Sources.js
+++ b/components/frontend/src/source/Sources.js
@@ -14,7 +14,9 @@ import {
stringsPropType,
} from "../sharedPropTypes"
import { pluralize } from "../utils"
-import { AddDropdownButton, CopyButton, MoveButton } from "../widgets/Button"
+import { AddDropdownButton } from "../widgets/buttons/AddDropdownButton"
+import { CopyButton } from "../widgets/buttons/CopyButton"
+import { MoveButton } from "../widgets/buttons/MoveButton"
import { source_options } from "../widgets/menu_options"
import { showMessage } from "../widgets/toast"
import { Source } from "./Source"
diff --git a/components/frontend/src/subject/SubjectTable.test.js b/components/frontend/src/subject/SubjectTable.test.js
index 80c9cd6646..37e9a3f30b 100644
--- a/components/frontend/src/subject/SubjectTable.test.js
+++ b/components/frontend/src/subject/SubjectTable.test.js
@@ -227,7 +227,7 @@ it("expands the details via the url", async () => {
it("moves a metric", async () => {
history.push("?expanded=1:2")
renderSubjectTable()
- await act(async () => fireEvent.click(screen.getByLabelText("Move metric to the next row")))
+ await act(async () => fireEvent.click(screen.getByRole("button", { name: "Move metric to the next row" })))
expect(fetch_server_api.fetch_server_api).toHaveBeenCalledWith("post", "metric/1/attribute/position", {
position: "next",
})
diff --git a/components/frontend/src/subject/SubjectTableFooter.js b/components/frontend/src/subject/SubjectTableFooter.js
index f62c96356a..14c9f1fdf4 100644
--- a/components/frontend/src/subject/SubjectTableFooter.js
+++ b/components/frontend/src/subject/SubjectTableFooter.js
@@ -7,7 +7,9 @@ import { DataModel } from "../context/DataModel"
import { EDIT_REPORT_PERMISSION, ReadOnlyOrEditable } from "../context/Permissions"
import { allMetricTypeOptions, metricTypeOptions, usedMetricTypes } from "../metric/MetricType"
import { reportsPropType, subjectPropType } from "../sharedPropTypes"
-import { AddDropdownButton, CopyButton, MoveButton } from "../widgets/Button"
+import { AddDropdownButton } from "../widgets/buttons/AddDropdownButton"
+import { CopyButton } from "../widgets/buttons/CopyButton"
+import { MoveButton } from "../widgets/buttons/MoveButton"
import { metric_options } from "../widgets/menu_options"
function SubjectTableFooterButtonRow({ subject, subjectUuid, reload, reports, stopFilteringAndSorting }) {
diff --git a/components/frontend/src/subject/SubjectTableHeader.js b/components/frontend/src/subject/SubjectTableHeader.js
index 9018a8aa26..a55251f835 100644
--- a/components/frontend/src/subject/SubjectTableHeader.js
+++ b/components/frontend/src/subject/SubjectTableHeader.js
@@ -1,20 +1,33 @@
-import { bool, func } from "prop-types"
+import { bool, func, string } from "prop-types"
import { useContext } from "react"
import { List, Table } from "semantic-ui-react"
import { DarkMode } from "../context/DarkMode"
import { StatusIcon } from "../measurement/StatusIcon"
import { STATUS_DESCRIPTION, STATUSES } from "../metric/status"
-import { Icon, Label } from "../semantic_ui_react_wrappers"
+import { Label } from "../semantic_ui_react_wrappers"
import { datesPropType, settingsPropType } from "../sharedPropTypes"
import { HyperLink } from "../widgets/HyperLink"
+import { IgnoreIcon, TriangleRightIcon } from "../widgets/icons"
import { SortableTableHeaderCell, UnsortableTableHeaderCell } from "../widgets/TableHeaderCell"
+function Expand({ children }) {
+ return (
+ <>
+ Expand the {children} (click
+ )
+ >
+ )
+}
+Expand.propTypes = {
+ children: string,
+}
+
const metricHelp = (
<>
The name of the metric.
- Expand the metric (click ) to edit its name in the configuration tab.
+ metric to edit its name in the configuration tab.
Click the column header to sort the metrics by name.
>
@@ -31,8 +44,7 @@ const trendHelp = (
number scale.
- Expand the metric (click ) and navigate to the trend graph tab to see a
- graph of all measurements.
+ metric and navigate to the trend graph tab to see a graph of all measurements.
>
)
@@ -65,8 +77,8 @@ const measurementHelp = (
The latest measurement value. Metrics are measured periodically.
If the measurement value is ?, no sources have been configured for the metric yet or the measurement data
- could not be collected. Expand the metric (click ) and navigate to the
- sources tab to add sources or see the error details.
+ could not be collected. metric and navigate to the sources tab to add sources or see the
+ error details.
If the measurement value has a{" "}
@@ -77,10 +89,9 @@ const measurementHelp = (
a system administrator should be notified.
- If there is a before the measurement value, it means one or more measurement entities
- are being ignored. Hover over the measurement value to see how many entities are ignored. Expand the metric
- (click ) and navigate to the entities tab to see why individual
- entities are ignored.
+ If there is a before the measurement value, it means one or more measurement entities are
+ being ignored. Hover over the measurement value to see how many entities are ignored.{" "}
+ metric and navigate to the entities tab to see why individual entities are ignored.
Hover over the measurement value to see when the metric was last measured.
Click the column header to sort the metrics by measurement value.
@@ -99,8 +110,7 @@ const targetHelp = (
past or all issues linked to the metric have been resolved.
- Expand the metric (click ) to edit the target value in the
- configuration tab.
+ metric to edit the target value in the configuration tab.
Click the column header to sort the metrics by target value.
>
@@ -113,8 +123,7 @@ const unitHelp = (
and target values.
- Expand the metric (click ) to edit the unit name in the configuration
- tab.
+ metric to edit the unit name in the configuration tab.
Click the column header to sort the metrics by unit.
>
@@ -124,13 +133,12 @@ const timeLeftHelp = (
<>
The number of days left to address the metric.
- If the metric needs action, the time left is based on the desired reaction times. Expand the report title
- (click ) to change the desired reaction times.
+ If the metric needs action, the time left is based on the desired reaction times.{" "}
+ report title to change the desired reaction times.
- If the metric has accepted technical debt, the time left is based on the technical debt end date. Expand the
- metric (click ) to edit technical debt end date in the technical debt
- tab.
+ If the metric has accepted technical debt, the time left is based on the technical debt end date.{" "}
+ metric to edit technical debt end date in the technical debt tab.
Hover over the number of days to see the exact deadline.
Click the column header to sort the metrics by time left.
@@ -141,7 +149,7 @@ const overrunHelp = (
<>
The number of days that the desired reaction time was exceeded, in the displayed period.
- Expand the report title (click ) to change the desired reaction times.
+ report title to change the desired reaction times.
Hover over the number of days to see an overview of when and for which statuses the metric had overruns, in
@@ -158,7 +166,7 @@ const commentHelp = (
and URLs are supported.
- Expand the metric (click ) to edit the comments.
+ metric to edit the comments.
>
)
@@ -171,11 +179,11 @@ const sourcesHelp = (
- , the source could not be accessed or the data could not be parsed. Expand the metric (click{" "}
- ) and navigate to the source to see the error details.
+ , the source could not be accessed or the data could not be parsed. metric and navigate to
+ the source to see the error details.
- Expand the metric (click ) to configure sources.
+ metric to configure sources.
Click a source to open the tool or report in a new tab.
Click the column header to sort the metrics by source.
@@ -193,8 +201,8 @@ const issuesHelp = (
- , the issue tracker could not be accessed or the data could not be parsed. Expand the metric and navigate to
- the technical debt tab to see the error details.
+ , the issue tracker could not be accessed or the data could not be parsed. metric and
+ navigate to the technical debt tab to see the error details.
Hover over an issue to see more information about the issue.
Click an issue to open the issue in a new tab.
@@ -212,7 +220,7 @@ const tagsHelp = (
selected tags.
- Expand the metric (click ) to add or remove tags.
+ metric to add or remove tags.
Click the column header to sort the metrics by tag.
>
diff --git a/components/frontend/src/subject/SubjectTableHeader.test.js b/components/frontend/src/subject/SubjectTableHeader.test.js
index 21a3ac1e00..a6b6f3eceb 100644
--- a/components/frontend/src/subject/SubjectTableHeader.test.js
+++ b/components/frontend/src/subject/SubjectTableHeader.test.js
@@ -1,4 +1,5 @@
-import { render, screen } from "@testing-library/react"
+import { render, screen, waitFor } from "@testing-library/react"
+import userEvent from "@testing-library/user-event"
import history from "history/browser"
import { Table } from "semantic-ui-react"
@@ -73,3 +74,12 @@ it("hides the delta columns", () => {
renderSubjectTableHeader([date1, date2])
expect(screen.queryAllByText("𝚫").length).toBe(0)
})
+
+it("shows help for column headers", async () => {
+ const date1 = new Date("2022-02-02")
+ renderSubjectTableHeader([date1])
+ await userEvent.hover(screen.getByText("Metric"))
+ await waitFor(() => {
+ expect(screen.queryByText(/Click the column header to sort the metrics by name/)).not.toBe(null)
+ })
+})
diff --git a/components/frontend/src/subject/SubjectTitle.js b/components/frontend/src/subject/SubjectTitle.js
index 67a0c14943..a5370644cc 100644
--- a/components/frontend/src/subject/SubjectTitle.js
+++ b/components/frontend/src/subject/SubjectTitle.js
@@ -1,6 +1,5 @@
import { bool, func, object, string } from "prop-types"
import { useContext } from "react"
-import { Icon } from "semantic-ui-react"
import { delete_subject, set_subject_attribute } from "../api/subject"
import { activeTabIndex, tabChangeHandler } from "../app_ui_settings"
@@ -10,9 +9,12 @@ import { EDIT_REPORT_PERMISSION, ReadOnlyOrEditable } from "../context/Permissio
import { Header, Tab } from "../semantic_ui_react_wrappers"
import { reportPropType, settingsPropType } from "../sharedPropTypes"
import { getSubjectType, slugify } from "../utils"
-import { DeleteButton, PermLinkButton, ReorderButtonGroup } from "../widgets/Button"
+import { ButtonRow } from "../widgets/ButtonRow"
+import { DeleteButton } from "../widgets/buttons/DeleteButton"
+import { PermLinkButton } from "../widgets/buttons/PermLinkButton"
+import { ReorderButtonGroup } from "../widgets/buttons/ReorderButtonGroup"
import { HeaderWithDetails } from "../widgets/HeaderWithDetails"
-import { HyperLink } from "../widgets/HyperLink"
+import { ReadTheDocsLink } from "../widgets/ReadTheDocsLink"
import { changelogTabPane, configurationTabPane } from "../widgets/TabPane"
import { SubjectParameters } from "./SubjectParameters"
@@ -23,10 +25,7 @@ function SubjectHeader({ subjectType }) {
{subjectType.name}
- {subjectType.description}{" "}
-
- Read the Docs
-
+ {subjectType.description}
@@ -36,12 +35,13 @@ SubjectHeader.propTypes = {
subjectType: object,
}
-function ButtonRow({ subject_uuid, firstSubject, lastSubject, reload, url }) {
+function SubjectTitleButtonRow({ subject_uuid, firstSubject, lastSubject, reload, url }) {
+ const deleteButton = delete_subject(subject_uuid, reload)} />
return (
+
- delete_subject(subject_uuid, reload)} />
- >
+
}
/>
)
}
-ButtonRow.propTypes = {
+SubjectTitleButtonRow.propTypes = {
subject_uuid: string,
firstSubject: bool,
lastSubject: bool,
@@ -112,7 +111,7 @@ export function SubjectTitle({
onTabChange={tabChangeHandler(settings.expandedItems, subject_uuid)}
panes={panes}
/>
- {
fetch_server_api.fetch_server_api = jest.fn().mockResolvedValue({ ok: true })
await renderSubjectTitle()
await act(async () => {
- fireEvent.click(screen.getByLabelText(/Move subject to the next position/))
+ fireEvent.click(screen.getByRole("button", { name: /Move subject to the next position/ }))
})
expect(fetch_server_api.fetch_server_api).toHaveBeenLastCalledWith(
"post",
diff --git a/components/frontend/src/subject/SubjectType.js b/components/frontend/src/subject/SubjectType.js
index e353327734..a44b001d2f 100644
--- a/components/frontend/src/subject/SubjectType.js
+++ b/components/frontend/src/subject/SubjectType.js
@@ -1,3 +1,4 @@
+import CircleIcon from "@mui/icons-material/Circle"
import { func, number, objectOf, string } from "prop-types"
import { useContext } from "react"
import { HeaderContent, HeaderSubheader } from "semantic-ui-react"
@@ -5,13 +6,19 @@ import { HeaderContent, HeaderSubheader } from "semantic-ui-react"
import { DataModel } from "../context/DataModel"
import { EDIT_REPORT_PERMISSION } from "../context/Permissions"
import { SingleChoiceInput } from "../fields/SingleChoiceInput"
-import { Header, Icon } from "../semantic_ui_react_wrappers"
+import { Header } from "../semantic_ui_react_wrappers"
import { subjectPropType } from "../sharedPropTypes"
export function subjectTypes(subjectTypesMapping, level = 0) {
const options = []
const headingLevel = `h${Math.min(level, 2) + 4}` // Ensure the heading level is at least h4 and at most h6
- const bullet = level === 0 ? null :
+ const bullet =
+ level === 0 ? null : (
+
+ )
Object.entries(subjectTypesMapping).forEach(([key, subjectType]) => {
options.push({
key: key,
diff --git a/components/frontend/src/subject/SubjectsButtonRow.js b/components/frontend/src/subject/SubjectsButtonRow.js
index 87d4e0e7a8..93582ecd62 100644
--- a/components/frontend/src/subject/SubjectsButtonRow.js
+++ b/components/frontend/src/subject/SubjectsButtonRow.js
@@ -6,7 +6,9 @@ import { DataModel } from "../context/DataModel"
import { EDIT_REPORT_PERMISSION, ReadOnlyOrEditable } from "../context/Permissions"
import { Segment } from "../semantic_ui_react_wrappers"
import { reportPropType, reportsPropType, settingsPropType } from "../sharedPropTypes"
-import { AddDropdownButton, CopyButton, MoveButton } from "../widgets/Button"
+import { AddDropdownButton } from "../widgets/buttons/AddDropdownButton"
+import { CopyButton } from "../widgets/buttons/CopyButton"
+import { MoveButton } from "../widgets/buttons/MoveButton"
import { subject_options } from "../widgets/menu_options"
import { subjectTypes } from "./SubjectType"
diff --git a/components/frontend/src/widgets/ButtonRow.js b/components/frontend/src/widgets/ButtonRow.js
new file mode 100644
index 0000000000..1f968891fa
--- /dev/null
+++ b/components/frontend/src/widgets/ButtonRow.js
@@ -0,0 +1,17 @@
+import { Box } from "@mui/material"
+import { element } from "prop-types"
+
+import { childrenPropType } from "../sharedPropTypes"
+
+export function ButtonRow({ children, rightButton }) {
+ return (
+
+ {children}
+ {rightButton}
+
+ )
+}
+ButtonRow.propTypes = {
+ children: childrenPropType,
+ rightButton: element,
+}
diff --git a/components/frontend/src/widgets/LabelWithHelp.js b/components/frontend/src/widgets/LabelWithHelp.js
index f09b9849c7..1d744eb063 100644
--- a/components/frontend/src/widgets/LabelWithHelp.js
+++ b/components/frontend/src/widgets/LabelWithHelp.js
@@ -12,7 +12,7 @@ export function LabelWithHelp({ labelId, labelFor, label, help, hoverable }) {
hoverable={hoverable}
on={["hover", "focus"]}
content={help}
- trigger={}
+ trigger={}
wide
/>