mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
Fix: UI improvements (#1114)
* fix: segments table author column width * fix: update feature form ui * fix: strategies breadcrumbs * fix: api token page title * fix: deprecated strategy label color * fix: project access remove user toast * fix: addon enable toast message * fix: ces from ui * fix: ui improvements with dialog typography * fix: revert ces * fix: change password error type
This commit is contained in:
parent
566d0613a4
commit
c0b52fa672
@ -53,7 +53,7 @@ export const ConfiguredAddons = () => {
|
||||
type: 'success',
|
||||
title: 'Success',
|
||||
text: !addon.enabled
|
||||
? 'Addon is now active'
|
||||
? 'Addon is now enabled'
|
||||
: 'Addon is now disabled',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
|
@ -11,6 +11,9 @@ import { ConfirmToken } from '../ConfirmToken/ConfirmToken';
|
||||
import { useState } from 'react';
|
||||
import { scrollToTop } from 'component/common/util';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
|
||||
const pageTitle = 'Create API token';
|
||||
|
||||
export const CreateApiToken = () => {
|
||||
const { setToastApiError } = useToast();
|
||||
@ -36,6 +39,8 @@ export const CreateApiToken = () => {
|
||||
|
||||
const { createToken, loading } = useApiTokensApi();
|
||||
|
||||
usePageTitle(pageTitle);
|
||||
|
||||
const handleSubmit = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
if (!isValid()) {
|
||||
@ -76,7 +81,7 @@ export const CreateApiToken = () => {
|
||||
return (
|
||||
<FormTemplate
|
||||
loading={loading}
|
||||
title="Create Api Token"
|
||||
title={pageTitle}
|
||||
description="In order to connect to Unleash clients will need an API token to grant access. A client SDK will need to token with 'client privileges', which allows them to fetch feature toggle configuration and post usage metrics back."
|
||||
documentationLink="https://docs.getunleash.io/reference/api-tokens-and-client-keys"
|
||||
documentationLinkLabel="API tokens documentation"
|
||||
|
@ -10,24 +10,24 @@ import PasswordChecker, {
|
||||
import { useThemeStyles } from 'themes/themeStyles';
|
||||
import PasswordMatcher from 'component/user/common/ResetPasswordForm/PasswordMatcher/PasswordMatcher';
|
||||
import { IUser } from 'interfaces/user';
|
||||
import useAdminUsersApi from 'hooks/api/actions/useAdminUsersApi/useAdminUsersApi';
|
||||
|
||||
interface IChangePasswordProps {
|
||||
showDialog: boolean;
|
||||
closeDialog: () => void;
|
||||
changePassword: (userId: number, password: string) => Promise<Response>;
|
||||
user: IUser;
|
||||
}
|
||||
|
||||
const ChangePassword = ({
|
||||
showDialog,
|
||||
closeDialog,
|
||||
changePassword,
|
||||
user,
|
||||
}: IChangePasswordProps) => {
|
||||
const [data, setData] = useState<Record<string, string>>({});
|
||||
const [error, setError] = useState<string>();
|
||||
const [validPassword, setValidPassword] = useState(false);
|
||||
const { classes: themeStyles } = useThemeStyles();
|
||||
const { changePassword } = useAdminUsersApi();
|
||||
|
||||
const updateField: React.ChangeEventHandler<HTMLInputElement> = event => {
|
||||
setError(undefined);
|
||||
|
@ -45,8 +45,7 @@ const UsersList = () => {
|
||||
const navigate = useNavigate();
|
||||
const { users, roles, refetch, loading } = useUsers();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { removeUser, changePassword, userLoading, userApiErrors } =
|
||||
useAdminUsersApi();
|
||||
const { removeUser, userLoading, userApiErrors } = useAdminUsersApi();
|
||||
const [pwDialog, setPwDialog] = useState<{ open: boolean; user?: IUser }>({
|
||||
open: false,
|
||||
});
|
||||
@ -320,7 +319,6 @@ const UsersList = () => {
|
||||
<ChangePassword
|
||||
showDialog={pwDialog.open}
|
||||
closeDialog={closePwDialog}
|
||||
changePassword={changePassword}
|
||||
user={pwDialog.user!}
|
||||
/>
|
||||
)}
|
||||
|
@ -23,7 +23,6 @@ const BreadcrumbNav = () => {
|
||||
item !== 'logs' &&
|
||||
item !== 'metrics' &&
|
||||
item !== 'copy' &&
|
||||
item !== 'strategies' &&
|
||||
item !== 'features' &&
|
||||
item !== 'features2' &&
|
||||
item !== 'create-toggle' &&
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
|
||||
import { DialogContentText } from '@mui/material';
|
||||
import { Typography } from '@mui/material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||
import React from 'react';
|
||||
@ -25,14 +25,13 @@ export const FeatureStaleDialog = ({
|
||||
const { patchFeatureToggle } = useFeatureApi();
|
||||
|
||||
const toggleToStaleContent = (
|
||||
<DialogContentText>
|
||||
Setting a toggle to stale marks it for cleanup
|
||||
</DialogContentText>
|
||||
<Typography>Setting a toggle to stale marks it for cleanup</Typography>
|
||||
);
|
||||
|
||||
const toggleToActiveContent = (
|
||||
<DialogContentText>
|
||||
<Typography>
|
||||
Setting a toggle to active marks it as in active use
|
||||
</DialogContentText>
|
||||
</Typography>
|
||||
);
|
||||
|
||||
const toggleActionText = isStale ? 'active' : 'stale';
|
||||
|
@ -16,7 +16,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
border: `1px solid ${theme.palette.grey[300]}`,
|
||||
border: `1px solid ${theme.palette.grey[500]}`,
|
||||
borderRadius: theme.shape.borderRadiusExtraLarge,
|
||||
padding: '3px 5px 3px 12px',
|
||||
width: '100%',
|
||||
|
@ -76,7 +76,7 @@ const CreateFeature = () => {
|
||||
return (
|
||||
<FormTemplate
|
||||
loading={loading}
|
||||
title="Create Feature toggle"
|
||||
title="Create feature toggle"
|
||||
description="Feature toggles support different use cases, each with their own specific needs such as simple static routing or more complex routing.
|
||||
The feature toggle is disabled when created and you decide when to enable"
|
||||
documentationLink="https://docs.getunleash.io/advanced/feature_toggle_types"
|
||||
@ -102,7 +102,7 @@ const CreateFeature = () => {
|
||||
clearErrors={clearErrors}
|
||||
>
|
||||
<CreateButton
|
||||
name="Feature"
|
||||
name="feature toggle"
|
||||
permission={CREATE_FEATURE}
|
||||
projectId={project}
|
||||
data-testid={CF_CREATE_BTN_ID}
|
||||
|
@ -33,10 +33,11 @@ export const useStyles = makeStyles()(theme => ({
|
||||
},
|
||||
inputDescription: {
|
||||
marginBottom: '0.5rem',
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
typeDescription: {
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
color: theme.palette.grey[600],
|
||||
color: theme.palette.text.secondary,
|
||||
top: '-13px',
|
||||
position: 'relative',
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
title: {
|
||||
margin: 0,
|
||||
marginBottom: '.5rem',
|
||||
fontSize: theme.fontSizes.smallerBody,
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
fontWeight: theme.fontWeight.thin,
|
||||
color: theme.palette.grey[800],
|
||||
},
|
||||
|
@ -2,8 +2,7 @@ import { FeatureMetricsTable } from '../FeatureMetricsTable/FeatureMetricsTable'
|
||||
import { IFeatureMetricsRaw } from 'interfaces/featureToggle';
|
||||
import { FeatureMetricsStatsRaw } from '../FeatureMetricsStats/FeatureMetricsStatsRaw';
|
||||
import { FeatureMetricsChart } from '../FeatureMetricsChart/FeatureMetricsChart';
|
||||
import { FeatureMetricsEmpty } from '../FeatureMetricsEmpty/FeatureMetricsEmpty';
|
||||
import { Box } from '@mui/material';
|
||||
import { Box, Typography } from '@mui/material';
|
||||
import theme from 'themes/theme';
|
||||
import { useId } from 'hooks/useId';
|
||||
|
||||
@ -22,7 +21,14 @@ export const FeatureMetricsContent = ({
|
||||
if (metrics.length === 0) {
|
||||
return (
|
||||
<Box mt={6}>
|
||||
<FeatureMetricsEmpty />
|
||||
<Typography variant="body1" paragraph>
|
||||
We have yet to receive any metrics for this feature toggle
|
||||
in the selected time period.
|
||||
</Typography>
|
||||
<Typography variant="body1" paragraph>
|
||||
Please note that, since the SDKs send metrics on an
|
||||
interval, it might take some time before metrics appear.
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { Typography } from '@mui/material';
|
||||
|
||||
export const FeatureMetricsEmpty = () => {
|
||||
return (
|
||||
<>
|
||||
<Typography variant="body1" paragraph>
|
||||
We have yet to receive any metrics for this feature toggle in
|
||||
the selected time period.
|
||||
</Typography>
|
||||
<Typography variant="body1" paragraph>
|
||||
Please note that, since the SDKs send metrics on an interval, it
|
||||
might take some time before metrics appear.
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
import { DialogContentText } from '@mui/material';
|
||||
import { Typography } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||
import Input from 'component/common/Input/Input';
|
||||
@ -30,7 +30,7 @@ const AddTagDialog = ({ open, setOpen }: IAddTagDialogProps) => {
|
||||
const { addTagToFeature, loading } = useFeatureApi();
|
||||
const { refetch } = useTags(featureId);
|
||||
const [errors, setErrors] = useState({ tagError: '' });
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { setToastData } = useToast();
|
||||
const [tag, setTag] = useState(DEFAULT_TAG);
|
||||
|
||||
const onCancel = () => {
|
||||
@ -64,7 +64,6 @@ const AddTagDialog = ({ open, setOpen }: IAddTagDialogProps) => {
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const message = formatUnknownError(error);
|
||||
setToastApiError(message);
|
||||
setErrors({ tagError: message });
|
||||
}
|
||||
};
|
||||
@ -84,9 +83,9 @@ const AddTagDialog = ({ open, setOpen }: IAddTagDialogProps) => {
|
||||
formId={formId}
|
||||
>
|
||||
<>
|
||||
<DialogContentText>
|
||||
<Typography paragraph>
|
||||
Tags allow you to group features together
|
||||
</DialogContentText>
|
||||
</Typography>
|
||||
<form id={formId} onSubmit={onSubmit}>
|
||||
<section className={styles.dialogFormContent}>
|
||||
<TagSelect
|
||||
|
@ -27,8 +27,6 @@ export const useStyles = makeStyles()(theme => ({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
padding: '1rem',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
closeIcon: {
|
||||
fontSize: '1.5rem',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Modal } from '@mui/material';
|
||||
import { IconButton, Modal } from '@mui/material';
|
||||
import React, { useContext } from 'react';
|
||||
import {
|
||||
feedbackCESContext,
|
||||
@ -16,12 +16,6 @@ export const FeedbackCES = ({ state }: IFeedbackCESProps) => {
|
||||
const { hideFeedbackCES } = useContext(feedbackCESContext);
|
||||
const { classes: styles } = useStyles();
|
||||
|
||||
const closeButton = (
|
||||
<button className={styles.close} onClick={hideFeedbackCES}>
|
||||
<CloseOutlined titleAccess="Close" className={styles.closeIcon} />
|
||||
</button>
|
||||
);
|
||||
|
||||
const modalContent = state && (
|
||||
<FeedbackCESForm state={state} onClose={hideFeedbackCES} />
|
||||
);
|
||||
@ -34,7 +28,14 @@ export const FeedbackCES = ({ state }: IFeedbackCESProps) => {
|
||||
>
|
||||
<div className={styles.overlay}>
|
||||
<div className={styles.modal}>
|
||||
{closeButton}
|
||||
<div className={styles.close}>
|
||||
<IconButton onClick={hideFeedbackCES} size="large">
|
||||
<CloseOutlined
|
||||
titleAccess="Close"
|
||||
className={styles.closeIcon}
|
||||
/>
|
||||
</IconButton>
|
||||
</div>
|
||||
{modalContent}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
all: 'unset',
|
||||
display: 'block',
|
||||
textAlign: 'center',
|
||||
color: theme.palette.grey[600],
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
subtitle: {
|
||||
all: 'unset',
|
||||
|
@ -8,9 +8,9 @@ export const useStyles = makeStyles()(theme => ({
|
||||
margin: '0 auto',
|
||||
},
|
||||
scoreHelp: {
|
||||
width: '8rem',
|
||||
width: '6.25rem',
|
||||
whiteSpace: 'nowrap',
|
||||
color: theme.palette.grey[600],
|
||||
color: theme.palette.text.secondary,
|
||||
'&:first-of-type': {
|
||||
textAlign: 'right',
|
||||
},
|
||||
|
@ -7,7 +7,7 @@ exports[`FeedbackCESForm 1`] = `
|
||||
class="tss-fdcp7c-container"
|
||||
>
|
||||
<h1
|
||||
class="tss-1a5bydb-title"
|
||||
class="tss-iyd7t0-title"
|
||||
>
|
||||
Please help us improve
|
||||
</h1>
|
||||
@ -24,7 +24,7 @@ exports[`FeedbackCESForm 1`] = `
|
||||
class="tss-io6e1g-scoreInput"
|
||||
>
|
||||
<span
|
||||
class="tss-b4a690-scoreHelp"
|
||||
class="tss-16omcck-scoreHelp"
|
||||
>
|
||||
Very difficult
|
||||
</span>
|
||||
@ -113,7 +113,7 @@ exports[`FeedbackCESForm 1`] = `
|
||||
</span>
|
||||
</label>
|
||||
<span
|
||||
class="tss-b4a690-scoreHelp"
|
||||
class="tss-16omcck-scoreHelp"
|
||||
>
|
||||
Very easy
|
||||
</span>
|
||||
|
@ -57,7 +57,9 @@ export const ProjectAccessPage = () => {
|
||||
refetchProjectAccess();
|
||||
setToastData({
|
||||
type: 'success',
|
||||
title: 'The user has been removed from project',
|
||||
title: `${
|
||||
user.email || user.username || 'The user'
|
||||
} has been removed from project`,
|
||||
});
|
||||
} catch (err: any) {
|
||||
setToastData({
|
||||
|
@ -1,3 +1,4 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { CreateButton } from 'component/common/CreateButton/CreateButton';
|
||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||
import { CREATE_SEGMENT } from 'component/providers/AccessProvider/permissions';
|
||||
@ -6,7 +7,6 @@ import { useConstraintsValidation } from 'hooks/api/getters/useConstraintsValida
|
||||
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import useToast from 'hooks/useToast';
|
||||
import React, { useContext } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { useSegmentForm } from '../hooks/useSegmentForm';
|
||||
|
@ -162,7 +162,7 @@ const COLUMNS = [
|
||||
{
|
||||
Header: 'Name',
|
||||
accessor: 'name',
|
||||
width: '80%',
|
||||
width: '60%',
|
||||
Cell: ({ value, row: { original } }: any) => (
|
||||
<HighlightCell value={value} subtitle={original.description} />
|
||||
),
|
||||
@ -177,6 +177,7 @@ const COLUMNS = [
|
||||
{
|
||||
Header: 'Created by',
|
||||
accessor: 'createdBy',
|
||||
width: '25%',
|
||||
},
|
||||
{
|
||||
Header: 'Actions',
|
||||
|
@ -4,7 +4,11 @@ export const useStyles = makeStyles()(theme => ({
|
||||
paramsContainer: {
|
||||
maxWidth: '400px',
|
||||
},
|
||||
divider: { borderStyle: 'dashed', marginBottom: '1rem !important' },
|
||||
divider: {
|
||||
borderStyle: 'dashed',
|
||||
marginBottom: '1rem !important',
|
||||
borderColor: theme.palette.grey[500],
|
||||
},
|
||||
nameContainer: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { Checkbox, FormControlLabel, IconButton, Tooltip } from '@mui/material';
|
||||
import {
|
||||
Checkbox,
|
||||
Divider,
|
||||
FormControlLabel,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
} from '@mui/material';
|
||||
import { Delete } from '@mui/icons-material';
|
||||
import { useStyles } from './StrategyParameter.styles';
|
||||
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
|
||||
@ -69,7 +75,7 @@ export const StrategyParameter = ({
|
||||
|
||||
return (
|
||||
<div className={styles.paramsContainer}>
|
||||
<hr className={styles.divider} />
|
||||
<Divider className={styles.divider} />
|
||||
<ConditionallyRender
|
||||
condition={index === 0}
|
||||
show={
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
Tooltip,
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import { Add, RadioButtonChecked } from '@mui/icons-material';
|
||||
import { AppsLinkList } from 'component/common';
|
||||
@ -26,6 +27,7 @@ export const StrategyDetails = ({
|
||||
applications,
|
||||
toggles,
|
||||
}: IStrategyDetailsProps) => {
|
||||
const theme = useTheme();
|
||||
const { parameters = [] } = strategy;
|
||||
const renderParameters = (params: IStrategyParameter[]) => {
|
||||
if (params.length > 0) {
|
||||
@ -70,7 +72,9 @@ export const StrategyDetails = ({
|
||||
condition={strategy.deprecated}
|
||||
show={
|
||||
<Grid item>
|
||||
<h5 style={{ color: '#ff0000' }}>Deprecated</h5>
|
||||
<h5 style={{ color: theme.palette.error.main }}>
|
||||
Deprecated
|
||||
</h5>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
|
@ -35,7 +35,7 @@ exports[`renders an empty list correctly 1`] = `
|
||||
className="tss-119iiqp-container"
|
||||
>
|
||||
<div
|
||||
className="tss-1mtd8gr-search search-container"
|
||||
className="tss-1xjrf9m-search search-container"
|
||||
>
|
||||
<svg
|
||||
aria-hidden={true}
|
||||
|
Loading…
Reference in New Issue
Block a user