-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
Closes #9796.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,3 @@ | ||
.MainContainer { | ||
flex: 1; | ||
margin-top: 6em; | ||
padding-left: 1em; | ||
padding-right: 1em; | ||
} | ||
|
||
@media print { | ||
.MainContainer { | ||
margin-top: 0em; | ||
} | ||
} | ||
|
||
html { | ||
scroll-padding-top: 163px; /* height of sticky header */ | ||
} | ||
|
||
:root { | ||
--inverted-menu-background-color: #1b1c1d; | ||
--selection-color: #2185d0; | ||
scroll-padding-top: 176px; /* height of sticky header */ | ||
} |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { Stack, Typography } from "@mui/material" | ||
|
||
import { datePropType, reportPropType } from "../sharedPropTypes" | ||
import { HyperLink } from "../widgets/HyperLink" | ||
|
||
export function PageHeader({ lastUpdate, report, reportDate }) { | ||
const reportURL = new URLSearchParams(window.location.search).get("report_url") ?? window.location.href | ||
const title = report?.title ?? "Reports overview" | ||
const changelogURL = `https://quality-time.readthedocs.io/en/v${process.env.REACT_APP_VERSION}/changelog.html` | ||
return ( | ||
<Stack | ||
direction="row" | ||
spacing={2} | ||
sx={{ display: "none", displayPrint: "inline-flex", justifyContent: "space-between", width: "100%" }} | ||
> | ||
<Typography key={"reportURL"} data-testid={"reportUrl"}> | ||
<HyperLink url={reportURL}>{title}</HyperLink> | ||
</Typography> | ||
<Typography key={"date"}>{"Report date: " + formatDate(reportDate ?? new Date())}</Typography> | ||
<Typography key={"generated"}> | ||
{"Generated: " + formatDate(lastUpdate) + ", " + formatTime(lastUpdate)} | ||
</Typography> | ||
<Typography key={"version"} data-testid={"version"}> | ||
<HyperLink url={changelogURL}>Quality-time v{process.env.REACT_APP_VERSION}</HyperLink> | ||
</Typography> | ||
</Stack> | ||
) | ||
} | ||
PageHeader.propTypes = { | ||
lastUpdate: datePropType, | ||
report: reportPropType, | ||
reportDate: datePropType, | ||
} | ||
|
||
// Hard code en-GB to get European style dates and times. See https://github.com/ICTU/quality-time/issues/8381. | ||
|
||
function formatDate(date) { | ||
return date.toLocaleDateString("en-GB", { year: "numeric", month: "2-digit", day: "2-digit" }).replace(/\//g, "-") | ||
} | ||
|
||
function formatTime(date) { | ||
return date.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" }) | ||
} |
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { bool, func, string } from "prop-types" | ||
|
||
import { TextField } from "./TextField" | ||
|
||
export function CommentField({ disabled, id, onChange, value }) { | ||
return ( | ||
<TextField | ||
disabled={disabled} | ||
id={id} | ||
label="Comment" | ||
multiline | ||
onChange={onChange} | ||
placeholder="Enter comments here (HTML allowed; URL's are transformed into links)" | ||
value={value} | ||
/> | ||
) | ||
} | ||
CommentField.propTypes = { | ||
disabled: bool, | ||
id: string, | ||
onChange: func, | ||
value: string, | ||
} |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { Autocomplete, TextField } from "@mui/material" | ||
import { arrayOf, bool, element, func, object, oneOfType, string } from "prop-types" | ||
|
||
import { stringsPropType } from "../sharedPropTypes" | ||
|
||
export function MultipleChoiceField({ | ||
disabled, | ||
freeSolo, | ||
helperText, | ||
label, | ||
onChange, | ||
onInputChange, | ||
options, | ||
placeholder, | ||
startAdornment, | ||
value, | ||
}) { | ||
return ( | ||
<Autocomplete | ||
value={value} | ||
disabled={disabled} | ||
filterOptions={(x) => x} // Disable built-in filtering | ||
freeSolo={freeSolo} // Allow additional options | ||
fullWidth | ||
multiple | ||
options={options} | ||
onChange={(_event, value) => onChange(value.map((value) => value?.id ?? value))} | ||
onInputChange={onInputChange} | ||
renderInput={(params) => { | ||
return ( | ||
<TextField | ||
{...params} | ||
helperText={helperText} | ||
label={label} | ||
placeholder={value.length === 0 ? placeholder : ""} | ||
slotProps={{ | ||
input: { | ||
...params.InputProps, | ||
startAdornment: ( | ||
<> | ||
{startAdornment} | ||
{params.InputProps.startAdornment} | ||
</> | ||
), | ||
}, | ||
}} | ||
/> | ||
) | ||
}} | ||
/> | ||
) | ||
} | ||
MultipleChoiceField.propTypes = { | ||
disabled: bool, | ||
freeSolo: bool, | ||
helperText: string, | ||
label: string, | ||
onChange: func, | ||
onInputChange: func, | ||
options: oneOfType([stringsPropType, arrayOf(object)]), | ||
placeholder: string, | ||
startAdornment: element, | ||
value: stringsPropType, | ||
} |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { InputAdornment, TextField as MUITextField } from "@mui/material" | ||
import { bool, element, func, number, oneOfType, string } from "prop-types" | ||
import { useState } from "react" | ||
|
||
import { childrenPropType } from "../sharedPropTypes" | ||
|
||
export function TextField({ | ||
children, | ||
disabled, | ||
endAdornment, | ||
error, | ||
helperText, | ||
id, | ||
label, | ||
max, | ||
multiline, | ||
onChange, | ||
placeholder, | ||
required, | ||
select, | ||
startAdornment, | ||
type, | ||
value, | ||
}) { | ||
const [textValue, setTextValue] = useState(value) | ||
|
||
function submitIfChanged() { | ||
if (textValue !== value) { | ||
onChange(textValue) | ||
} | ||
} | ||
|
||
function onKeyDown(event) { | ||
if (event.key === "Escape") { | ||
setTextValue(value) | ||
} | ||
if (event.key === "Enter") { | ||
submitIfChanged() | ||
} | ||
} | ||
|
||
const startInputAdornment = startAdornment ? ( | ||
<InputAdornment position="start">{startAdornment}</InputAdornment> | ||
) : null | ||
const endInputAdornment = endAdornment ? <InputAdornment position="end">{endAdornment}</InputAdornment> : null | ||
return ( | ||
<MUITextField | ||
defaultValue={textValue ?? ""} | ||
disabled={disabled || (select && children.length === 0)} | ||
error={error} | ||
fullWidth | ||
helperText={helperText} | ||
id={id} | ||
label={label} | ||
maxRows={8} | ||
minRows={3} | ||
multiline={multiline} | ||
onBlur={() => submitIfChanged()} | ||
onChange={select ? (event) => onChange(event.target.value) : (event) => setTextValue(event.target.value)} | ||
onKeyDown={onKeyDown} | ||
onWheel={(event) => event.target.blur()} // Prevent scrolling from changing the number value | ||
placeholder={placeholder} | ||
required={required} | ||
select={select && children.length > 0} | ||
slotProps={{ | ||
input: { | ||
endAdornment: endInputAdornment, | ||
inputProps: { | ||
max: max, | ||
min: 0, | ||
}, | ||
startAdornment: startInputAdornment, | ||
}, | ||
}} | ||
type={type} | ||
variant="outlined" | ||
> | ||
{children} | ||
</MUITextField> | ||
) | ||
} | ||
TextField.propTypes = { | ||
children: childrenPropType, | ||
disabled: bool, | ||
endAdornment: oneOfType([element, string]), | ||
error: bool, | ||
helperText: oneOfType([element, string]), | ||
id: string, | ||
label: oneOfType([element, string]), | ||
max: number, | ||
multiline: bool, | ||
onChange: func, | ||
placeholder: string, | ||
required: bool, | ||
select: bool, | ||
startAdornment: oneOfType([element, string]), | ||
type: string, | ||
value: oneOfType([bool, string]), | ||
} |
This file was deleted.
This file was deleted.
This file was deleted.