diff --git a/litmus-portal/frontend/.eslintrc.json b/litmus-portal/frontend/.eslintrc.json index 5f2b81504..721716988 100644 --- a/litmus-portal/frontend/.eslintrc.json +++ b/litmus-portal/frontend/.eslintrc.json @@ -18,6 +18,9 @@ } }, "rules": { + "no-nested-ternary": 0, + "no-plusplus": 0, + "dot-notation": 0, "camelcase": 0, "jsx-a11y/href-no-hash": ["off"], "react/jsx-props-no-spreading": ["off"], diff --git a/litmus-portal/frontend/public/icons/calender.svg b/litmus-portal/frontend/public/icons/calender.svg new file mode 100644 index 000000000..8a748ab44 --- /dev/null +++ b/litmus-portal/frontend/public/icons/calender.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/litmus-portal/frontend/public/icons/deleteSchedule.svg b/litmus-portal/frontend/public/icons/deleteSchedule.svg new file mode 100644 index 000000000..c5c533bbb --- /dev/null +++ b/litmus-portal/frontend/public/icons/deleteSchedule.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/litmus-portal/frontend/public/icons/editSchedule.svg b/litmus-portal/frontend/public/icons/editSchedule.svg new file mode 100644 index 000000000..9daa1a259 --- /dev/null +++ b/litmus-portal/frontend/public/icons/editSchedule.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/BrowseWorkflow/TableData.tsx b/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/BrowseWorkflow/TableData.tsx index 25fd0f892..5575e58fd 100644 --- a/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/BrowseWorkflow/TableData.tsx +++ b/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/BrowseWorkflow/TableData.tsx @@ -11,6 +11,7 @@ import CustomStatus from '../CustomStatus/Status'; import LinearProgressBar from '../../ReturningHome/ProgressBar/LinearProgressBar'; import useStyles from './styles'; import timeDifferenceForDate from '../../../../utils/datesModifier'; +import { history } from '../../../../redux/configureStore'; interface TableDataProps { data: any; @@ -35,7 +36,7 @@ const TableData: React.FC = ({ data }) => { - + {data.workflow_name} @@ -70,11 +71,7 @@ const TableData: React.FC = ({ data }) => { -
- - {timeDifferenceForDate(data.last_updated)} - -
+ {timeDifferenceForDate(data.last_updated)}
= ({ data }) => { open={open} onClose={handleClose} > - + + history.push({ + pathname: '/workflow-underground', + state: data, + }) + } + > Show the workflow diff --git a/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/BrowseWorkflow/index.tsx b/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/BrowseWorkflow/index.tsx index 9ea5fb70e..d80c499a8 100644 --- a/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/BrowseWorkflow/index.tsx +++ b/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/BrowseWorkflow/index.tsx @@ -1,66 +1,175 @@ -import React, { useEffect, useState } from 'react'; import { useQuery } from '@apollo/client'; -import SearchIcon from '@material-ui/icons/Search'; import { - InputBase, - InputAdornment, FormControl, + IconButton, + InputAdornment, + InputBase, InputLabel, - Select, MenuItem, - Typography, - TableContainer, + Select, Table, - TableHead, - TableRow, - TableCell, TableBody, + TableCell, + TableContainer, + TableHead, + TablePagination, + TableRow, + Typography, } from '@material-ui/core'; +import ExpandLessIcon from '@material-ui/icons/ExpandLess'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import SearchIcon from '@material-ui/icons/Search'; +import React, { useEffect, useState } from 'react'; +import { WORKFLOW_DETAILS, WORKFLOW_EVENTS } from '../../../../graphql'; +import { + ExecutionData, + Workflow, + WorkflowDataVars, + WorkflowRun, + WorkflowSubscription, +} from '../../../../models/workflowData'; + +import { + sortAlphaAsc, + sortAlphaDesc, + sortNumAsc, + sortNumDesc, +} from '../../../../utils/sort'; +import Loader from '../../../Loader'; import useStyles from './styles'; -import { history } from '../../../../redux/configureStore'; -import { WORKFLOW_DETAILS, WORKFLOW_EVENTS } from '../../../../schemas'; import TableData from './TableData'; +interface FilterOptions { + search: string; + status: string; + cluster: string; +} + +interface PaginationData { + pageNo: number; + rowsPerPage: number; +} + +interface SortData { + lastRun: { sort: boolean; ascending: boolean }; + name: { sort: boolean; ascending: boolean }; + noOfSteps: { sort: boolean; ascending: boolean }; +} + const BrowseWorkflow = () => { - // Apollo query with subscribeToMore - const { subscribeToMore, ...result } = useQuery(WORKFLOW_DETAILS); - - // Default table data - const [mainData, setMainData] = useState(); - - useEffect(() => { - // Get the inital table data - setMainData(result.data); - // Once Subscription is made, this is called - subscribeToMore({ - document: WORKFLOW_EVENTS, - updateQuery: (prev, { subscriptionData }) => { - if (!subscriptionData.data) return setMainData(prev); - const newData = subscriptionData.data.workflowEventListener; - return setMainData({ - ...prev, - getWorkFlowRuns: [...prev.getWorkFlowRuns, newData], - }); - }, - }); - }, [result.data]); const classes = useStyles(); - const [search, setSearch] = React.useState(''); + // Query to get workflows + const { subscribeToMore, data, loading, error } = useQuery< + Workflow, + WorkflowDataVars + >(WORKFLOW_DETAILS, { variables: { projectID: '00000' } }); - const [status, setStatus] = React.useState(''); + // Using subscription to get realtime data + useEffect(() => { + subscribeToMore({ + document: WORKFLOW_EVENTS, + variables: { projectID: '00000' }, + updateQuery: (prev, { subscriptionData }) => { + if (!subscriptionData.data) return prev; + const modifiedWorkflows = prev.getWorkFlowRuns.slice(); + const newWorkflow = subscriptionData.data.workflowEventListener; - const handleStatusChange = (event: React.ChangeEvent<{ value: unknown }>) => { - setStatus(event.target.value as String); - }; + // Updating the query data + let i = 0; + for (; i < modifiedWorkflows.length; i++) { + if ( + modifiedWorkflows[i].workflow_run_id === newWorkflow.workflow_run_id + ) { + modifiedWorkflows[i] = newWorkflow; + break; + } + } + if (i === modifiedWorkflows.length) + modifiedWorkflows.unshift(newWorkflow); - const [cluster, setCluster] = React.useState(''); + return { ...prev, getWorkFlowRuns: modifiedWorkflows }; + }, + }); + }, [data]); + + // States for filters + const [filters, setFilters] = useState({ + search: '', + status: 'All', + cluster: 'All', + }); + + // State for sorting + const [sortData, setSortData] = useState({ + lastRun: { sort: true, ascending: true }, + name: { sort: false, ascending: true }, + noOfSteps: { sort: false, ascending: false }, + }); + + // State for pagination + const [paginationData, setPaginationData] = useState({ + pageNo: 0, + rowsPerPage: 5, + }); + + const filteredData = data?.getWorkFlowRuns + .filter((dataRow) => + dataRow.workflow_name.toLowerCase().includes(filters.search) + ) + .filter((dataRow) => + filters.status === 'All' + ? true + : (JSON.parse(dataRow.execution_data) as ExecutionData).phase.includes( + filters.status + ) + ) + .filter((dataRow) => + filters.cluster === 'All' + ? true + : dataRow.cluster_name.toLowerCase().includes(filters.cluster) + ) + .sort((a: WorkflowRun, b: WorkflowRun) => { + // Sorting based on unique fields + if (sortData.name.sort) { + const x = a.workflow_name; + const y = b.workflow_name; + + return sortData.name.ascending + ? sortAlphaAsc(x, y) + : sortAlphaDesc(x, y); + } + + if (sortData.lastRun.sort) { + const x = parseInt(a.last_updated, 10); + const y = parseInt(b.last_updated, 10); + + return sortData.lastRun.ascending + ? sortNumAsc(y, x) + : sortNumDesc(y, x); + } + + return 0; + }) + .sort((a: WorkflowRun, b: WorkflowRun) => { + // Sorting based on non-unique fields + if (sortData.noOfSteps.sort) { + const x = Object.keys( + (JSON.parse(a.execution_data) as ExecutionData).nodes + ).length; + + const y = Object.keys( + (JSON.parse(b.execution_data) as ExecutionData).nodes + ).length; + + return sortData.noOfSteps.ascending + ? sortNumAsc(x, y) + : sortNumDesc(x, y); + } + + return 0; + }); - const handleClusterChange = ( - event: React.ChangeEvent<{ value: unknown }> - ) => { - setCluster(event.target.value as String); - }; return (
@@ -69,8 +178,11 @@ const BrowseWorkflow = () => { id="input-with-icon-adornment" placeholder="Search" className={classes.search} - value={search} - onChange={(e) => setSearch(e.target.value)} + value={filters.search} + onChange={(e) => { + setFilters({ ...filters, search: e.target.value as string }); + setPaginationData({ ...paginationData, pageNo: 0 }); + }} startAdornment={ @@ -84,18 +196,24 @@ const BrowseWorkflow = () => { @@ -107,12 +225,15 @@ const BrowseWorkflow = () => { - - for the period - Date + setFilter({ ...filter, cluster: event.target.value as string }) + } + disableUnderline + > + + All + + + + Cluset pre-defined + + + + + Kubernetes Cluster + + + + +
+ +
+ + + + + + + Workflow Name + + + + Starting Date + + + + Regularity + + + + + Cluster + + + + + Show Experiments + + + + + + + {loading ? ( + + + + + + ) : error ? ( + + + Unable to fetch data + + + ) : filteredData && filteredData.length ? ( + filteredData + .slice( + paginationData.pageNo * paginationData.rowsPerPage, + paginationData.pageNo * paginationData.rowsPerPage + + paginationData.rowsPerPage + ) + .map((data: any) => ( + + + + )) + ) : ( + + + No records available + + + )} + +
+
+ + setPaginationData({ ...paginationData, pageNo: page }) + } + onChangeRowsPerPage={(event) => { + setPaginationData({ + ...paginationData, + pageNo: 0, + rowsPerPage: parseInt(event.target.value, 10), + }); + }} + /> +
+ + ); +}; + +export default ScheduleWorkflow; diff --git a/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/ScheduleWorkflow/styles.ts b/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/ScheduleWorkflow/styles.ts new file mode 100644 index 000000000..22075e4a4 --- /dev/null +++ b/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/ScheduleWorkflow/styles.ts @@ -0,0 +1,128 @@ +import { makeStyles } from '@material-ui/core'; + +const useStyles = makeStyles((theme) => ({ + headerSection: { + width: '100%', + display: 'flex', + flexDirection: 'row', + alignContent: 'center', + alignItems: 'center', + justifyContent: 'center', + border: '1px solid ', + borderColor: theme.palette.text.hint, + backgroundColor: theme.palette.common.white, + }, + search: { + marginRight: 'auto', + marginLeft: theme.spacing(6.25), + }, + select: { + width: '10.375rem', + marginLeft: theme.spacing(1.25), + paddingBottom: theme.spacing(2.5), + marginRight: theme.spacing(3.75), + }, + headerText: { + marginLeft: theme.spacing(3.75), + color: theme.palette.text.disabled, + paddingBottom: theme.spacing(0.625), + }, + tableMain: { + marginTop: theme.spacing(6.25), + border: '1px solid rgba(0,0,0,0.1)', + backgroundColor: theme.palette.common.white, + height: '29.180rem', + }, + tableHead: { + opacity: 1, + height: '4.6875rem', + }, + headerStatus: { + paddingLeft: theme.spacing(10), + color: theme.palette.customColors.black(0.4), + }, + headerStatus1: { + paddingLeft: theme.spacing(8), + }, + progressBar: { + width: '6.5rem', + }, + steps: { + marginLeft: theme.spacing(5.625), + }, + menuItem: { + paddingLeft: theme.spacing(1.75), + }, + workflowName: { + borderRight: '1px solid rgba(0,0,0,0.1)', + color: theme.palette.customColors.black(0.4), + }, + workflowNameData: { + borderRight: '1px solid rgba(0,0,0,0.1)', + }, + regularity: { + paddingLeft: theme.spacing(3.75), + color: theme.palette.customColors.black(0.4), + }, + targetCluster: { + color: theme.palette.customColors.black(0.4), + }, + clusterStartDate: { + paddingLeft: theme.spacing(8), + }, + regularityData: { + maxWidth: '12.5rem', + paddingLeft: theme.spacing(4), + }, + stepsData: { + paddingLeft: theme.spacing(3.75), + }, + expInfo: { + color: theme.palette.primary.dark, + }, + showExp: { + paddingLeft: theme.spacing(1), + color: theme.palette.customColors.black(0.4), + }, + expDiv: { + display: 'flex', + flexDirection: 'row', + }, + expDiv1: { + display: 'flex', + flexDirection: 'row', + cursor: 'pointer', + }, + weightDiv: { + width: 243, + padding: '25px 20px', + }, + weightInfo: { + display: 'flex', + flexDirection: 'row', + paddingBottom: theme.spacing(0.625), + }, + clusterData: { + paddingTop: theme.spacing(1.25), + }, + optionBtn: { + marginLeft: theme.spacing(-6.25), + }, + menuCell: { + width: '3.125rem', + }, + timeDiv: { + display: 'flex', + flexDirection: 'row', + }, + btnImg: { + width: '0.8125rem', + height: '0.8125rem', + marginTop: theme.spacing(0.375), + }, + btnText: { + paddingLeft: theme.spacing(1.625), + }, +})); + +export default useStyles; diff --git a/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/WorkflowTabs/index.tsx b/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/WorkflowTabs/index.tsx index aa89e4194..e19dc0fba 100644 --- a/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/WorkflowTabs/index.tsx +++ b/litmus-portal/frontend/src/components/Sections/ChaosWorkflows/WorkflowTabs/index.tsx @@ -5,9 +5,9 @@ import Tabs from '@material-ui/core/Tabs'; import React from 'react'; import { history } from '../../../../redux/configureStore'; import ButtonFilled from '../../../Button/ButtonFilled'; -import Loader from '../../../Loader'; import BrowseWorkflow from '../BrowseWorkflow'; import useStyles from './styles'; +import ScheduleWorkflow from '../ScheduleWorkflow'; import Templates from '../Templates'; interface TabPanelProps { @@ -86,7 +86,7 @@ const CenteredTabs = () => { - + diff --git a/litmus-portal/frontend/src/components/Sections/Workflow/WorkflowCluster/index.tsx b/litmus-portal/frontend/src/components/Sections/Workflow/WorkflowCluster/index.tsx index 674ae3e2a..7c4af2e33 100644 --- a/litmus-portal/frontend/src/components/Sections/Workflow/WorkflowCluster/index.tsx +++ b/litmus-portal/frontend/src/components/Sections/Workflow/WorkflowCluster/index.tsx @@ -11,7 +11,7 @@ import { useSelector } from 'react-redux'; import ButtonFilled from '../../../Button/ButtonFilled'; import ButtonOutLine from '../../../Button/ButtonOutline'; import useStyles from './styles'; -import { GET_CLUSTER } from '../../../../schemas'; +import { GET_CLUSTER } from '../../../../graphql'; import { RootState } from '../../../../redux/reducers'; import { UserData } from '../../../../models/user'; import useActions from '../../../../redux/actions'; diff --git a/litmus-portal/frontend/src/components/WelcomeModal/Stepper.tsx b/litmus-portal/frontend/src/components/WelcomeModal/Stepper.tsx index 42a7e318b..c536eb318 100644 --- a/litmus-portal/frontend/src/components/WelcomeModal/Stepper.tsx +++ b/litmus-portal/frontend/src/components/WelcomeModal/Stepper.tsx @@ -5,8 +5,8 @@ import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import ButtonFilled from '../Button/ButtonFilled'; import config from '../../config'; +import { CREATE_USER } from '../../graphql'; import { RootState } from '../../redux/reducers'; -import { CREATE_USER } from '../../schemas'; import InputField from '../InputField'; import ModalPage from './Modalpage'; import useStyles from './styles'; diff --git a/litmus-portal/frontend/src/components/WorkflowStepper/index.tsx b/litmus-portal/frontend/src/components/WorkflowStepper/index.tsx index edfd48a6a..c48077ece 100644 --- a/litmus-portal/frontend/src/components/WorkflowStepper/index.tsx +++ b/litmus-portal/frontend/src/components/WorkflowStepper/index.tsx @@ -23,7 +23,7 @@ import { RootState } from '../../redux/reducers'; import useActions from '../../redux/actions'; import * as WorkflowActions from '../../redux/actions/workflow'; import parsed from '../../utils/yamlUtils'; -import { CREATE_WORKFLOW } from '../../schemas'; +import { CREATE_WORKFLOW } from '../../graphql'; import Unimodal from '../../containers/layouts/Unimodal'; import { history } from '../../redux/configureStore'; diff --git a/litmus-portal/frontend/src/containers/app/App.tsx b/litmus-portal/frontend/src/containers/app/App.tsx index 5c166275c..39982c44a 100644 --- a/litmus-portal/frontend/src/containers/app/App.tsx +++ b/litmus-portal/frontend/src/containers/app/App.tsx @@ -23,7 +23,7 @@ const BrowseTemplate = lazy(() => const HomePage = lazy(() => import('../../pages/HomePage')); const Community = lazy(() => import('../../pages/Community')); const Settings = lazy(() => import('../../pages/Settings')); - +const SchedulePage = lazy(() => import('../../pages/SchedulePage')); interface RoutesProps { userData: string; } @@ -49,6 +49,7 @@ const Routes: React.FC = ({ userData }) => { + { diff --git a/litmus-portal/frontend/src/pages/SchedulePage/SetTime/index.tsx b/litmus-portal/frontend/src/pages/SchedulePage/SetTime/index.tsx new file mode 100644 index 000000000..4226f70c9 --- /dev/null +++ b/litmus-portal/frontend/src/pages/SchedulePage/SetTime/index.tsx @@ -0,0 +1,102 @@ +import { + Button, + Fade, + FormControl, + Menu, + MenuItem, + TextField, +} from '@material-ui/core'; +import React from 'react'; +import useStyles from './styles'; + +interface SetTimeProps { + start: number; + end: number; + interval: number; + label: string; + type: string; +} + +// dropdown menu component for setting time +const SetTime: React.FC = ({ + start, + end, + interval, + label, + type, +}) => { + const classes = useStyles(); + const [anchorEl, setAnchorEl] = React.useState(null); + const [age, setAge] = React.useState(0); + const open = Boolean(anchorEl); + const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => { + setAge((event.target.value as unknown) as number); + setAnchorEl(null); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + const size = (end - start) / interval; + + const names: number[] = [start]; + for (let i = 1; i <= size; i += 1) { + names[i] = names[i - 1] + interval; + } + + return ( +
+ + + + + + {names.map((name) => ( + { + setAge(name); + setAnchorEl(null); + }} + > + {name} {type} + + ))} + +
+ ); +}; +export default SetTime; diff --git a/litmus-portal/frontend/src/pages/SchedulePage/SetTime/styles.ts b/litmus-portal/frontend/src/pages/SchedulePage/SetTime/styles.ts new file mode 100644 index 000000000..3448d8faf --- /dev/null +++ b/litmus-portal/frontend/src/pages/SchedulePage/SetTime/styles.ts @@ -0,0 +1,20 @@ +import { makeStyles, Theme } from '@material-ui/core/styles'; + +const useStyles = makeStyles((theme: Theme) => ({ + button: { + fontSize: '0.75rem', + '&:hover': { + focusVisible: 'none', + background: theme.palette.secondary.contrastText, + }, + marginTop: theme.spacing(0.7), + textTransform: 'none', + fontWeight: 'normal', + }, + textField: { + width: '4.4375rem', + height: '2.75rem', + marginLeft: theme.spacing(1.875), + }, +})); +export default useStyles; diff --git a/litmus-portal/frontend/src/pages/SchedulePage/index.tsx b/litmus-portal/frontend/src/pages/SchedulePage/index.tsx new file mode 100644 index 000000000..a3996c4db --- /dev/null +++ b/litmus-portal/frontend/src/pages/SchedulePage/index.tsx @@ -0,0 +1,373 @@ +import { + Divider, + FormControl, + FormControlLabel, + Radio, + RadioGroup, + Select, + Typography, +} from '@material-ui/core'; +import React from 'react'; +import CustomDate from '../../components/DateTime/CustomDate/index'; +import CustomTime from '../../components/DateTime/CustomTime/index'; +import SetTime from './SetTime/index'; +import useStyles from './styles'; +import Scaffold from '../../containers/layouts/Scaffold'; +import ButtonFilled from '../../components/Button/ButtonFilled'; +import ButtonOutline from '../../components/Button/ButtonOutline'; + +// To be changed to a Location Generic +interface WorkflowScheduleProps { + location: any; +} + +const SchedulePage: React.FC = () => { + const start = 0; + const end = 10; + const interval = 2; + + const classes = useStyles(); + // controls radio buttons + const [value, setValue] = React.useState('now'); + const handleChange = (event: React.ChangeEvent) => { + setValue(event.target.value); + }; + + // controls inner radio buttons of recurring schedule + const [valueDef, setValueDef] = React.useState(''); + const handleChangeInstance = (event: React.ChangeEvent) => { + setValueDef(event.target.value); + }; + + // sets weekdays + const [days, setDays] = React.useState('Monday'); + + // sets dates + const [dates, setDates] = React.useState(1); + + // stores dates in an array + const names: number[] = [1]; + for (let i = 1; i <= 30; i += 1) { + names[i] = i + 1; + } + + const weekdays: string[] = [ + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + 'Sunday', + ]; + + return ( + +
+ + Schedule a workflow + + + Click on test to see detailed log of your workflow + +
+
+ {/* Upper segment */} +
+
+ + Schedule details: + + +
+ + Choose the right time to first workflow. Below you can find + any option convenient for you. + +
+
+ calendar +
+ + + {/* Lower segment */} +
+ + + {/* options to choose schedule */} + } + label={ + + Schedule now + + } + /> + + } + label={ + + Schedule after some time + + } + /> + {value === 'afterSometime' ? ( +
+ + Choose the minutes, hours, or days when you want to + start workflow + +
+ + After + + + + +
+
+ ) : ( + <> + )} + } + label={ + + Schedule at a specific time + + } + /> + + {value === 'specificTime' ? ( +
+ + Select date and time to start workflow in future + +
+ + +
+
+ ) : ( + <> + )} + } + label={ + + Recurring Schedule + + } + /> + {value === 'recurringScedule' ? ( +
+ + Choose the right recurring time to start your workflow + + + {/* options to select time of recurring schedule */} +
+ + + } + label="Every Hour" + /> + {valueDef === 'everyHr' ? ( +
+
+ + At + + +
+
+ ) : ( + <> + )} + } + label="Every Day " + /> + {valueDef === 'everyDay' ? ( +
+
+ + At + + +
+
+ ) : ( + <> + )} + } + label="Every Week " + /> + {valueDef === 'everyWeek' ? ( +
+
+ + On + + + + + + at + + +
+
+ ) : ( + <> + )} + } + label="Every Month" + /> + {valueDef === 'everyMonth' ? ( +
+
+ + On + + + + + + at + + +
+
+ ) : ( + <> + )} +
+
+
+
+ ) : ( + <> + )} +
+
+
+ +
+ {}}> + Cancel + +
+ {}}> + Save Changes + +
+
+
+
+
+
+ ); +}; + +export default SchedulePage; diff --git a/litmus-portal/frontend/src/pages/SchedulePage/styles.ts b/litmus-portal/frontend/src/pages/SchedulePage/styles.ts new file mode 100644 index 000000000..c89386489 --- /dev/null +++ b/litmus-portal/frontend/src/pages/SchedulePage/styles.ts @@ -0,0 +1,166 @@ +import { makeStyles, Theme } from '@material-ui/core/styles'; + +const useStyles = makeStyles((theme: Theme) => ({ + rootContainer: { + paddingTop: 50, + paddingLeft: 30, + }, + root: { + backgroundColor: 'rgba(255, 255, 255, 0.6)', + width: '90%', + marginTop: 30, + border: 1, + borderColor: theme.palette.text.disabled, + borderRadius: '0.1875rem', + }, + scHeader: { + paddingLeft: theme.spacing(3.75), + paddingRight: theme.spacing(3.75), + paddingTop: theme.spacing(3.75), + paddingBottom: theme.spacing(3.75), + }, + + mainHeader: { + marginTop: theme.spacing(1.25), + fontSize: '36px', + }, + + headerDesc: { + fontSize: '16px', + }, + /* styles for upper and lower segment */ + scSegments: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-even', + }, + + headerText: { + marginTop: theme.spacing(1.25), + fontSize: '1.5625rem', + }, + schBody: { + width: '32.18rem', + }, + captionText: { + fontSize: '0.75rem', + color: theme.palette.text.disabled, + }, + schLater: { + marginLeft: theme.spacing(3.75), + }, + + radioText: { + fontSize: '0.875rem', + }, + description: { + width: '32.18rem', + marginTop: theme.spacing(3.25), + marginBottom: theme.spacing(7.5), + fontSize: '1rem', + }, + + calIcon: { + width: '7rem', + height: '6.31rem', + marginTop: theme.spacing(5), + marginLeft: 'auto', + }, + + scFormControl: { + marginTop: theme.spacing(5), + }, + + /* For recurring schedule options */ + scRandom: { + display: 'flex', + flexDirection: 'row', + marginLeft: theme.spacing(1.625), + marginBottom: theme.spacing(4.125), + height: '2.75rem', + alignItems: 'center', + }, + + formControl: { + margin: theme.spacing(1), + }, + + /* for option- after sometime */ + wtDateTime: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + width: '19.2rem', + height: '2.75rem', + marginTop: theme.spacing(2.125), + marginBottom: theme.spacing(4.125), + }, + + /* for option- at specific time */ + innerSpecific: { + marginTop: theme.spacing(2.125), + marginBottom: theme.spacing(4.125), + display: 'flex', + flexDirection: 'row', + alignItems: 'stretch', + }, + + innerRecurring: { + marginTop: theme.spacing(2.125), + }, + + /* for each options of recurring schedule */ + scRandsub1: { + margin: theme.spacing(1.875), + fontSize: '0.75rem', + color: theme.palette.text.disabled, + }, + + /* for selecting weekdays */ + formControlDT: { + margin: theme.spacing(1), + minWidth: '6.6025rem', + minHeight: '2.75rem', + '&:select': { + focusVisible: 'none', + background: theme.palette.secondary.contrastText, + }, + }, + + /* for selecting date of every month */ + formControlMonth: { + margin: theme.spacing(1), + minWidth: '5.3125rem', + minHeight: '2.75rem', + }, + + /* for each select */ + select: { + padding: theme.spacing(2.5), + border: '1px solid #D1D2D7', + borderRadius: '0.1875rem', + fontSize: '0.75rem', + height: '2.75rem', + }, + /* for each option */ + opt: { + marginBottom: theme.spacing(1), + marginLeft: theme.spacing(0.2), + marginRight: theme.spacing(0.2), + paddingLeft: theme.spacing(1), + borderRadius: '0.0625rem', + '&:hover': { + background: '#D1D2D7', + }, + }, + /* style for submit section */ + submitDiv: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-even', + marginTop: theme.spacing(6.25), + }, +})); + +export default useStyles; diff --git a/litmus-portal/frontend/src/pages/WorkflowUnderground/index.tsx b/litmus-portal/frontend/src/pages/WorkflowUnderground/index.tsx index f317253f2..a40e48c80 100644 --- a/litmus-portal/frontend/src/pages/WorkflowUnderground/index.tsx +++ b/litmus-portal/frontend/src/pages/WorkflowUnderground/index.tsx @@ -1,13 +1,11 @@ -/* eslint-disable camelcase */ - import React, { useState, useEffect } from 'react'; import { useSubscription } from '@apollo/client'; import { Typography } from '@material-ui/core'; import Scaffold from '../../containers/layouts/Scaffold'; -import { WORKFLOW_EVENTS } from '../../schemas'; import SideBar from '../../components/Sections/WorkflowUnderground/WorkflowRepresentation'; import useStyles from './styles'; import Loader from '../../components/Loader'; +import { WORKFLOW_EVENTS } from '../../graphql'; interface WorkflowUndergroundProps { location: any; diff --git a/litmus-portal/frontend/src/theme/index.tsx b/litmus-portal/frontend/src/theme/index.tsx index 0f518b453..66c528d10 100644 --- a/litmus-portal/frontend/src/theme/index.tsx +++ b/litmus-portal/frontend/src/theme/index.tsx @@ -71,13 +71,13 @@ function customTheme(options: ThemeOptions) { white: (opacity: number): string => { let op = opacity; if (op < 0) op = 0; - if (op < 100) op = 100; + if (op > 100) op = 100; return `rgba(255, 255, 255, ${op})`; }, black: (opacity: number): string => { let op = opacity; if (op < 0) op = 0; - if (op < 100) op = 100; + if (op > 100) op = 100; return `rgba(0, 0, 0, ${op})`; }, }, diff --git a/litmus-portal/frontend/src/utils/sort.ts b/litmus-portal/frontend/src/utils/sort.ts new file mode 100644 index 000000000..a50b3a4a5 --- /dev/null +++ b/litmus-portal/frontend/src/utils/sort.ts @@ -0,0 +1,13 @@ +const sortAlphaAsc = (a: string, b: string): number => + a === b ? 0 : a < b ? -1 : 1; + +const sortAlphaDesc = (a: string, b: string): number => + a === b ? 0 : a > b ? -1 : 1; + +const sortNumAsc = (a: number, b: number): number => + a === b ? 0 : a < b ? -1 : 1; + +const sortNumDesc = (a: number, b: number): number => + a === b ? 0 : a > b ? -1 : 1; + +export { sortAlphaAsc, sortAlphaDesc, sortNumAsc, sortNumDesc };