Skip to content
This repository has been archived by the owner on Oct 27, 2022. It is now read-only.

Commit

Permalink
Merge branch 'main' into fix/playground_virtualisation_loader
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas-unleash committed Aug 10, 2022
2 parents d1a3901 + 493a996 commit dc9154d
Show file tree
Hide file tree
Showing 61 changed files with 527 additions and 588 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "unleash-frontend",
"description": "unleash your features",
"version": "4.14.3",
"version": "4.15.0-beta.0",
"keywords": [
"unleash",
"feature toggle",
Expand Down
4 changes: 2 additions & 2 deletions src/component/admin/groups/GroupsList/GroupsList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useEffect, useMemo, useState, VFC } from 'react';
import { useGroups } from 'hooks/api/getters/useGroups/useGroups';
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { IGroup } from 'interfaces/group';
import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Search } from 'component/common/Search/Search';
import { Button, Grid, useMediaQuery } from '@mui/material';
import { Grid, useMediaQuery } from '@mui/material';
import theme from 'themes/theme';
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { TablePlaceholder } from 'component/common/Table';
Expand Down
6 changes: 3 additions & 3 deletions src/component/admin/users/UserForm/UserForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import React from 'react';
import { useUsers } from 'hooks/api/getters/useUsers/useUsers';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { EDIT } from 'constants/misc';
import useUiBootstrap from 'hooks/api/getters/useUiBootstrap/useUiBootstrap';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';

interface IUserForm {
email: string;
Expand Down Expand Up @@ -49,7 +49,7 @@ const UserForm: React.FC<IUserForm> = ({
}) => {
const { classes: styles } = useStyles();
const { roles } = useUsers();
const { bootstrap } = useUiBootstrap();
const { uiConfig } = useUiConfig();

// @ts-expect-error
const sortRoles = (a, b) => {
Expand Down Expand Up @@ -127,7 +127,7 @@ const UserForm: React.FC<IUserForm> = ({
</RadioGroup>
</FormControl>
<ConditionallyRender
condition={mode !== EDIT && bootstrap?.email}
condition={mode !== EDIT && Boolean(uiConfig?.emailEnabled)}
show={
<FormControl>
<Typography
Expand Down
8 changes: 4 additions & 4 deletions src/component/admin/users/hooks/useAddUserForm.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useEffect, useState } from 'react';
import useUiBootstrap from 'hooks/api/getters/useUiBootstrap/useUiBootstrap';
import { useUsers } from 'hooks/api/getters/useUsers/useUsers';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';

const useCreateUserForm = (
initialName = '',
initialEmail = '',
initialRootRole = 1
) => {
const { bootstrap } = useUiBootstrap();
const { uiConfig } = useUiConfig();
const [name, setName] = useState(initialName);
const [email, setEmail] = useState(initialEmail);
const [sendEmail, setSendEmail] = useState(false);
Expand All @@ -25,8 +25,8 @@ const useCreateUserForm = (
}, [initialEmail]);

useEffect(() => {
setSendEmail(bootstrap?.email || false);
}, [bootstrap?.email]);
setSendEmail(uiConfig?.emailEnabled || false);
}, [uiConfig?.emailEnabled]);

useEffect(() => {
setRootRole(initialRootRole);
Expand Down
15 changes: 5 additions & 10 deletions src/component/common/HelpIcon/HelpIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import { Tooltip } from '@mui/material';
import { Tooltip, TooltipProps } from '@mui/material';
import { Info } from '@mui/icons-material';
import { useStyles } from 'component/common/HelpIcon/HelpIcon.styles';
import React from 'react';

interface IHelpIconProps {
tooltip: string;
style?: React.CSSProperties;
placement?: TooltipProps['placement'];
}

export const HelpIcon = ({ tooltip, style }: IHelpIconProps) => {
export const HelpIcon = ({ tooltip, placement }: IHelpIconProps) => {
const { classes: styles } = useStyles();

return (
<Tooltip title={tooltip} arrow>
<span
className={styles.container}
style={style}
tabIndex={0}
aria-label="Help"
>
<Tooltip title={tooltip} placement={placement} arrow>
<span className={styles.container} tabIndex={0} aria-label="Help">
<Info className={styles.icon} />
</span>
</Tooltip>
Expand Down
7 changes: 4 additions & 3 deletions src/component/common/Search/Search.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, useState } from 'react';
import React, { useRef, useState } from 'react';
import { IconButton, InputBase, Tooltip } from '@mui/material';
import { Search as SearchIcon, Close } from '@mui/icons-material';
import classnames from 'classnames';
Expand All @@ -18,6 +18,7 @@ interface ISearchProps {
disabled?: boolean;
getSearchContext?: () => IGetSearchContextOutput;
containerStyles?: React.CSSProperties;
debounceTime?: number;
}

export const Search = ({
Expand All @@ -29,14 +30,14 @@ export const Search = ({
disabled,
getSearchContext,
containerStyles,
debounceTime = 200,
}: ISearchProps) => {
const ref = useRef<HTMLInputElement>();
const { classes: styles } = useStyles();
const [showSuggestions, setShowSuggestions] = useState(false);

const [value, setValue] = useState(initialValue);

const debouncedOnChange = useAsyncDebounce(onChange, 200);
const debouncedOnChange = useAsyncDebounce(onChange, debounceTime);

const onSearchChange = (value: string) => {
debouncedOnChange(value);
Expand Down
130 changes: 130 additions & 0 deletions src/component/events/EventCard/EventCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import EventDiff from 'component/events/EventDiff/EventDiff';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { IEvent } from 'interfaces/event';
import { useLocationSettings } from 'hooks/useLocationSettings';
import { formatDateYMDHMS } from 'utils/formatDate';
import { Link } from 'react-router-dom';
import { styled } from '@mui/material';

interface IEventCardProps {
entry: IEvent;
}

const StyledDefinitionTerm = styled('dt')(({ theme }) => ({
color: theme.palette.text.secondary,
}));

const StyledChangesTitle = styled('strong')(({ theme }) => ({
fontWeight: 'inherit',
color: theme.palette.text.secondary,
}));

const StyledContainerListItem = styled('li')(({ theme }) => ({
display: 'grid',
backgroundColor: theme.palette.neutral.light,
borderRadius: theme.shape.borderRadiusLarge,
padding: theme.spacing(0.5),
[theme.breakpoints.up('md')]: {
gridTemplateColumns: 'auto minmax(0, 1fr)',
},

'& dl': {
display: 'grid',
gridTemplateColumns: 'auto 1fr',
alignContent: 'start',
gap: theme.spacing(1),
padding: theme.spacing(2),
[theme.breakpoints.up('md')]: {
padding: theme.spacing(4),
},
},
}));

const StyledCodeSection = styled('div')(({ theme }) => ({
backgroundColor: 'white',
overflowX: 'auto',
padding: theme.spacing(2),
borderBottomLeftRadius: theme.shape.borderRadiusLarge,
borderBottomRightRadius: theme.shape.borderRadiusLarge,
[theme.breakpoints.up('md')]: {
padding: theme.spacing(4),
borderRadius: 0,
borderTopRightRadius: theme.shape.borderRadiusLarge,
borderBottomRightRadius: theme.shape.borderRadiusLarge,
},

'& code': {
wordWrap: 'break-word',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
lineHeight: 1.5,
fontSize: theme.fontSizes.smallBody,
},
}));

const EventCard = ({ entry }: IEventCardProps) => {
const { locationSettings } = useLocationSettings();

const createdAtFormatted = formatDateYMDHMS(
entry.createdAt,
locationSettings.locale
);

return (
<StyledContainerListItem>
<dl>
<StyledDefinitionTerm>Event id:</StyledDefinitionTerm>
<dd>{entry.id}</dd>
<StyledDefinitionTerm>Changed at:</StyledDefinitionTerm>
<dd>{createdAtFormatted}</dd>
<StyledDefinitionTerm>Event:</StyledDefinitionTerm>
<dd>{entry.type}</dd>
<StyledDefinitionTerm>Changed by:</StyledDefinitionTerm>
<dd title={entry.createdBy}>{entry.createdBy}</dd>
<ConditionallyRender
condition={Boolean(entry.project)}
show={
<>
<StyledDefinitionTerm>
Project:
</StyledDefinitionTerm>
<dd>
<Link to={`/projects/${entry.project}`}>
{entry.project}
</Link>
</dd>
</>
}
/>
<ConditionallyRender
condition={Boolean(entry.featureName)}
show={
<>
<StyledDefinitionTerm>
Feature:
</StyledDefinitionTerm>
<dd>
<Link
to={`/projects/${entry.project}/features/${entry.featureName}`}
>
{entry.featureName}
</Link>
</dd>
</>
}
/>
</dl>
<ConditionallyRender
condition={entry.data || entry.preData}
show={
<StyledCodeSection>
<StyledChangesTitle>Changes:</StyledChangesTitle>
<EventDiff entry={entry} />
</StyledCodeSection>
}
/>
</StyledContainerListItem>
);
};

export default EventCard;
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { diff } from 'deep-diff';
import { useStyles } from './EventDiff.styles';
import { IEvent } from 'interfaces/event';
import { useTheme } from '@mui/system';
import { CSSProperties } from 'react';

const DIFF_PREFIXES = {
const DIFF_PREFIXES: Record<string, string> = {
A: ' ',
E: ' ',
D: '-',
Expand All @@ -14,13 +15,13 @@ interface IEventDiffProps {
}

const EventDiff = ({ entry }: IEventDiffProps) => {
const { classes: styles } = useStyles();
const theme = useTheme();

const KLASSES = {
A: styles.blue, // array edited
E: styles.blue, // edited
D: styles.negative, // deleted
N: styles.positive, // added
const styles: Record<string, CSSProperties> = {
A: { color: theme.palette.code.edited }, // array edited
E: { color: theme.palette.code.edited }, // edited
D: { color: theme.palette.code.diffSub }, // deleted
N: { color: theme.palette.code.diffAdd }, // added
};

const diffs =
Expand All @@ -32,18 +33,14 @@ const EventDiff = ({ entry }: IEventDiffProps) => {
let change;
if (diff.lhs !== undefined) {
change = (
<div>
<div className={KLASSES.D}>
- {key}: {JSON.stringify(diff.lhs)}
</div>
<div style={styles.D}>
- {key}: {JSON.stringify(diff.lhs)}
</div>
);
} else if (diff.rhs !== undefined) {
change = (
<div>
<div className={KLASSES.N}>
+ {key}: {JSON.stringify(diff.rhs)}
</div>
<div style={styles.N}>
+ {key}: {JSON.stringify(diff.rhs)}
</div>
);
}
Expand All @@ -60,23 +57,19 @@ const EventDiff = ({ entry }: IEventDiffProps) => {
} else if (diff.lhs !== undefined && diff.rhs !== undefined) {
change = (
<div>
<div className={KLASSES.D}>
<div style={styles.D}>
- {key}: {JSON.stringify(diff.lhs)}
</div>
<div className={KLASSES.N}>
<div style={styles.N}>
+ {key}: {JSON.stringify(diff.rhs)}
</div>
</div>
);
} else {
// @ts-expect-error
const spadenClass = KLASSES[diff.kind];
// @ts-expect-error
const prefix = DIFF_PREFIXES[diff.kind];

change = (
<div className={spadenClass}>
{prefix} {key}: {JSON.stringify(diff.rhs || diff.item)}
<div style={styles[diff.kind]}>
{DIFF_PREFIXES[diff.kind]} {key}:{' '}
{JSON.stringify(diff.rhs || diff.item)}
</div>
);
}
Expand All @@ -91,16 +84,15 @@ const EventDiff = ({ entry }: IEventDiffProps) => {
} else {
// Just show the data if there is no diff yet.
const data = entry.data || entry.preData;
changes = (
<div className={entry.data ? KLASSES.N : KLASSES.D}>
changes = [
<div style={entry.data ? styles.N : styles.D}>
{JSON.stringify(data, null, 2)}
</div>
);
</div>,
];
}

return (
<pre style={{ overflowX: 'auto', overflowY: 'hidden' }} tabIndex={0}>
{/* @ts-expect-error */}
<code>{changes.length === 0 ? '(no changes)' : changes}</code>
</pre>
);
Expand Down

0 comments on commit dc9154d

Please sign in to comment.