Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1,566 changes: 763 additions & 803 deletions ui/package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
"@date-io/luxon": "^3.2.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@fontsource/roboto": "^5.2.8",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from deprecated roboto to current.

"@lingui/core": "^4.14.0",
"@lingui/react": "^4.14.0",
"@mui/icons-material": "^6.4.12",
"@mui/material": "^6.4.8",
"@mui/x-date-pickers": "^7.29.4",
"@mui/icons-material": "^7.3.4",
"@mui/material": "^7.3.4",
"@mui/x-date-pickers": "^8.14.1",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.1",
"@reduxjs/toolkit": "^1.9.7",
"@svgr/webpack": "^8.1.0",
Expand All @@ -36,7 +37,7 @@
"dotenv-expand": "^12.0.3",
"file-loader": "^6.2.0",
"formik": "^2.4.6",
"formik-mui": "5.0.0-alpha.0",
"formik-mui": "5.0.0-alpha.1",
"fs-extra": "^11.3.2",
"html-webpack-plugin": "^5.6.4",
"identity-obj-proxy": "^3.0.0",
Expand Down Expand Up @@ -76,7 +77,6 @@
"style-loader": "^4.0.0",
"terser-webpack-plugin": "^5.3.14",
"tss-react": "^4.9.19",
"typeface-roboto": "1.1.13",
"typescript": "~5.9.3",
"webpack": "^5.102.1",
"webpack-dev-server": "^5.2.2",
Expand Down
13 changes: 10 additions & 3 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import {
Routes,
Route,
} from "react-router-dom";
import "typeface-roboto";
import "@fontsource/roboto";

import store, { AppDispatch } from "app/store";
import { Provider } from "react-redux";
import { i18n } from "@lingui/core";
import { I18nProvider } from "@lingui/react";
import { messages as enMessages } from "locale/en/messages";

// apply material-ui cross-browser style normalizaion
// apply material-ui cross-browser style normalization
import CssBaseline from "@mui/material/CssBaseline";
import useMediaQuery from "@mui/material/useMediaQuery";
import { makeStyles } from "tss-react/mui";
Expand Down Expand Up @@ -47,6 +47,7 @@ const ResultsPage = React.lazy(() => import("pages/ResultsPage"));
const SearchPage = React.lazy(() => import("pages/SearchPage"));
const UsersPage = React.lazy(() => import("pages/UsersPage"));
const UserSettings = React.lazy(() => import("pages/UserSettings"));
const DatePickerTestPage = React.lazy(() => import("pages/DatePickerTestPage"));

// browser language preference
// currently used for displaying times in locale-specific format
Expand Down Expand Up @@ -143,6 +144,12 @@ export const AppRoutes = () => {
)}
<Route path="/settings" element={<UserSettings />} />
<Route path="/search" element={<SearchPage />} />
{process.env.NODE_ENV === "development" && (
<Route
path="/datepicker-test"
element={<DatePickerTestPage />}
/>
)}
<Route path="*" element={<Navigate to="/" />} />
</Routes>
</React.Suspense>
Expand Down Expand Up @@ -283,7 +290,7 @@ const ThemedApp = () => {
);

// TODO i18n: Date/Time pickers have changed the way they handle i18n
// instead of overriding indivudal strings like okText, cancelText, etc. you now wrap the component in a <LocalizationProvider> with an "adapterLocale" set
// instead of overriding individual strings like okText, cancelText, etc. you now wrap the component in a <LocalizationProvider> with an "adapterLocale" set
// this is more complete, since it also translates items like calendar month names
// see: https://mui.com/x/react-date-pickers/date-picker/#localization

Expand Down
28 changes: 13 additions & 15 deletions ui/src/app/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
AppBar,
Box,
CircularProgress,
Hidden,
IconButton,
ListItemIcon,
ListItemText,
Expand Down Expand Up @@ -261,20 +260,19 @@ const NavBar = (props: INavBar) => {
{systemStatus.maintenance.message}
</Alert>
)}
<Hidden mdDown>
<Box
displayPrint="none"
style={{ position: "absolute", right: "1rem" }}
>
{currentUser?.last_login && (
<Typography variant="caption">
<Trans>
Last Login: {formatDate(currentUser.last_login, "long")}
</Trans>
</Typography>
)}
</Box>
</Hidden>
<Box
sx={{ display: { xs: "none", md: "block" } }}
displayPrint="none"
style={{ position: "absolute", right: "1rem" }}
>
{currentUser?.last_login && (
<Typography variant="caption">
<Trans>
Last Login: {formatDate(currentUser.last_login, "long")}
</Trans>
</Typography>
)}
</Box>
</div>
);
};
Expand Down
20 changes: 12 additions & 8 deletions ui/src/components/ApiKeys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
FormGroup,
FormHelperText,
FormLabel,
Grid2 as Grid,
Grid,
IconButton,
InputAdornment,
LinearProgress,
Expand Down Expand Up @@ -199,7 +199,7 @@ interface ScrollToTopProps {
}

// element that will appear as user approaches bottom of target element
// and will scroll back to element indentified by selector
// and will scroll back to element identified by selector
// will usually wrap a <Fab> child element
function ScrollTop(props: ScrollToTopProps) {
const { children, selector, target } = props;
Expand Down Expand Up @@ -1265,7 +1265,6 @@ const ApiKeys: React.FC<ApiKeysProps> = ({ title = "API Keys", user }) => {
<ListItemText
classes={{ secondary: classes.listItemText }}
primary={i18n._(t`Scope`)}
disableTypography={true}
secondary={
selectedRow?.scope &&
Array.isArray(selectedRow.scope) &&
Expand All @@ -1281,6 +1280,11 @@ const ApiKeys: React.FC<ApiKeysProps> = ({ title = "API Keys", user }) => {
</i>
)
}
slotProps={{
secondary: {
component: "span",
},
}}
/>
</Tooltip>
</ListItem>
Expand All @@ -1301,7 +1305,6 @@ const ApiKeys: React.FC<ApiKeysProps> = ({ title = "API Keys", user }) => {
>
<ListItemText
primary={i18n._(t`Features`)}
disableTypography={true}
secondary={
featuresChips &&
Array.isArray(featuresChips) &&
Expand All @@ -1313,6 +1316,11 @@ const ApiKeys: React.FC<ApiKeysProps> = ({ title = "API Keys", user }) => {
</i>
)
}
slotProps={{
secondary: {
component: "span",
},
}}
/>
</Tooltip>
</ListItem>
Expand All @@ -1331,7 +1339,6 @@ const ApiKeys: React.FC<ApiKeysProps> = ({ title = "API Keys", user }) => {
>
<ListItemText
primary={i18n._(t`Type`)}
disableTypography={true}
secondary={
selectedRow?.admin
? i18n._(t`Administrator`)
Expand All @@ -1352,7 +1359,6 @@ const ApiKeys: React.FC<ApiKeysProps> = ({ title = "API Keys", user }) => {
</ListItemIcon>
<ListItemText
primary={i18n._(t`Created Date`)}
disableTypography={true}
secondary={
selectedRow?.created ? (
<DateTimeCell value={selectedRow?.created} format="long" />
Expand All @@ -1373,7 +1379,6 @@ const ApiKeys: React.FC<ApiKeysProps> = ({ title = "API Keys", user }) => {
</ListItemIcon>
<ListItemText
primary={i18n._(t`Expiration Date`)}
disableTypography={true}
secondary={
selectedRow?.expires ? (
<ExpiringDateTimeCell
Expand All @@ -1397,7 +1402,6 @@ const ApiKeys: React.FC<ApiKeysProps> = ({ title = "API Keys", user }) => {
</ListItemIcon>
<ListItemText
primary={i18n._(t`Last Used Date`)}
disableTypography={true}
secondary={
selectedRow?.last_used ? (
<DateTimeCell
Expand Down
9 changes: 6 additions & 3 deletions ui/src/components/AutoCompleteField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ const AutoCompleteField = React.forwardRef(
ref={ref}
name={allParams.name}
error={allParams.error}
InputProps={InputProps}
helperText={allParams.helperText}
label={
loading ? i18n._(t`Loading options...`) : allParams.label
}
placeholder={allParams.placeholder}
variant="outlined"
slotProps={{
input: InputProps,
}}
/>
);
}}
Expand All @@ -62,9 +64,10 @@ const AutoCompleteField = React.forwardRef(
}
const matches = match(optionLabel, inputValue);
const parts = parse(optionLabel, matches);

// don't pass key in with rest of props
const { key, ...otherProps } = renderProps;
return (
<li {...renderProps}>
<li key={key} {...otherProps}>
<div>
{parts.map((part, index) => (
<span
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/EnhancedTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ interface MenuOptions {
}

interface EnhancedTableProps {
id?: string; // row field to use for unique key, defaults to keyId if unsupplied
id?: string; // row field to use for unique key, defaults to keyId if not supplied
columns: ColDef[];
rows: RowDef[];
defaultOrder?: Order; // how all columns will be ordered initially unless overridden in ColDef.order, default: "asc"
Expand Down
40 changes: 16 additions & 24 deletions ui/src/components/FormikPickers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,13 @@ import { browserLanguage } from "App";
import { InputBaseProps } from "@mui/material";

// Formik wrapper for Material UI date/time pickers
// adapted from Material-UI picker Formik sample:
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed broken linkl

// https://next.material-ui-pickers.dev/guides/forms#validation-props
//
// also adds i18n for component labels
//
// usage:
// <Field ...attrs component={DateTimePicker} />

interface DatePickerFieldProps
extends FieldProps,
DesktopDateTimePickerProps<DateTime> {
id?: string;
interface DatePickerFieldProps extends FieldProps, DesktopDateTimePickerProps {
id: string;
getShouldDisableDateError: (date: DateTime | null) => string;
size?: "small" | "medium";
style?: React.CSSProperties;
Expand All @@ -44,7 +39,6 @@ const DatePickerField = (props: DatePickerFieldProps) => {
field,
form,
getShouldDisableDateError,
onChange,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was never used.

invalidDateMessage,
minDateMessage,
maxDateMessage,
Expand Down Expand Up @@ -72,23 +66,19 @@ const DatePickerField = (props: DatePickerFieldProps) => {
if (!localeText?.nextMonth) {
localeText.nextMonth = i18n._(t`Next month`);
}
// x-date-pickers v6 expects the picker's field value to be in the adapter's date/time format - it no longer performs this conversion
// so this wrapper will now handle this conversion
// Luxon adapter doesn't accept Date objects, so convert to a string first.

if (field.value && typeof field.value.toISOString === "function") {
field.value = field.value.toISOString();
}
const adapter = new DateAdapter({ locale: browserLanguage });
const fieldValue = adapter.date(field.value);
let fieldValue = field.value || null;
if (field.value && typeof field.value === "string") {
const adapter = new DateAdapter({ locale: browserLanguage });
fieldValue = adapter.date(field.value);
}

// for a11y assign an additional title to the input field separate from the value, since v6 x-date-pickers picker value contains additional non-display characters
// const displayValue = fieldValue
// ? fieldValue.toFormat(other.format ?? "yyyy/LL/dd HH:mm")
// : "";
const displayValue = "";
const inputProps: InputBaseProps["inputProps"] = {
id: props.id,
title: displayValue,
"data-testid": `${field.name}_date_input`,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a testid to the input, the date field is no longer a single input, but it added a hidden input field to show the date, using this on tests.

};
if (props.placeholder) {
inputProps.placeholder = props.placeholder;
Expand Down Expand Up @@ -125,11 +115,13 @@ const DatePickerField = (props: DatePickerFieldProps) => {
label={props?.label}
onChange={(date) => {
form.setFieldTouched(field.name, true, false);
if (muiError) {
form.setFieldValue(field.name, date, false);
form.setFieldError(field.name, muiError);
} else {
form.setFieldValue(field.name, date, true);
if (date) {
if (muiError) {
form.setFieldValue(field.name, date, false);
form.setFieldError(field.name, muiError);
} else {
form.setFieldValue(field.name, date, true);
}
}
}}
onError={(code, value) => {
Expand Down
Loading
Loading