* Fixed links to ChaosHub, added textButton component

Signed-off-by: Vansh Bhatia <vansh@chaosnative.com>

* Added workflow status Icons to homePage

Signed-off-by: Vansh Bhatia <vansh@chaosnative.com>

* moved from links to TextButton in homePage

Signed-off-by: Vansh Bhatia <vansh@chaosnative.com>

* removed unused redux Tab state, added pagination bugFix

Signed-off-by: Vansh Bhatia <vansh@chaosnative.com>

* Review changes

Signed-off-by: Vansh Bhatia <vansh@chaosnative.com>

* Loader UX issue fixed

Signed-off-by: Vansh Bhatia <vansh@chaosnative.com>
This commit is contained in:
Vansh Bhatia 2021-06-23 13:17:10 +05:30 committed by GitHub
parent 91ae3a3134
commit 08204190ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 86 additions and 126 deletions

View File

@ -1,6 +1,6 @@
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import { Avatar, IconButton, Popover, Typography } from '@material-ui/core'; import { Avatar, IconButton, Popover, Typography } from '@material-ui/core';
import { ButtonFilled, ButtonOutlined } from 'litmus-ui'; import { ButtonFilled, TextButton } from 'litmus-ui';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@ -121,8 +121,9 @@ const ProfileDropdown: React.FC = () => {
</ButtonFilled> </ButtonFilled>
</div> </div>
<ButtonOutlined <TextButton
title="Edit your profile" title="Edit your profile"
variant="highlight"
disabled={projectRole !== 'Owner'} disabled={projectRole !== 'Owner'}
onClick={() => { onClick={() => {
tabs.changeSettingsTabs(0); tabs.changeSettingsTabs(0);
@ -133,7 +134,7 @@ const ProfileDropdown: React.FC = () => {
}} }}
> >
{t('header.profileDropdown.editProfile')} {t('header.profileDropdown.editProfile')}
</ButtonOutlined> </TextButton>
</div> </div>
</div> </div>
</Popover> </Popover>

View File

@ -22,7 +22,7 @@ const Loader: React.FC<LoaderProps> = ({ size, message }) => {
const classes = useStyles(); const classes = useStyles();
const defaultSize = 40; const defaultSize = 40;
return ( return (
<> <div>
<Center> <Center>
<CircularProgress <CircularProgress
className={classes.spinner} className={classes.spinner}
@ -30,7 +30,7 @@ const Loader: React.FC<LoaderProps> = ({ size, message }) => {
/> />
</Center> </Center>
<Typography>{message}</Typography> <Typography>{message}</Typography>
</> </div>
); );
}; };

View File

@ -40,16 +40,13 @@ const useStyles = makeStyles((theme) => ({
marginRight: theme.spacing(1.5), marginRight: theme.spacing(1.5),
}, },
'& a': {
textDecoration: 'none',
marginLeft: theme.spacing(1.875),
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
'& p': { '& p': {
fontWeight: 500, fontWeight: 500,
fontSize: '1rem', fontSize: '1rem',
}, },
'& button:last-child': {
marginLeft: theme.spacing(2.5),
}, },
}, },
})); }));

View File

@ -8,12 +8,6 @@ const useStyles = makeStyles((theme) => ({
containerHeading: { containerHeading: {
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
'& a': {
textDecoration: 'none',
color: theme.palette.primary.main,
marginRight: theme.spacing(4.5),
},
}, },
heading: { heading: {
flexGrow: 1, flexGrow: 1,

View File

@ -15,6 +15,7 @@ import * as AnalyticsActions from '../../redux/actions/analytics';
import { history } from '../../redux/configureStore'; import { history } from '../../redux/configureStore';
import { getToken, getUserId, getUserRole } from '../../utils/auth'; import { getToken, getUserId, getUserRole } from '../../utils/auth';
import { getProjectID, getProjectRole } from '../../utils/getSearchParams'; import { getProjectID, getProjectRole } from '../../utils/getSearchParams';
import Center from '../layouts/Center';
const ErrorPage = lazy(() => import('../../pages/ErrorPage')); const ErrorPage = lazy(() => import('../../pages/ErrorPage'));
const Workflows = lazy(() => import('../../pages/Workflows')); const Workflows = lazy(() => import('../../pages/Workflows'));
@ -257,7 +258,9 @@ function App() {
<Suspense <Suspense
fallback={ fallback={
<div style={{ height: '100vh' }}> <div style={{ height: '100vh' }}>
<Center>
<Loader /> <Loader />
</Center>
</div> </div>
} }
> >

View File

@ -3,7 +3,6 @@ export interface TabState {
settings: number; settings: number;
node: number; node: number;
analytics: number; analytics: number;
overviewDashboard: number;
} }
export enum TabActions { export enum TabActions {
@ -11,7 +10,6 @@ export enum TabActions {
CHANGE_SETTINGS_TAB = 'CHANGE_SETTINGS_TAB', CHANGE_SETTINGS_TAB = 'CHANGE_SETTINGS_TAB',
CHANGE_WORKFLOW_DETAILS_TAB = 'CHANGE_WORKFLOW_DETAILS_TAB', CHANGE_WORKFLOW_DETAILS_TAB = 'CHANGE_WORKFLOW_DETAILS_TAB',
CHANGE_ANALYTICS_DASHBOARD_TAB = 'CHANGE_ANALYTICS_DASHBOARD_TAB', CHANGE_ANALYTICS_DASHBOARD_TAB = 'CHANGE_ANALYTICS_DASHBOARD_TAB',
CHANGE_OVERVIEW_DASHBOARD_TAB = 'CHANGE_OVERVIEW_DASHBOARD_TAB',
} }
interface TabActionType<T, P> { interface TabActionType<T, P> {
@ -23,5 +21,4 @@ export type TabAction =
| TabActionType<typeof TabActions.CHANGE_WORKFLOWS_TAB, number> | TabActionType<typeof TabActions.CHANGE_WORKFLOWS_TAB, number>
| TabActionType<typeof TabActions.CHANGE_SETTINGS_TAB, number> | TabActionType<typeof TabActions.CHANGE_SETTINGS_TAB, number>
| TabActionType<typeof TabActions.CHANGE_WORKFLOW_DETAILS_TAB, number> | TabActionType<typeof TabActions.CHANGE_WORKFLOW_DETAILS_TAB, number>
| TabActionType<typeof TabActions.CHANGE_ANALYTICS_DASHBOARD_TAB, number> | TabActionType<typeof TabActions.CHANGE_ANALYTICS_DASHBOARD_TAB, number>;
| TabActionType<typeof TabActions.CHANGE_OVERVIEW_DASHBOARD_TAB, number>;

View File

@ -27,10 +27,3 @@ export function changeAnalyticsDashboardTabs(tabNumber: number): TabAction {
payload: tabNumber, payload: tabNumber,
}; };
} }
export function changeOverviewDashboardTabs(tabNumber: number): TabAction {
return {
type: TabActions.CHANGE_OVERVIEW_DASHBOARD_TAB,
payload: tabNumber,
};
}

View File

@ -7,7 +7,6 @@ const initialState: TabState = {
settings: 0, settings: 0,
node: 0, node: 0,
analytics: 0, analytics: 0,
overviewDashboard: 0,
}; };
export const tabNumber = createReducer<TabState>(initialState, { export const tabNumber = createReducer<TabState>(initialState, {
@ -38,15 +37,6 @@ export const tabNumber = createReducer<TabState>(initialState, {
analytics: action.payload, analytics: action.payload,
}; };
}, },
[TabActions.CHANGE_OVERVIEW_DASHBOARD_TAB](
state: TabState,
action: TabAction
) {
return {
...state,
overviewDashboard: action.payload,
};
},
}); });
export default tabNumber; export default tabNumber;

View File

@ -8,6 +8,13 @@ import {
getProjectID, getProjectID,
getProjectRole, getProjectRole,
} from '../../../../utils/getSearchParams'; } from '../../../../utils/getSearchParams';
import {
FAILED,
NOTAVAILABLE,
PENDING,
RUNNING,
SUCCEEDED,
} from '../../../WorkflowDetails/workflowConstants';
import useStyles from './styles'; import useStyles from './styles';
interface WorkflowDashboardCardProps { interface WorkflowDashboardCardProps {
@ -24,15 +31,15 @@ const WorkflowDashboardCard: React.FC<WorkflowDashboardCardProps> = ({
function getStatusVariant(phase: string) { function getStatusVariant(phase: string) {
switch (phase) { switch (phase) {
case 'Running': case RUNNING:
return 'status-running.svg'; return 'status-running.svg';
case 'Succeeded': case SUCCEEDED:
return 'status-success.svg'; return 'status-success.svg';
case 'Failed': case FAILED:
return 'status-failed.svg'; return 'status-failed.svg';
case 'Pending': case PENDING:
return 'status-pending.svg'; return 'status-pending.svg';
case 'NotAvailabe': case NOTAVAILABLE:
return 'status-NotAvailable.svg'; return 'status-NotAvailable.svg';
default: default:
return ''; return '';

View File

@ -1,6 +1,6 @@
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import { Link, Typography } from '@material-ui/core'; import { Link, Typography } from '@material-ui/core';
import { ButtonFilled, ButtonOutlined } from 'litmus-ui'; import { ButtonFilled, ButtonOutlined, TextButton } from 'litmus-ui';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Loader from '../../../components/Loader'; import Loader from '../../../components/Loader';
@ -28,8 +28,6 @@ import {
Workflow, Workflow,
WorkflowDataVars, WorkflowDataVars,
} from '../../../models/graphql/workflowData'; } from '../../../models/graphql/workflowData';
import useActions from '../../../redux/actions';
import * as TabActions from '../../../redux/actions/tabs';
import { history } from '../../../redux/configureStore'; import { history } from '../../../redux/configureStore';
import { getProjectID, getProjectRole } from '../../../utils/getSearchParams'; import { getProjectID, getProjectRole } from '../../../utils/getSearchParams';
import { ApplicationDashboardCard } from './ApplicationDashboardCard'; import { ApplicationDashboardCard } from './ApplicationDashboardCard';
@ -42,8 +40,6 @@ const Overview: React.FC = () => {
const projectRole = getProjectRole(); const projectRole = getProjectRole();
const { t } = useTranslation(); const { t } = useTranslation();
const tabs = useActions(TabActions);
let dataSource = false; let dataSource = false;
let workflowDashboardCount = 0; let workflowDashboardCount = 0;
let applicationDashboardCount = 0; let applicationDashboardCount = 0;
@ -155,13 +151,11 @@ const Overview: React.FC = () => {
</ButtonFilled> </ButtonFilled>
} }
link={ link={
<Link <TextButton
underline="none" variant="highlight"
color="primary"
onClick={() => { onClick={() => {
tabs.changeWorkflowsTabs(2);
history.push({ history.push({
pathname: '/workflows', pathname: '/myhub/Chaos%20Hub',
search: `?projectID=${projectID}&projectRole=${projectRole}`, search: `?projectID=${projectID}&projectRole=${projectRole}`,
}); });
}} }}
@ -169,7 +163,7 @@ const Overview: React.FC = () => {
<Typography> <Typography>
{t('homeViews.agentConfiguredHome.noWorkflow.explore')} {t('homeViews.agentConfiguredHome.noWorkflow.explore')}
</Typography> </Typography>
</Link> </TextButton>
} }
/> />
); );
@ -227,12 +221,18 @@ const Overview: React.FC = () => {
link={ link={
<Link <Link
underline="none" underline="none"
color="primary" href="https://github.com/litmuschaos/litmus/tree/master/monitoring#model-1-optional-prometheus-scrape-config-model"
href="https://prometheus.io/docs/introduction/overview/"
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
> >
<Typography>Read prometheus doc</Typography> <TextButton variant="highlight" className={classes.docsButton}>
<Typography>Sample Prometheus configuration</Typography>
<img
src="./icons/externalLink.svg"
alt="external link"
title="Read documentation"
/>
</TextButton>
</Link> </Link>
} }
/> />

View File

@ -4,6 +4,12 @@ const useStyles = makeStyles((theme: Theme) => ({
linkPointer: { linkPointer: {
cursor: 'pointer', cursor: 'pointer',
}, },
docsButton: {
'& img': {
padding: 0,
margin: theme.spacing(0, 0, 0, 1),
},
},
infoContainerButton: { infoContainerButton: {
'& img': { '& img': {
margin: theme.spacing(0, 1, -0.5, 0), margin: theme.spacing(0, 1, -0.5, 0),

View File

@ -366,7 +366,7 @@ const BrowseSchedule: React.FC = () => {
<TablePagination <TablePagination
rowsPerPageOptions={[10, 25, 50]} rowsPerPageOptions={[10, 25, 50]}
component="div" component="div"
count={filteredWorkflows?.length ?? 0} count={data?.ListWorkflow.totalNoOfWorkflows ?? 0}
rowsPerPage={paginationData.limit} rowsPerPage={paginationData.limit}
page={paginationData.page} page={paginationData.page}
onChangePage={(_, page) => onChangePage={(_, page) =>

View File

@ -12,6 +12,7 @@ import {
} from '../../../../utils/getSearchParams'; } from '../../../../utils/getSearchParams';
import { import {
FAILED, FAILED,
NOTAVAILABLE,
PENDING, PENDING,
RUNNING, RUNNING,
SUCCEEDED, SUCCEEDED,
@ -31,18 +32,20 @@ const WorkflowRunCard: React.FC<WorkflowRunCardProps> = ({ data }) => {
const nodeSelection = useActions(NodeSelectionActions); const nodeSelection = useActions(NodeSelectionActions);
function getPhaseVariant(variant: string | undefined): string { function getStatusVariant(phase: string | undefined): string {
switch (variant) { switch (phase) {
case SUCCEEDED: case SUCCEEDED:
return classes.succeeded; return 'status-success.svg';
case RUNNING: case RUNNING:
return classes.running; return 'status-running.svg';
case FAILED: case FAILED:
return classes.failed; return 'status-failed.svg';
case PENDING: case PENDING:
return classes.pending; return 'status-pending.svg';
case NOTAVAILABLE:
return 'status-NotAvailable.svg';
default: default:
return classes.pending; return '';
} }
} }
@ -77,9 +80,11 @@ const WorkflowRunCard: React.FC<WorkflowRunCardProps> = ({ data }) => {
<div className={classes.workflowDataContainer}> <div className={classes.workflowDataContainer}>
<div> <div>
<div className={classes.statusDiv}> <div className={classes.statusDiv}>
<svg viewBox="0 0 10 10"> <img
<circle className={getPhaseVariant(data.phase)} /> src={`./icons/${getStatusVariant(data.phase)}`}
</svg> alt={data.phase}
title={data.phase}
/>
<div> <div>
<Typography <Typography
className={`${classes.testName} ${classes.noWrapProvider}`} className={`${classes.testName} ${classes.noWrapProvider}`}

View File

@ -3,7 +3,7 @@ import { makeStyles } from '@material-ui/core';
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
animatedContainer: { animatedContainer: {
marginTop: theme.spacing(3.125), marginTop: theme.spacing(3.125),
padding: theme.spacing(2.5, 0), padding: theme.spacing(2.5),
willChange: `transform`, willChange: `transform`,
transition: `transform 250ms`, transition: `transform 250ms`,
cursor: 'pointer', cursor: 'pointer',
@ -19,19 +19,14 @@ const useStyles = makeStyles((theme) => ({
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
width: '75%', width: '75%',
'& svg': {
width: '3.75rem',
},
'& circle': {
r: '1',
cx: '5',
cy: '5',
},
}, },
statusDiv: { statusDiv: {
display: 'flex', display: 'flex',
'& img': {
width: '2.5rem',
marginRight: theme.spacing(2),
},
}, },
testName: { testName: {
@ -50,36 +45,9 @@ const useStyles = makeStyles((theme) => ({
lastRunTime: { lastRunTime: {
width: '4.8125rem', width: '4.8125rem',
}, },
listContainer: {
'& img': {
width: '1rem',
marginLeft: theme.spacing(2.25),
},
'& span': {
marginRight: theme.spacing(1.25),
},
},
listItem: {
'&:hover': {
background: theme.palette.cards.highlight,
},
},
noWrapProvider: { noWrapProvider: {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
}, },
// Phase states indicating the present run status
succeeded: {
fill: theme.palette.success.main,
},
running: {
fill: theme.palette.primary.main,
},
failed: {
fill: theme.palette.error.main,
},
pending: {
fill: theme.palette.primary.main,
},
// Resiliency Score indicators // Resiliency Score indicators
lowScore: { lowScore: {
color: theme.palette.error.main, color: theme.palette.error.main,

View File

@ -1,7 +1,7 @@
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import { Link, Typography } from '@material-ui/core'; import { Typography } from '@material-ui/core';
import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward'; import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward';
import { ButtonFilled, ButtonOutlined, Modal } from 'litmus-ui'; import { ButtonFilled, ButtonOutlined, Modal, TextButton } from 'litmus-ui';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { AgentDeployModal } from '../../../components/AgentDeployModal'; import { AgentDeployModal } from '../../../components/AgentDeployModal';
@ -86,9 +86,9 @@ const AgentConfiguredHome: React.FC<AgentConfiguredHomeProps> = ({
'homeViews.agentConfiguredHome.recentWorkflowRuns.heading' 'homeViews.agentConfiguredHome.recentWorkflowRuns.heading'
)} )}
link={ link={
<Link <TextButton
underline="none" className={classes.textButton}
color="primary" variant="highlight"
onClick={() => { onClick={() => {
tabs.changeWorkflowsTabs(0); tabs.changeWorkflowsTabs(0);
history.push({ history.push({
@ -97,10 +97,10 @@ const AgentConfiguredHome: React.FC<AgentConfiguredHomeProps> = ({
}); });
}} }}
> >
<Typography className={classes.linkPointer}> <Typography>
{t('homeViews.agentConfiguredHome.recentWorkflowRuns.viewAll')} {t('homeViews.agentConfiguredHome.recentWorkflowRuns.viewAll')}
</Typography> </Typography>
</Link> </TextButton>
} }
buttonLink="/create-workflow" buttonLink="/create-workflow"
buttonImgSrc="./icons/calendarBlank.svg" buttonImgSrc="./icons/calendarBlank.svg"
@ -138,13 +138,11 @@ const AgentConfiguredHome: React.FC<AgentConfiguredHomeProps> = ({
</ButtonFilled> </ButtonFilled>
} }
link={ link={
<Link <TextButton
underline="none" variant="highlight"
color="primary"
onClick={() => { onClick={() => {
tabs.changeWorkflowsTabs(2);
history.push({ history.push({
pathname: '/workflows', pathname: '/myhub/Chaos%20Hub',
search: `?projectID=${projectID}&projectRole=${projectRole}`, search: `?projectID=${projectID}&projectRole=${projectRole}`,
}); });
}} }}
@ -152,7 +150,7 @@ const AgentConfiguredHome: React.FC<AgentConfiguredHomeProps> = ({
<Typography> <Typography>
{t('homeViews.agentConfiguredHome.noWorkflow.explore')} {t('homeViews.agentConfiguredHome.noWorkflow.explore')}
</Typography> </Typography>
</Link> </TextButton>
} }
/> />
)} )}

View File

@ -1,8 +1,8 @@
import { makeStyles } from '@material-ui/core'; import { makeStyles } from '@material-ui/core';
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
linkPointer: { textButton: {
cursor: 'pointer', marginRight: theme.spacing(4.5),
}, },
infoContainerButton: { infoContainerButton: {
'& svg': { '& svg': {

View File

@ -2,6 +2,7 @@ export const FAILED: string = 'Failed';
export const RUNNING: string = 'Running'; export const RUNNING: string = 'Running';
export const PENDING: string = 'Pending'; export const PENDING: string = 'Pending';
export const SUCCEEDED: string = 'Succeeded'; export const SUCCEEDED: string = 'Succeeded';
export const NOTAVAILABLE: string = 'NotAvailable';
export const OMITTED: string = 'Omitted'; export const OMITTED: string = 'Omitted';
export const SKIPPED: string = 'Skipped'; export const SKIPPED: string = 'Skipped';
export const ERROR: string = 'Error'; export const ERROR: string = 'Error';