mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Merge branch 'master' into feat/API-token-improvement
This commit is contained in:
		
						commit
						338c74e955
					
				@ -49,6 +49,7 @@
 | 
			
		||||
    "@types/react": "17.0.27",
 | 
			
		||||
    "@types/react-dom": "17.0.9",
 | 
			
		||||
    "@types/react-router-dom": "5.3.1",
 | 
			
		||||
    "@types/react-timeago": "^4.1.3",
 | 
			
		||||
    "@welldone-software/why-did-you-render": "6.2.1",
 | 
			
		||||
    "array-move": "3.0.1",
 | 
			
		||||
    "classnames": "2.3.1",
 | 
			
		||||
 | 
			
		||||
@ -3,20 +3,22 @@ import PropTypes from 'prop-types';
 | 
			
		||||
import classnames from 'classnames';
 | 
			
		||||
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import { Switch, IconButton, ListItem } from '@material-ui/core';
 | 
			
		||||
import { IconButton, ListItem } from '@material-ui/core';
 | 
			
		||||
import { Undo } from '@material-ui/icons';
 | 
			
		||||
 | 
			
		||||
import TimeAgo from 'react-timeago';
 | 
			
		||||
import Progress from '../../ProgressWheel';
 | 
			
		||||
import Status from '../../status-component';
 | 
			
		||||
import FeatureToggleListItemChip from './FeatureToggleListItemChip';
 | 
			
		||||
import ConditionallyRender from '../../../common/ConditionallyRender/ConditionallyRender';
 | 
			
		||||
 | 
			
		||||
import { UPDATE_FEATURE } from '../../../AccessProvider/permissions';
 | 
			
		||||
import { calc, styles as commonStyles } from '../../../common';
 | 
			
		||||
import { styles as commonStyles } from '../../../common';
 | 
			
		||||
 | 
			
		||||
import { useStyles } from './styles';
 | 
			
		||||
import { getTogglePath } from '../../../../utils/route-path-helpers';
 | 
			
		||||
import FeatureStatus from '../../FeatureView2/FeatureStatus/FeatureStatus';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const FeatureToggleListItem = ({
 | 
			
		||||
    feature,
 | 
			
		||||
@ -30,25 +32,9 @@ const FeatureToggleListItem = ({
 | 
			
		||||
}) => {
 | 
			
		||||
    const styles = useStyles();
 | 
			
		||||
 | 
			
		||||
    const { name, description, enabled, type, stale, createdAt, project } =
 | 
			
		||||
    const { name, description, type, stale, createdAt, project, lastSeenAt } =
 | 
			
		||||
        feature;
 | 
			
		||||
    const { showLastHour = false } = settings;
 | 
			
		||||
    const isStale = showLastHour
 | 
			
		||||
        ? metricsLastHour.isFallback
 | 
			
		||||
        : metricsLastMinute.isFallback;
 | 
			
		||||
    const percent =
 | 
			
		||||
        1 *
 | 
			
		||||
        (showLastHour
 | 
			
		||||
            ? calc(
 | 
			
		||||
                  metricsLastHour.yes,
 | 
			
		||||
                  metricsLastHour.yes + metricsLastHour.no,
 | 
			
		||||
                  0
 | 
			
		||||
              )
 | 
			
		||||
            : calc(
 | 
			
		||||
                  metricsLastMinute.yes,
 | 
			
		||||
                  metricsLastMinute.yes + metricsLastMinute.no,
 | 
			
		||||
                  0
 | 
			
		||||
              ));
 | 
			
		||||
   
 | 
			
		||||
    const featureUrl =
 | 
			
		||||
        toggleFeature === undefined
 | 
			
		||||
            ? `/projects/${feature.project}/archived/${name}/metrics`
 | 
			
		||||
@ -60,33 +46,7 @@ const FeatureToggleListItem = ({
 | 
			
		||||
            className={classnames(styles.listItem, rest.className)}
 | 
			
		||||
        >
 | 
			
		||||
            <span className={styles.listItemMetric}>
 | 
			
		||||
                <Progress
 | 
			
		||||
                    strokeWidth={15}
 | 
			
		||||
                    percentage={percent}
 | 
			
		||||
                    isFallback={isStale}
 | 
			
		||||
                />
 | 
			
		||||
            </span>
 | 
			
		||||
            <span className={styles.listItemToggle}>
 | 
			
		||||
                <ConditionallyRender
 | 
			
		||||
                    condition={hasAccess(UPDATE_FEATURE, project)}
 | 
			
		||||
                    show={
 | 
			
		||||
                        <Switch
 | 
			
		||||
                            disabled={toggleFeature === undefined}
 | 
			
		||||
                            title={`Toggle ${name}`}
 | 
			
		||||
                            key="left-actions"
 | 
			
		||||
                            onChange={() => toggleFeature(!enabled, name)}
 | 
			
		||||
                            checked={enabled}
 | 
			
		||||
                        />
 | 
			
		||||
                    }
 | 
			
		||||
                    elseShow={
 | 
			
		||||
                        <Switch
 | 
			
		||||
                            disabled
 | 
			
		||||
                            title={`Toggle ${name}`}
 | 
			
		||||
                            key="left-actions"
 | 
			
		||||
                            checked={enabled}
 | 
			
		||||
                        />
 | 
			
		||||
                    }
 | 
			
		||||
                />
 | 
			
		||||
                <FeatureStatus lastSeenAt={lastSeenAt} />
 | 
			
		||||
            </span>
 | 
			
		||||
            <span className={classnames(styles.listItemLink)}>
 | 
			
		||||
                <Link
 | 
			
		||||
 | 
			
		||||
@ -8,55 +8,33 @@ exports[`renders correctly with one feature 1`] = `
 | 
			
		||||
  <span
 | 
			
		||||
    className="makeStyles-listItemMetric-2"
 | 
			
		||||
  >
 | 
			
		||||
    <svg
 | 
			
		||||
      viewBox="0 0 24 24"
 | 
			
		||||
    >
 | 
			
		||||
      <path
 | 
			
		||||
        d="M17.3,18C19,16.5 20,14.4 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12C4,14.4 5,16.5 6.7,18C8.2,16.7 10,16 12,16C14,16 15.9,16.7 17.3,18M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M7,9A1,1 0 0,1 8,10A1,1 0 0,1 7,11A1,1 0 0,1 6,10A1,1 0 0,1 7,9M10,6A1,1 0 0,1 11,7A1,1 0 0,1 10,8A1,1 0 0,1 9,7A1,1 0 0,1 10,6M17,9A1,1 0 0,1 18,10A1,1 0 0,1 17,11A1,1 0 0,1 16,10A1,1 0 0,1 17,9M14.4,6.1C14.9,6.3 15.1,6.9 15,7.4L13.6,10.8C13.8,11.1 14,11.5 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12C10,11 10.7,10.1 11.7,10L13.1,6.7C13.3,6.1 13.9,5.9 14.4,6.1Z"
 | 
			
		||||
        fill="#E0E0E0"
 | 
			
		||||
      />
 | 
			
		||||
    </svg>
 | 
			
		||||
  </span>
 | 
			
		||||
  <span>
 | 
			
		||||
    <span
 | 
			
		||||
      className="MuiSwitch-root"
 | 
			
		||||
    <div
 | 
			
		||||
      aria-describedby={null}
 | 
			
		||||
      className="makeStyles-container-6"
 | 
			
		||||
      onBlur={[Function]}
 | 
			
		||||
      onFocus={[Function]}
 | 
			
		||||
      onMouseLeave={[Function]}
 | 
			
		||||
      onMouseOver={[Function]}
 | 
			
		||||
      onTouchEnd={[Function]}
 | 
			
		||||
      onTouchStart={[Function]}
 | 
			
		||||
      style={
 | 
			
		||||
        Object {
 | 
			
		||||
          "background": "#EDF0F1",
 | 
			
		||||
          "fontSize": "0.8rem",
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      title="No usage reported"
 | 
			
		||||
    >
 | 
			
		||||
      <span
 | 
			
		||||
        aria-disabled={false}
 | 
			
		||||
        className="MuiButtonBase-root MuiIconButton-root PrivateSwitchBase-root-6 MuiSwitch-switchBase MuiSwitch-colorSecondary"
 | 
			
		||||
        onBlur={[Function]}
 | 
			
		||||
        onDragLeave={[Function]}
 | 
			
		||||
        onFocus={[Function]}
 | 
			
		||||
        onKeyDown={[Function]}
 | 
			
		||||
        onKeyUp={[Function]}
 | 
			
		||||
        onMouseDown={[Function]}
 | 
			
		||||
        onMouseLeave={[Function]}
 | 
			
		||||
        onMouseUp={[Function]}
 | 
			
		||||
        onTouchEnd={[Function]}
 | 
			
		||||
        onTouchMove={[Function]}
 | 
			
		||||
        onTouchStart={[Function]}
 | 
			
		||||
        tabIndex={null}
 | 
			
		||||
        title="Toggle Another"
 | 
			
		||||
        style={
 | 
			
		||||
          Object {
 | 
			
		||||
            "fontSize": "1.4rem",
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        <span
 | 
			
		||||
          className="MuiIconButton-label"
 | 
			
		||||
        >
 | 
			
		||||
          <input
 | 
			
		||||
            checked={false}
 | 
			
		||||
            className="PrivateSwitchBase-input-9 MuiSwitch-input"
 | 
			
		||||
            disabled={false}
 | 
			
		||||
            onChange={[Function]}
 | 
			
		||||
            type="checkbox"
 | 
			
		||||
          />
 | 
			
		||||
          <span
 | 
			
		||||
            className="MuiSwitch-thumb"
 | 
			
		||||
          />
 | 
			
		||||
        </span>
 | 
			
		||||
        ⊕
 | 
			
		||||
      </span>
 | 
			
		||||
      <span
 | 
			
		||||
        className="MuiSwitch-track"
 | 
			
		||||
      />
 | 
			
		||||
    </span>
 | 
			
		||||
    </div>
 | 
			
		||||
  </span>
 | 
			
		||||
  <span
 | 
			
		||||
    className="makeStyles-listItemLink-4"
 | 
			
		||||
@ -105,58 +83,33 @@ exports[`renders correctly with one feature without permission 1`] = `
 | 
			
		||||
  <span
 | 
			
		||||
    className="makeStyles-listItemMetric-2"
 | 
			
		||||
  >
 | 
			
		||||
    <svg
 | 
			
		||||
      viewBox="0 0 24 24"
 | 
			
		||||
    >
 | 
			
		||||
      <path
 | 
			
		||||
        d="M17.3,18C19,16.5 20,14.4 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12C4,14.4 5,16.5 6.7,18C8.2,16.7 10,16 12,16C14,16 15.9,16.7 17.3,18M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M7,9A1,1 0 0,1 8,10A1,1 0 0,1 7,11A1,1 0 0,1 6,10A1,1 0 0,1 7,9M10,6A1,1 0 0,1 11,7A1,1 0 0,1 10,8A1,1 0 0,1 9,7A1,1 0 0,1 10,6M17,9A1,1 0 0,1 18,10A1,1 0 0,1 17,11A1,1 0 0,1 16,10A1,1 0 0,1 17,9M14.4,6.1C14.9,6.3 15.1,6.9 15,7.4L13.6,10.8C13.8,11.1 14,11.5 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12C10,11 10.7,10.1 11.7,10L13.1,6.7C13.3,6.1 13.9,5.9 14.4,6.1Z"
 | 
			
		||||
        fill="#E0E0E0"
 | 
			
		||||
      />
 | 
			
		||||
    </svg>
 | 
			
		||||
  </span>
 | 
			
		||||
  <span>
 | 
			
		||||
    <span
 | 
			
		||||
      className="MuiSwitch-root"
 | 
			
		||||
    <div
 | 
			
		||||
      aria-describedby={null}
 | 
			
		||||
      className="makeStyles-container-6"
 | 
			
		||||
      onBlur={[Function]}
 | 
			
		||||
      onFocus={[Function]}
 | 
			
		||||
      onMouseLeave={[Function]}
 | 
			
		||||
      onMouseOver={[Function]}
 | 
			
		||||
      onTouchEnd={[Function]}
 | 
			
		||||
      onTouchStart={[Function]}
 | 
			
		||||
      style={
 | 
			
		||||
        Object {
 | 
			
		||||
          "background": "#EDF0F1",
 | 
			
		||||
          "fontSize": "0.8rem",
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      title="No usage reported"
 | 
			
		||||
    >
 | 
			
		||||
      <span
 | 
			
		||||
        aria-disabled={false}
 | 
			
		||||
        className="MuiButtonBase-root MuiIconButton-root PrivateSwitchBase-root-6 MuiSwitch-switchBase MuiSwitch-colorSecondary"
 | 
			
		||||
        onBlur={[Function]}
 | 
			
		||||
        onDragLeave={[Function]}
 | 
			
		||||
        onFocus={[Function]}
 | 
			
		||||
        onKeyDown={[Function]}
 | 
			
		||||
        onKeyUp={[Function]}
 | 
			
		||||
        onMouseDown={[Function]}
 | 
			
		||||
        onMouseLeave={[Function]}
 | 
			
		||||
        onMouseUp={[Function]}
 | 
			
		||||
        onTouchEnd={[Function]}
 | 
			
		||||
        onTouchMove={[Function]}
 | 
			
		||||
        onTouchStart={[Function]}
 | 
			
		||||
        tabIndex={null}
 | 
			
		||||
        title="Toggle Another"
 | 
			
		||||
        style={
 | 
			
		||||
          Object {
 | 
			
		||||
            "fontSize": "1.4rem",
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        <span
 | 
			
		||||
          className="MuiIconButton-label"
 | 
			
		||||
        >
 | 
			
		||||
          <input
 | 
			
		||||
            checked={false}
 | 
			
		||||
            className="PrivateSwitchBase-input-9 MuiSwitch-input"
 | 
			
		||||
            disabled={false}
 | 
			
		||||
            onChange={[Function]}
 | 
			
		||||
            type="checkbox"
 | 
			
		||||
          />
 | 
			
		||||
          <span
 | 
			
		||||
            className="MuiSwitch-thumb"
 | 
			
		||||
          />
 | 
			
		||||
        </span>
 | 
			
		||||
        <span
 | 
			
		||||
          className="MuiTouchRipple-root"
 | 
			
		||||
        />
 | 
			
		||||
        ⊕
 | 
			
		||||
      </span>
 | 
			
		||||
      <span
 | 
			
		||||
        className="MuiSwitch-track"
 | 
			
		||||
      />
 | 
			
		||||
    </span>
 | 
			
		||||
    </div>
 | 
			
		||||
  </span>
 | 
			
		||||
  <span
 | 
			
		||||
    className="makeStyles-listItemLink-4"
 | 
			
		||||
 | 
			
		||||
@ -19,20 +19,24 @@ export const useStyles = makeStyles(theme => ({
 | 
			
		||||
            display: 'none',
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    tableCellStatus: {
 | 
			
		||||
        width: '50px',
 | 
			
		||||
    },
 | 
			
		||||
    tableCellName: {
 | 
			
		||||
        width: '250px',
 | 
			
		||||
        display: 'flex',
 | 
			
		||||
    },
 | 
			
		||||
    tableCellEnv: {
 | 
			
		||||
        width: '20px',
 | 
			
		||||
    },
 | 
			
		||||
    tableCellType: {
 | 
			
		||||
        display: 'flex',
 | 
			
		||||
        width: '32px',
 | 
			
		||||
        alignItems: 'center',
 | 
			
		||||
        [theme.breakpoints.down('sm')]: {
 | 
			
		||||
            display: 'none',
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    icon: {
 | 
			
		||||
        marginRight: '0.3rem',
 | 
			
		||||
        color: theme.palette.grey[600],
 | 
			
		||||
    },
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,10 @@ import FeatureToggleListNewItem from './FeatureToggleListNewItem/FeatureToggleLi
 | 
			
		||||
import usePagination from '../../../hooks/usePagination';
 | 
			
		||||
 | 
			
		||||
import loadingFeatures from './FeatureToggleListNewItem/loadingFeatures';
 | 
			
		||||
import { IFeatureToggleListItem } from '../../../interfaces/featureToggle';
 | 
			
		||||
import {
 | 
			
		||||
    IFeatureToggle,
 | 
			
		||||
    IFeatureToggleListItem,
 | 
			
		||||
} from '../../../interfaces/featureToggle';
 | 
			
		||||
import PaginateUI from '../../common/PaginateUI/PaginateUI';
 | 
			
		||||
interface IFeatureToggleListNewProps {
 | 
			
		||||
    features: IFeatureToggleListItem[];
 | 
			
		||||
@ -26,7 +29,7 @@ const FeatureToggleListNew = ({
 | 
			
		||||
}: IFeatureToggleListNewProps) => {
 | 
			
		||||
    const styles = useStyles();
 | 
			
		||||
    const { page, pages, nextPage, prevPage, setPageIndex, pageIndex } =
 | 
			
		||||
        usePagination(features, 9);
 | 
			
		||||
        usePagination(features, 50);
 | 
			
		||||
 | 
			
		||||
    const getEnvironments = () => {
 | 
			
		||||
        if (features.length > 0) {
 | 
			
		||||
@ -57,7 +60,7 @@ const FeatureToggleListNew = ({
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return page.map((feature: IFeatureToggleListItem) => {
 | 
			
		||||
        return page.map((feature: IFeatureToggle) => {
 | 
			
		||||
            return (
 | 
			
		||||
                <FeatureToggleListNewItem
 | 
			
		||||
                    key={feature.name}
 | 
			
		||||
@ -65,6 +68,7 @@ const FeatureToggleListNew = ({
 | 
			
		||||
                    type={feature.type}
 | 
			
		||||
                    environments={feature.environments}
 | 
			
		||||
                    projectId={projectId}
 | 
			
		||||
                    lastSeenAt={feature.lastSeenAt}
 | 
			
		||||
                />
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
@ -78,12 +82,12 @@ const FeatureToggleListNew = ({
 | 
			
		||||
                        <TableCell
 | 
			
		||||
                            className={classnames(
 | 
			
		||||
                                styles.tableCell,
 | 
			
		||||
                                styles.tableCellName,
 | 
			
		||||
                                styles.tableCellStatus,
 | 
			
		||||
                                styles.tableCellHeader
 | 
			
		||||
                            )}
 | 
			
		||||
                            align="left"
 | 
			
		||||
                        >
 | 
			
		||||
                            <span data-loading>Name</span>
 | 
			
		||||
                            <span data-loading>Status</span>
 | 
			
		||||
                        </TableCell>
 | 
			
		||||
                        <TableCell
 | 
			
		||||
                            className={classnames(
 | 
			
		||||
@ -91,10 +95,20 @@ const FeatureToggleListNew = ({
 | 
			
		||||
                                styles.tableCellHeader,
 | 
			
		||||
                                styles.typeHeader
 | 
			
		||||
                            )}
 | 
			
		||||
                            align="left"
 | 
			
		||||
                            align="center"
 | 
			
		||||
                        >
 | 
			
		||||
                            <span data-loading>Type</span>
 | 
			
		||||
                        </TableCell>
 | 
			
		||||
                        <TableCell
 | 
			
		||||
                            className={classnames(
 | 
			
		||||
                                styles.tableCell,
 | 
			
		||||
                                styles.tableCellName,
 | 
			
		||||
                                styles.tableCellHeader
 | 
			
		||||
                            )}
 | 
			
		||||
                            align="left"
 | 
			
		||||
                        >
 | 
			
		||||
                            <span data-loading>Name</span>
 | 
			
		||||
                        </TableCell>
 | 
			
		||||
                        {getEnvironments().map((env: any) => {
 | 
			
		||||
                            return (
 | 
			
		||||
                                <TableCell
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ import {
 | 
			
		||||
    Switch,
 | 
			
		||||
    TableCell,
 | 
			
		||||
    TableRow,
 | 
			
		||||
    Tooltip,
 | 
			
		||||
    useMediaQuery,
 | 
			
		||||
    useTheme,
 | 
			
		||||
} from '@material-ui/core';
 | 
			
		||||
@ -16,16 +17,19 @@ import useToast from '../../../../hooks/useToast';
 | 
			
		||||
import { getTogglePath } from '../../../../utils/route-path-helpers';
 | 
			
		||||
import { SyntheticEvent } from 'react-router/node_modules/@types/react';
 | 
			
		||||
import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
 | 
			
		||||
import FeatureStatus from '../../FeatureView2/FeatureStatus/FeatureStatus';
 | 
			
		||||
 | 
			
		||||
interface IFeatureToggleListNewItemProps {
 | 
			
		||||
    name: string;
 | 
			
		||||
    type: string;
 | 
			
		||||
    environments: IEnvironments[];
 | 
			
		||||
    environments: IFeatureEnvironment[];
 | 
			
		||||
    projectId: string;
 | 
			
		||||
    lastSeenAt?: Date;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FeatureToggleListNewItem = ({
 | 
			
		||||
    name,
 | 
			
		||||
    lastSeenAt,
 | 
			
		||||
    type,
 | 
			
		||||
    environments,
 | 
			
		||||
    projectId,
 | 
			
		||||
@ -35,7 +39,7 @@ const FeatureToggleListNewItem = ({
 | 
			
		||||
    const smallScreen = useMediaQuery(theme.breakpoints.down('sm'));
 | 
			
		||||
    const { toggleFeatureByEnvironment } = useToggleFeatureByEnv(
 | 
			
		||||
        projectId,
 | 
			
		||||
        name
 | 
			
		||||
        name,
 | 
			
		||||
    );
 | 
			
		||||
    const { uiConfig } = useUiConfig();
 | 
			
		||||
    
 | 
			
		||||
@ -74,22 +78,25 @@ const FeatureToggleListNewItem = ({
 | 
			
		||||
        <>
 | 
			
		||||
            <TableRow className={styles.tableRow}>
 | 
			
		||||
                <TableCell className={styles.tableCell} align="left" onClick={onClick}>
 | 
			
		||||
                    <span data-loading>{name}</span>
 | 
			
		||||
                    <FeatureStatus lastSeenAt={lastSeenAt} />
 | 
			
		||||
                </TableCell>
 | 
			
		||||
                <ConditionallyRender
 | 
			
		||||
                    condition={!smallScreen}
 | 
			
		||||
                    show={
 | 
			
		||||
                        <TableCell className={styles.tableCell} align="left" onClick={onClick}>
 | 
			
		||||
                            <div className={styles.tableCellType}>
 | 
			
		||||
                        <TableCell className={styles.tableCell} align="center" onClick={onClick}>
 | 
			
		||||
                            <Tooltip arrow placement="right" title={type}>
 | 
			
		||||
                                <IconComponent
 | 
			
		||||
                                    data-loading
 | 
			
		||||
                                    className={styles.icon}
 | 
			
		||||
                                />{' '}
 | 
			
		||||
                                <span data-loading>{type}</span>
 | 
			
		||||
                            </div>
 | 
			
		||||
                                />
 | 
			
		||||
                            </Tooltip>
 | 
			
		||||
                        </TableCell>
 | 
			
		||||
                    }
 | 
			
		||||
                />
 | 
			
		||||
                <TableCell className={styles.tableCell} align="left" onClick={onClick}>
 | 
			
		||||
                    <span data-loading>{name}</span>
 | 
			
		||||
                </TableCell>
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                {environments.map((env: IEnvironments) => {
 | 
			
		||||
                    return (
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,16 @@
 | 
			
		||||
import { makeStyles } from '@material-ui/core/styles';
 | 
			
		||||
 | 
			
		||||
export const useStyles = makeStyles(theme => ({
 | 
			
		||||
    container: {
 | 
			
		||||
        width: '42px',
 | 
			
		||||
        height: '42px',
 | 
			
		||||
        fontSize: '0.7em',
 | 
			
		||||
        background: 'gray',
 | 
			
		||||
        borderRadius: '3px',
 | 
			
		||||
        textAlign: 'center',
 | 
			
		||||
        display: 'flex',
 | 
			
		||||
        alignItems: 'center',
 | 
			
		||||
        justifyContent: 'center',
 | 
			
		||||
        padding: '13px 10px',
 | 
			
		||||
    },
 | 
			
		||||
}));
 | 
			
		||||
@ -0,0 +1,105 @@
 | 
			
		||||
import { useStyles } from './FeatureStatus.styles';
 | 
			
		||||
import TimeAgo from 'react-timeago';
 | 
			
		||||
import ConditionallyRender from '../../../common/ConditionallyRender';
 | 
			
		||||
import { Tooltip } from '@material-ui/core';
 | 
			
		||||
 | 
			
		||||
function generateUnit(unit?: string): string {
 | 
			
		||||
    switch (unit) {
 | 
			
		||||
        case 'second':
 | 
			
		||||
            return 's';
 | 
			
		||||
        case 'minute':
 | 
			
		||||
            return 'm';
 | 
			
		||||
        case 'hour':
 | 
			
		||||
            return 'h';
 | 
			
		||||
        case 'day':
 | 
			
		||||
            return 'D';
 | 
			
		||||
        case 'week':
 | 
			
		||||
            return 'W';
 | 
			
		||||
        case 'month':
 | 
			
		||||
            return 'M';
 | 
			
		||||
        case 'year':
 | 
			
		||||
            return 'Y';
 | 
			
		||||
        default:
 | 
			
		||||
            return '';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getColor(unit?: string): string {
 | 
			
		||||
    switch (unit) {
 | 
			
		||||
        case 'second':
 | 
			
		||||
            return '#98E3AF';
 | 
			
		||||
        case 'minute':
 | 
			
		||||
            return '#98E3AF';
 | 
			
		||||
        case 'hour':
 | 
			
		||||
            return '#98E3AF';
 | 
			
		||||
        case 'day':
 | 
			
		||||
            return '#98E3AF';
 | 
			
		||||
        case 'week':
 | 
			
		||||
            return '#ECD875';
 | 
			
		||||
        case 'month':
 | 
			
		||||
            return '#F5A69A';
 | 
			
		||||
        case 'year':
 | 
			
		||||
            return '#F5A69A';
 | 
			
		||||
        default:
 | 
			
		||||
            return '#EDF0F1';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface FeatureStatusProps {
 | 
			
		||||
    lastSeenAt?: Date;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FeatureStatus = ({ lastSeenAt }: FeatureStatusProps) => {
 | 
			
		||||
    const styles = useStyles();
 | 
			
		||||
 | 
			
		||||
    const Wrapper = (
 | 
			
		||||
        props: React.PropsWithChildren<{ color: string; toolTip: string }>
 | 
			
		||||
    ) => {
 | 
			
		||||
        return (
 | 
			
		||||
            <Tooltip title={props.toolTip} arrow placement="left">
 | 
			
		||||
                <div
 | 
			
		||||
                    className={styles.container}
 | 
			
		||||
                    style={{ background: props.color, fontSize: '0.8rem' }}
 | 
			
		||||
                >
 | 
			
		||||
                    {props.children}
 | 
			
		||||
                </div>
 | 
			
		||||
            </Tooltip>
 | 
			
		||||
        );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <ConditionallyRender
 | 
			
		||||
            condition={!!lastSeenAt}
 | 
			
		||||
            show={
 | 
			
		||||
                //@ts-ignore
 | 
			
		||||
                <TimeAgo
 | 
			
		||||
                    date={lastSeenAt}
 | 
			
		||||
                    title=""
 | 
			
		||||
                    live={false}
 | 
			
		||||
                    formatter={(
 | 
			
		||||
                        value: number,
 | 
			
		||||
                        unit: string,
 | 
			
		||||
                        suffix: string
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        return (
 | 
			
		||||
                            <Wrapper
 | 
			
		||||
                                toolTip={`Last usage reported ${value} ${unit} ${suffix}`}
 | 
			
		||||
                                color={getColor(unit)}
 | 
			
		||||
                            >
 | 
			
		||||
                                {value}
 | 
			
		||||
                                {generateUnit(unit)}
 | 
			
		||||
                            </Wrapper>
 | 
			
		||||
                        );
 | 
			
		||||
                    }}
 | 
			
		||||
                />
 | 
			
		||||
            }
 | 
			
		||||
            elseShow={
 | 
			
		||||
                <Wrapper toolTip="No usage reported" color={getColor()}>
 | 
			
		||||
                    <span style={{ fontSize: '1.4rem' }}>⊕</span>
 | 
			
		||||
                </Wrapper>
 | 
			
		||||
            }
 | 
			
		||||
        />
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default FeatureStatus;
 | 
			
		||||
@ -8,6 +8,7 @@ export const useStyles = makeStyles(theme => ({
 | 
			
		||||
            flexDirection: 'column',
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    projectToggles: { width: '100%', minHeight: '100%' },
 | 
			
		||||
    header: {
 | 
			
		||||
        backgroundColor: '#fff',
 | 
			
		||||
        borderRadius: '10px',
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,11 @@ import { makeStyles } from '@material-ui/core/styles';
 | 
			
		||||
export const useStyles = makeStyles(theme => ({
 | 
			
		||||
    container: {
 | 
			
		||||
        boxShadow: 'none',
 | 
			
		||||
        marginLeft: '2rem',
 | 
			
		||||
        width: '100%',
 | 
			
		||||
        marginLeft: '1rem',
 | 
			
		||||
        minHeight: '100%',
 | 
			
		||||
        width: 'calc(100% - 1rem)',
 | 
			
		||||
        position: 'relative',
 | 
			
		||||
        paddingBottom: '4rem',
 | 
			
		||||
        [theme.breakpoints.down('sm')]: {
 | 
			
		||||
            marginLeft: '0',
 | 
			
		||||
            paddingBottom: '4rem',
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,11 @@ export const useStyles = makeStyles(theme => ({
 | 
			
		||||
            marginBottom: '1rem',
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    percentageContainer: {
 | 
			
		||||
        display: 'flex',
 | 
			
		||||
        justifyContent: 'center',
 | 
			
		||||
        margin: '1rem 0',
 | 
			
		||||
    },
 | 
			
		||||
    projectIcon: {
 | 
			
		||||
        margin: '2rem 0',
 | 
			
		||||
        [theme.breakpoints.down('sm')]: {
 | 
			
		||||
@ -35,7 +40,7 @@ export const useStyles = makeStyles(theme => ({
 | 
			
		||||
    infoSection: {
 | 
			
		||||
        margin: '0',
 | 
			
		||||
        textAlign: 'center',
 | 
			
		||||
        marginBottom: '1.5rem',
 | 
			
		||||
        marginBottom: '1rem',
 | 
			
		||||
        backgroundColor: '#fff',
 | 
			
		||||
        borderRadius: '10px',
 | 
			
		||||
        width: '100%',
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,9 @@ import { Link } from 'react-router-dom';
 | 
			
		||||
import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
 | 
			
		||||
import classnames from 'classnames';
 | 
			
		||||
 | 
			
		||||
import { ReactComponent as ProjectIcon } from '../../../../assets/icons/projectIcon.svg';
 | 
			
		||||
import { useCommonStyles } from '../../../../common.styles';
 | 
			
		||||
import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
 | 
			
		||||
import PercentageCircle from '../../../common/PercentageCircle/PercentageCircle';
 | 
			
		||||
 | 
			
		||||
interface IProjectInfoProps {
 | 
			
		||||
    id: string;
 | 
			
		||||
@ -34,8 +34,8 @@ const ProjectInfo = ({
 | 
			
		||||
        <aside>
 | 
			
		||||
            <div className={styles.projectInfo}>
 | 
			
		||||
                <div className={styles.infoSection}>
 | 
			
		||||
                    <div data-loading>
 | 
			
		||||
                        <ProjectIcon className={styles.projectIcon} />
 | 
			
		||||
                    <div data-loading className={styles.percentageContainer}>
 | 
			
		||||
                        <PercentageCircle percentage={health} />
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <p className={styles.subtitle} data-loading>
 | 
			
		||||
                        Overall health rating
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ interface ProjectOverviewProps {
 | 
			
		||||
    projectId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ProjectOverview = ({projectId}: ProjectOverviewProps) => {
 | 
			
		||||
const ProjectOverview = ({ projectId }: ProjectOverviewProps) => {
 | 
			
		||||
    const { project, loading } = useProject(projectId);
 | 
			
		||||
    const { members, features, health } = project;
 | 
			
		||||
    const styles = useStyles();
 | 
			
		||||
@ -21,9 +21,13 @@ const ProjectOverview = ({projectId}: ProjectOverviewProps) => {
 | 
			
		||||
                    health={health}
 | 
			
		||||
                    featureCount={features?.length}
 | 
			
		||||
                />
 | 
			
		||||
                <ProjectFeatureToggles features={features} loading={loading} />
 | 
			
		||||
                <div className={styles.projectToggles}>
 | 
			
		||||
                    <ProjectFeatureToggles
 | 
			
		||||
                        features={features}
 | 
			
		||||
                        loading={loading}
 | 
			
		||||
                    />
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,6 @@ export interface IFeatureToggleListItem {
 | 
			
		||||
 | 
			
		||||
export interface IEnvironments {
 | 
			
		||||
    name: string;
 | 
			
		||||
    displayName: string;
 | 
			
		||||
    enabled: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,7 +15,7 @@ export interface IFeatureToggle {
 | 
			
		||||
    stale: boolean;
 | 
			
		||||
    archived: boolean;
 | 
			
		||||
    createdAt: string;
 | 
			
		||||
    lastSeenAt: string;
 | 
			
		||||
    lastSeenAt: Date;
 | 
			
		||||
    description: string;
 | 
			
		||||
    environments: IFeatureEnvironment[];
 | 
			
		||||
    name: string;
 | 
			
		||||
 | 
			
		||||
@ -2176,6 +2176,13 @@
 | 
			
		||||
    "@types/history" "*"
 | 
			
		||||
    "@types/react" "*"
 | 
			
		||||
 | 
			
		||||
"@types/react-timeago@^4.1.3":
 | 
			
		||||
  version "4.1.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@types/react-timeago/-/react-timeago-4.1.3.tgz#957baaa9f8ea98457ee63b6a57b57a616066ba35"
 | 
			
		||||
  integrity sha512-XaaMBzuXLw7lxPPDs/fenlohcf3NDqM5qP4oOL/Meu+Hb1QChW4Igw/SruS1llEqch18RQB3wDTIwvqq4nivvw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@types/react" "*"
 | 
			
		||||
 | 
			
		||||
"@types/react-transition-group@^4.2.0":
 | 
			
		||||
  version "4.4.1"
 | 
			
		||||
  resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user