Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Moving pagination, sorting and filtering of workflow runs table to the backend #2829

Merged
merged 26 commits into from
Jun 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0e5b950
added pagination for QueryWorkflowRuns
arkajyotiMukherjee May 14, 2021
276ed71
merging pagination branch with master
arkajyotiMukherjee May 17, 2021
c561a26
filtering workflowRuns based on workflowRunIDs
arkajyotiMukherjee May 17, 2021
1a5c963
changed the API for getWorkflowRuns in frontend
arkajyotiMukherjee May 17, 2021
ff57b5f
added pagination for frontend and refactored code to accomodate the c…
arkajyotiMukherjee May 18, 2021
7a50efd
Added Sorting and Filtering
SarthakJain26 May 18, 2021
15f0d1a
sorting added from backend api call
arkajyotiMukherjee May 19, 2021
3d72e51
filtering removed from frontend and used backend APIs to filter data
arkajyotiMukherjee May 19, 2021
d09ce14
typed execution data in backend and sent common metadata from executi…
arkajyotiMukherjee May 21, 2021
9fcf93a
changing resiliency score to null in case of running workflows
arkajyotiMukherjee May 21, 2021
9dacdbe
Merge branch 'master' of https://github.com/litmuschaos/litmus into p…
arkajyotiMukherjee May 21, 2021
c3ca53e
WIP: filtering and sorting done, pagination remaining
arkajyotiMukherjee May 26, 2021
decd1b5
pagination completed in database
arkajyotiMukherjee May 27, 2021
f693fe0
reverted ID -> String changes
arkajyotiMukherjee May 27, 2021
556ba78
Merge branch 'master' of https://github.com/litmuschaos/litmus into p…
arkajyotiMukherjee May 27, 2021
92396f0
changed the sortStage
arkajyotiMukherjee May 27, 2021
a8c8659
Added condition to check no workflows
SarthakJain26 May 31, 2021
667422e
Merge branch 'master' of https://github.com/litmuschaos/litmus into p…
arkajyotiMukherjee Jun 1, 2021
20148f9
Pagination bug fix (#1)
arkajyotiMukherjee Jun 3, 2021
27701b6
Merge branch 'pagination' of https://github.com/arkajyotiMukherjee/li…
arkajyotiMukherjee Jun 3, 2021
a84ea1e
fixed the workflow subscription bugs...EVERYTHING FINALLY WORKS
arkajyotiMukherjee Jun 4, 2021
0d8bb5d
Merge branch 'master' of https://github.com/litmuschaos/litmus into p…
arkajyotiMukherjee Jun 4, 2021
6bf768d
removed comments from config
arkajyotiMukherjee Jun 4, 2021
79b2e08
resolved review comments: translations, formatting and removing binar…
arkajyotiMukherjee Jun 4, 2021
d5e2107
fixed some bugs and added Execution data to types.go
arkajyotiMukherjee Jun 4, 2021
c2c20a0
go fmt project
arkajyotiMukherjee Jun 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions litmus-portal/frontend/public/locales/en/translation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ chaosWorkflows:
browseWorkflows:
status: Status
name: Name
dateFilterHelperText: Select a period
targetAgent: Target Agent
reliabilityDetails: Reliability Details
experiments: Experiments
Expand Down
52 changes: 41 additions & 11 deletions litmus-portal/frontend/src/graphql/queries.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
import { gql } from '@apollo/client';

export const WORKFLOW_DETAILS_WITH_EXEC_DATA = gql`
query workflowDetails($workflowRunsInput: GetWorkflowRunsInput!) {
getWorkflowRuns(workflowRunsInput: $workflowRunsInput) {
total_no_of_workflow_runs
workflow_runs {
workflow_id
workflow_name
workflow_run_id
cluster_name
last_updated
cluster_id
phase
execution_data
resiliency_score
}
}
}
`;

export const WORKFLOW_DETAILS = gql`
query workflowDetails($projectID: String!) {
getWorkFlowRuns(project_id: $projectID) {
workflow_id
workflow_name
workflow_run_id
execution_data
project_id
cluster_name
last_updated
cluster_type
cluster_id
query workflowDetails($workflowRunsInput: GetWorkflowRunsInput!) {
getWorkflowRuns(workflowRunsInput: $workflowRunsInput) {
total_no_of_workflow_runs
workflow_runs {
workflow_id
workflow_name
workflow_run_id
cluster_name
last_updated
phase
resiliency_score
experiments_passed
total_experiments
}
}
}
`;
Expand Down Expand Up @@ -150,6 +172,14 @@ export const GET_CLUSTER_LENGTH = gql`
}
`;

export const GET_CLUSTER_NAMES = gql`
query getClusters($project_id: String!) {
getCluster(project_id: $project_id) {
cluster_name
}
}
`;

export const ALL_USERS = gql`
query allUsers {
users {
Expand Down
23 changes: 20 additions & 3 deletions litmus-portal/frontend/src/graphql/subscriptions.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import { gql } from '@apollo/client';

export const WORKFLOW_EVENTS = gql`
export const WORKFLOW_EVENTS_WITH_EXEC_DATA = gql`
subscription workflowEvents($projectID: String!) {
workflowEventListener(project_id: $projectID) {
workflow_id
workflow_name
workflow_run_id
execution_data
project_id
cluster_name
last_updated
cluster_id
phase
execution_data
resiliency_score
}
}
`;

export const WORKFLOW_EVENTS = gql`
subscription workflowEvents($projectID: String!) {
workflowEventListener(project_id: $projectID) {
workflow_id
workflow_name
workflow_run_id
cluster_name
last_updated
phase
resiliency_score
experiments_passed
total_experiments
}
}
`;
Expand Down
55 changes: 53 additions & 2 deletions litmus-portal/frontend/src/models/graphql/workflowData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,67 @@ export interface WorkflowRun {
workflow_run_id: string;
cluster_type: string;
cluster_id: string;
phase: string;
resiliency_score?: number;
experiments_passed?: number;
total_experiments?: number;
}

interface GetWorkflowRunsOutput {
total_no_of_workflow_runs: number;
workflow_runs: WorkflowRun[];
}

export interface Workflow {
getWorkFlowRuns: WorkflowRun[];
getWorkflowRuns: GetWorkflowRunsOutput;
}

export interface WorkflowSubscription {
workflowEventListener: WorkflowRun;
}

export interface WorkflowDataVars {
export interface WorkflowSubscriptionInput {
projectID: string;
}

// Pagination
export interface Pagination {
page: number;
limit: number;
}

// Sort
export interface SortInput {
field: 'Name' | 'Time';
descending?: boolean;
}

// Filter
interface DateRange {
start_date: string;
end_date?: string;
}

export type WorkflowStatus =
| 'All'
| 'Failed'
| 'Running'
| 'Succeeded'
| undefined;

export interface WorkflowRunFilterInput {
workflow_name?: string;
cluster_name?: string;
workflow_status?: WorkflowStatus;
date_range?: DateRange;
}

export interface WorkflowDataVars {
workflowRunsInput: {
project_id: string;
workflow_run_ids?: string[];
pagination?: Pagination;
sort?: SortInput;
filter?: WorkflowRunFilterInput;
};
}
77 changes: 43 additions & 34 deletions litmus-portal/frontend/src/pages/WorkflowDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import Tabs from '@material-ui/core/Tabs/Tabs';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { useParams } from 'react-router-dom';
import BackButton from '../../components/Button/BackButton';
import Loader from '../../components/Loader';
import { StyledTab, TabPanel } from '../../components/Tabs';
import Scaffold from '../../containers/layouts/Scaffold';
import {
SCHEDULE_DETAILS,
WORKFLOW_DETAILS,
WORKFLOW_EVENTS,
WORKFLOW_DETAILS_WITH_EXEC_DATA,
WORKFLOW_EVENTS_WITH_EXEC_DATA,
} from '../../graphql';
import {
ScheduleDataVars,
Expand All @@ -24,6 +24,7 @@ import {
Workflow,
WorkflowDataVars,
WorkflowSubscription,
WorkflowSubscriptionInput,
} from '../../models/graphql/workflowData';
import useActions from '../../redux/actions';
import * as NodeSelectionActions from '../../redux/actions/nodeSelection';
Expand All @@ -37,6 +38,10 @@ import WorkflowNodeInfo from '../../views/WorkflowDetails/WorkflowNodeInfo';
import NodeTable from '../../views/WorkflowDetails/WorkflowTable';
import useStyles from './styles';

interface URLParams {
workflowRunId: string;
}

const WorkflowDetails: React.FC = () => {
const theme = useTheme();
const { t } = useTranslation();
Expand All @@ -62,19 +67,23 @@ const WorkflowDetails: React.FC = () => {

const { pod_name } = useSelector((state: RootState) => state.selectedNode);

// Getting the workflow nome from the pathname
const { pathname } = useLocation();
const workflowRunId = pathname.split('/')[2];
const { workflowRunId }: URLParams = useParams();

// Query to get workflows
const { subscribeToMore, data, error } = useQuery<Workflow, WorkflowDataVars>(
WORKFLOW_DETAILS,
{ variables: { projectID } }
WORKFLOW_DETAILS_WITH_EXEC_DATA,
{
variables: {
workflowRunsInput: {
project_id: projectID,
workflow_run_ids: [workflowRunId],
},
},
fetchPolicy: 'cache-and-network',
}
);

const workflow = data?.getWorkFlowRuns.filter(
(w) => w.workflow_run_id === workflowRunId
)[0];
const workflow = data?.getWorkflowRuns.workflow_runs[0];

// Apollo query to get the scheduled data
const { data: SchedulesData, loading } = useQuery<
Expand All @@ -87,34 +96,32 @@ const WorkflowDetails: React.FC = () => {

// Using subscription to get realtime data
useEffect(() => {
if (
workflow?.execution_data &&
(JSON.parse(workflow?.execution_data) as ExecutionData).phase ===
'Running'
) {
subscribeToMore<WorkflowSubscription>({
document: WORKFLOW_EVENTS,
if (workflow?.phase && workflow.phase === 'Running') {
subscribeToMore<WorkflowSubscription, WorkflowSubscriptionInput>({
document: WORKFLOW_EVENTS_WITH_EXEC_DATA,
variables: { projectID },
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) return prev;
const modifiedWorkflows = prev.getWorkFlowRuns.slice();
if (!subscriptionData.data || !prev || !prev.getWorkflowRuns)
return prev;

const modifiedWorkflows = prev.getWorkflowRuns.workflow_runs.slice();
const newWorkflow = subscriptionData.data.workflowEventListener;

// 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);
// Update only the required workflowRun
if (
modifiedWorkflows[0].workflow_run_id === newWorkflow.workflow_run_id
)
modifiedWorkflows[0] = newWorkflow;

const totalNoOfWorkflows =
prev.getWorkflowRuns.total_no_of_workflow_runs;

return { ...prev, getWorkFlowRuns: modifiedWorkflows };
return {
getWorkflowRuns: {
total_no_of_workflow_runs: totalNoOfWorkflows,
workflow_runs: modifiedWorkflows,
},
};
},
});
}
Expand Down Expand Up @@ -233,6 +240,7 @@ const WorkflowDetails: React.FC = () => {
data={
JSON.parse(workflow.execution_data) as ExecutionData
}
resiliency_score={workflow.resiliency_score}
/>
)}
</div>
Expand All @@ -245,6 +253,7 @@ const WorkflowDetails: React.FC = () => {
tab={2}
cluster_name={workflow.cluster_name}
data={JSON.parse(workflow.execution_data) as ExecutionData}
resiliency_score={workflow.resiliency_score}
/>
{/* Table for all Node details */}
<NodeTable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ import React, { useState } from 'react';
import { DateRangePicker } from 'react-date-range';
import 'react-date-range/dist/styles.css'; // main css file
import 'react-date-range/dist/theme/default.css'; // theme css file
import { Workflow, WorkflowRun } from '../../../models/graphql/workflowData';
import { Clusters } from '../../../models/graphql/clusterData';
import { WorkflowStatus } from '../../../models/graphql/workflowData';
import useStyles from './styles';

interface HeaderSectionProps {
searchValue: string;
statusValue: string;
clusterValue: string;
searchValue?: string;
statusValue?: WorkflowStatus;
clusterValue?: string;
isOpen: boolean;
data: Workflow | undefined;
getClusters: (wfdata: WorkflowRun[]) => string[];
clusterList?: Partial<Clusters>;
isDateOpen: boolean;
popAnchorEl: HTMLElement | null;
displayDate: string;
Expand Down Expand Up @@ -62,10 +62,9 @@ const HeaderSection: React.FC<HeaderSectionProps> = ({
statusValue,
clusterValue,
isOpen,
data,
popAnchorEl,
displayDate,
getClusters,
clusterList,
changeSearch,
changeStatus,
changeCluster,
Expand All @@ -82,6 +81,7 @@ const HeaderSection: React.FC<HeaderSectionProps> = ({
key: 'selection',
},
]);

return (
<div>
<div className={classes.headerSection}>
Expand Down Expand Up @@ -127,13 +127,11 @@ const HeaderSection: React.FC<HeaderSectionProps> = ({
className={classes.selectText}
>
<MenuItem value="All">All</MenuItem>
{(data ? getClusters(data.getWorkFlowRuns) : []).map(
(cluster: string) => (
<MenuItem key={cluster} value={cluster}>
{cluster}
</MenuItem>
)
)}
{clusterList?.getCluster?.map((cluster) => (
<MenuItem key={cluster.cluster_name} value={cluster.cluster_name}>
{cluster.cluster_name}
</MenuItem>
))}
</Select>
</FormControl>

Expand Down
Loading