fluent ui details List implementation in Functional component - reactjs

Can anybody send code on how to implement fluent UI details List in Functional Component(https://developer.microsoft.com/en-us/fluentui#/controls/web/detailslist/basic) and how to fetch data from API to details List

That's a start you will need to "refact" this code by the way this is a really good practice :
import * as React from "react";
import { Announced } from "office-ui-fabric-react/lib/Announced";
import {
TextField,
ITextFieldStyles
} from "office-ui-fabric-react/lib/TextField";
import {
DetailsList,
DetailsListLayoutMode,
Selection,
IColumn
} from "office-ui-fabric-react/lib/DetailsList";
import { MarqueeSelection } from "office-ui-fabric-react/lib/MarqueeSelection";
import { Fabric } from "office-ui-fabric-react/lib/Fabric";
import { mergeStyles } from "office-ui-fabric-react/lib/Styling";
import { Text } from "office-ui-fabric-react/lib/Text";
const exampleChildClass = mergeStyles({
display: "block",
marginBottom: "10px"
});
const textFieldStyles: Partial<ITextFieldStyles> = {
root: { maxWidth: "300px" }
};
export interface IDetailsListBasicExampleItem {
key: number;
name: string;
value: number;
}
export interface IDetailsListBasicExampleState {
items: IDetailsListBasicExampleItem[];
selectionDetails: string;
}
export const DetailsListBasicExampleFunction: React.FunctionComponent<
{} | IDetailsListBasicExampleState
> = () => {
const _allItems: IDetailsListBasicExampleItem[] = [];
const [selection, setSelection] = React.useState<Selection | undefined>();
function _getSelectionDetails(): string {
const selectionCount = selection ? selection.getSelectedCount() : 0;
switch (selectionCount) {
case 0:
return "No items selected";
case 1:
return (
"1 item selected: " +
(selection.getSelection()[0] as IDetailsListBasicExampleItem).name
);
default:
return `${selectionCount} items selected`;
}
}
const [state, setState] = React.useState({
items: _allItems,
selectionDetails: _getSelectionDetails()
});
React.useEffect(() => {
const _selection: Selection = new Selection({
onSelectionChanged: () =>
setState((prev) => {
return { ...prev, selectionDetails: _getSelectionDetails() };
})
});
setSelection(_selection);
for (let i = 0; i < 200; i++) {
_allItems.push({
key: i,
name: "Item " + i,
value: i
});
}
setState((prev) => {
return { ...prev, items: _allItems };
});
}, []);
const _columns: IColumn[] = [
{
key: "column1",
name: "Name",
fieldName: "name",
minWidth: 100,
maxWidth: 200,
isResizable: true
},
{
key: "column2",
name: "Value",
fieldName: "value",
minWidth: 100,
maxWidth: 200,
isResizable: true
}
];
// Populate with items for demos.
const _onFilter = (
ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
text: string
): void => {
console.log(text);
setState((prev) => {
return {
...prev,
items: text
? _allItems.filter((i) => i.name.toLowerCase().indexOf(text) > -1)
: _allItems
};
});
};
const _onItemInvoked = (item: IDetailsListBasicExampleItem): void => {
alert(`Item invoked: ${item.name}`);
};
return selection ? (
<Fabric>
<div className={exampleChildClass}>{state.selectionDetails}</div>
<Text>
Note: While focusing a row, pressing enter or double clicking will
execute onItemInvoked, which in this example will show an alert.
</Text>
<Announced message={state.selectionDetails} />
<TextField
className={exampleChildClass}
label="Filter by name:"
onChange={(e, t) => _onFilter(e, t ?? "")}
styles={textFieldStyles}
/>
<Announced
message={`Number of items after filter applied: ${state.items.length}.`}
/>
<MarqueeSelection selection={selection}>
<DetailsList
items={state.items}
columns={_columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selection={selection}
selectionPreservedOnEmptyClick={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
checkButtonAriaLabel="select row"
onItemInvoked={_onItemInvoked}
/>
</MarqueeSelection>
</Fabric>
) : (
<div>Loading</div>
);
};
UPDATE
To pass this sample of code in JSX this is pretty easy you just need to remove all type thing.
And to fetch data I use axios.
see the code below:
import * as React from "react";
import { Announced } from "office-ui-fabric-react/lib/Announced";
import { TextField } from "office-ui-fabric-react/lib/TextField";
import {
DetailsList,
DetailsListLayoutMode,
Selection
} from "office-ui-fabric-react/lib/DetailsList";
import { MarqueeSelection } from "office-ui-fabric-react/lib/MarqueeSelection";
import { Fabric } from "office-ui-fabric-react/lib/Fabric";
import { mergeStyles } from "office-ui-fabric-react/lib/Styling";
import { Text } from "office-ui-fabric-react/lib/Text";
import axios from "axios";
const exampleChildClass = mergeStyles({
display: "block",
marginBottom: "10px"
});
const textFieldStyles = {
root: { maxWidth: "300px" }
};
export const DetailsListBasicExampleFunction = () => {
const _allItems = [];
const [selection, setSelection] = React.useState();
function _getSelectionDetails() {
const selectionCount = selection ? selection.getSelectedCount() : 0;
switch (selectionCount) {
case 0:
return "No items selected";
case 1:
return "1 item selected: " + selection.getSelection()[0].name;
default:
return `${selectionCount} items selected`;
}
}
const [state, setState] = React.useState({
items: _allItems,
selectionDetails: _getSelectionDetails()
});
React.useEffect(() => {
const _selection = new Selection({
onSelectionChanged: () =>
setState((prev) => {
return { ...prev, selectionDetails: _getSelectionDetails() };
})
});
setSelection(_selection);
//********************** */fetch data from api***************************************
axios
.get("/data.json") //pass your url in param
.then((res) =>
setState((prev) => {
return { ...prev, items: res.data };
})
); //pass data in setState
}, []);
const _columns = [
{
key: "column1",
name: "Name",
fieldName: "name",
minWidth: 100,
maxWidth: 200,
isResizable: true
},
{
key: "column2",
name: "Value",
fieldName: "value",
minWidth: 100,
maxWidth: 200,
isResizable: true
}
];
// Populate with items for demos.
const _onFilter = (ev, text) => {
console.log(text);
setState((prev) => {
return {
...prev,
items: text
? _allItems.filter((i) => i.name.toLowerCase().indexOf(text) > -1)
: _allItems
};
});
};
const _onItemInvoked = (item) => {
alert(`Item invoked: ${item.name}`);
};
return selection ? (
<Fabric>
<div className={exampleChildClass}>{state.selectionDetails}</div>
<Text>
Note: While focusing a row, pressing enter or double clicking will
execute onItemInvoked, which in this example will show an alert.
</Text>
<Announced message={state.selectionDetails} />
<TextField
className={exampleChildClass}
label="Filter by name:"
onChange={(e, t) => _onFilter(e, t ?? "")}
styles={textFieldStyles}
/>
<Announced
message={`Number of items after filter applied: ${state.items.length}.`}
/>
<MarqueeSelection selection={selection}>
<DetailsList
items={state.items}
columns={_columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selection={selection}
selectionPreservedOnEmptyClick={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
checkButtonAriaLabel="select row"
onItemInvoked={_onItemInvoked}
/>
</MarqueeSelection>
</Fabric>
) : (
<div>Loading</div>
);
};

Related

Custom nodes in react-flow; saving additional data to a node after it has been created

This is my first introduction to react-flow. I am looking to create a custom node where after creation, the user can enter information in the node and save/display it. From the react-flow documentation on custom nodes, they have a similar example where they created a TextUpdaterNode that console.logs the user input.
Instead of logging it it via console, I am looking for a way to save the information to the node itself and display it on the node. For example, if a user were to enter "24, male" into the input and hit the "enter" key, I want the node to be updated with that information.
What are the ways I can go about doing this?
What you're trying to do needs a little more than that:
You can see alive example here: https://codesandbox.io/s/dank-waterfall-8jfcf4?file=/src/App.js
Basically, you need:
Import useNodesState from 'react-flow-renderer';
Instead of basic definition of nodes, you will need to use: const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
Then, will have to define the onAdd, which looks like:
const onAdd = useCallback(() => {
const newNode = {
id: getNodeId(),
data: { label: `${state.name} (${state.age})` },
position: {
x: 0,
y: 0 + (nodes.length + 1) * 20
}
};
setNodes((nds) => nds.concat(newNode));
}, [nodes, setNodes, state.name, state.age]);
You can include edit, pretty similar like:
const onEdit = () => {
setNodes((nds) =>
nds.map((node) => {
if (node.id === editState.id) {
node.data = {
...node.data,
label: `${node.id} - ${editState.name} (${editState.age})`
};
}
return node;
})
);
};
Finally, draw the flow: <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} />
The whole code looks like:
import React, { useState, useCallback } from "react";
import ReactFlow, {
ReactFlowProvider,
useNodesState,
useEdgesState
} from "react-flow-renderer";
import "./styles.css";
const getNodeId = () => `randomnode_${+new Date()}`;
const initialNodes = [
{ id: "1", data: { label: "Node 1" }, position: { x: 100, y: 100 } },
{ id: "2", data: { label: "Node 2" }, position: { x: 100, y: 200 } }
];
const initialEdges = [{ id: "e1-2", source: "1", target: "2" }];
const FlowExample = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges] = useEdgesState(initialEdges);
const [state, setState] = useState({ name: "", age: "" });
const onAdd = useCallback(() => {
const newNode = {
id: getNodeId(),
data: { label: `${state.name} (${state.age})` },
position: {
x: 0,
y: 0 + (nodes.length + 1) * 20
}
};
setNodes((nds) => nds.concat(newNode));
}, [nodes, setNodes, state.name, state.age]);
return (
<div>
Name:{" "}
<input
type="text"
onChange={(e) => {
setState((prev) => ({ ...prev, name: e.target.value }));
}}
/>
Age:{" "}
<input
type="text"
onChange={(e) => {
setState((prev) => ({ ...prev, age: e.target.value }));
}}
/>
<button onClick={onAdd}>add node</button>
<div style={{ width: "500px", height: "500px" }}>
<ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} />
</div>
</div>
);
};
export default () => (
<ReactFlowProvider>
<FlowExample />
</ReactFlowProvider>
);
Also, with edit:
import React, { useState, useCallback } from "react";
import ReactFlow, {
ReactFlowProvider,
useNodesState,
useEdgesState
} from "react-flow-renderer";
import "./styles.css";
const getNodeId = () => `${String(+new Date()).slice(6)}`;
const initialNodes = [
{ id: "1", data: { label: "Node 1" }, position: { x: 100, y: 100 } },
{ id: "2", data: { label: "Node 2" }, position: { x: 100, y: 200 } }
];
const initialEdges = [{ id: "e1-2", source: "1", target: "2" }];
const FlowExample = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges] = useEdgesState(initialEdges);
const [state, setState] = useState({ name: "", age: "" });
const [editState, setEditState] = useState({ id: "", name: "", age: "" });
const onEdit = () => {
setNodes((nds) =>
nds.map((node) => {
if (node.id === editState.id) {
node.data = {
...node.data,
label: `${node.id} - ${editState.name} (${editState.age})`
};
}
return node;
})
);
};
const onAdd = () => {
const id = getNodeId();
const newNode = {
id,
data: { label: `${id} - ${state.name} (${state.age})` },
position: {
x: 0,
y: 0 + (nodes.length + 1) * 20
}
};
setNodes((nds) => nds.concat(newNode));
};
return (
<div>
Name:{" "}
<input
type="text"
onChange={(e) => {
setState((prev) => ({ ...prev, name: e.target.value }));
}}
/>
Age:{" "}
<input
type="text"
onChange={(e) => {
setState((prev) => ({ ...prev, age: e.target.value }));
}}
/>
<button onClick={onAdd}>add node</button>
<br />
Id:{" "}
<input
type="text"
onChange={(e) => {
setEditState((prev) => ({ ...prev, id: e.target.value }));
}}
/>
Name:{" "}
<input
type="text"
onChange={(e) => {
setEditState((prev) => ({ ...prev, name: e.target.value }));
}}
/>
Age:{" "}
<input
type="text"
onChange={(e) => {
setEditState((prev) => ({ ...prev, age: e.target.value }));
}}
/>
<button onClick={onEdit}>Edit node</button>
<div style={{ width: "500px", height: "500px" }}>
<ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} />
</div>
</div>
);
};
export default () => (
<ReactFlowProvider>
<FlowExample />
</ReactFlowProvider>
);
A more helpful example from documentation would be:
https://reactflow.dev/docs/examples/interaction/save-and-restore/
https://reactflow.dev/docs/examples/nodes/update-node/
But you have to remove all the extra information (Also, you can use it to go deeper!)
I managed to come up a solution to create such a custom node that allowed you to input, save and display information. I have tried to include relevant information and the code block I used below.
Custom Node
import { useCallback } from 'react';
import { Handle, Position} from 'react-flow-renderer';
const handleStyle = { left: 10 };
//Custom node requires props of data to be passed to it.
function CustomNode({ data }) {
let serviceType = "offered";
//This handles pressing enter inside the description
const handleKeyDown = (evt) => {
if (evt.key === "Enter") {
//Check if empty string
if (evt.target.value.length !== 0) {
//This code is because services are either offered or borrowed.
if (serviceType === "offered") {
data.serviceOffered.push(evt.target.value);
} else if (serviceType === "borrowed") {
data.serviceBorrowed.push(evt.target.value);
}
//Clearing input after pressing enter
evt.currentTarget.value = "";
}
}
};
const onChange = useCallback((evt) => {
//Update service type without pressing enter
serviceType = evt.target.value;
});
return (
<div className="text-updater-node">
<Handle type="target" position={Position.Top} />
<div>
<p>Entity</p>
<label htmlFor="text"><p className='nodeTitle'>{data.label}</p></label>
<input id="text" name="text" onKeyDown={handleKeyDown} />
<select name="type" onChange={onChange}>
<option value="offered" >Offered </option>
<option value="borrowed">Borrowed</option>
</select>
<div className="info">
{/* This is where the description information is displayed. It checks if it is empty, if not it loops through and displays it. */}
<h2>Service Borrowed</h2>
<ul>
{data.serviceBorrowed.length? data.serviceBorrowed.map(service => (<li key={service}>{service}</li>)) : <span></span>}
</ul>
<h2>Service Offered</h2>
<ul>
{data.serviceOffered.length? data.serviceOffered.map(service => (<li key={service}>{service}</li>)) : <span></span>}
</ul>
</div>
</div>
<Handle type="source" position={Position.Bottom} id="a" style={handleStyle} />
<Handle type="source" position={Position.Bottom} id="b" />
</div>
);
}
export default CustomNode;
I have a parent reactFlow component with the following code block. The important thing about this is to set the custom node type of react flow and pass in an object containing information about the nodes and edges to be rendered.
import { Fragment, useCallback, useState } from "react";
import ReactFlow, {
addEdge,
applyEdgeChanges,
applyNodeChanges,
} from "react-flow-renderer";
import initialNodes from "../data/nodes"; //This both ended up being empty file
import initialEdges from "../data/edges"; //This both ended up being empty file
import CustomNode from "./customNode";
import "./customNode.css";
//Set nodetype as Custom node, IMPORTANT!
const nodeTypes = { customNode: CustomNode };
function Flow() {
const defaultEdgeOptions = { animated: true };
//Input Elements
const [name, setName] = useState("");
const addNode = () => {
setNodes((e) =>
e.concat({
id: (e.length + 1).toString(),
data: { label: `${name}`, serviceOffered: [], serviceBorrowed: [] },
position: { x: 0, y: 0 },
type: "customNode",
})
);
};
//Nodes and edges containing information of the nodes and edges
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
//Boiler plate code for reactFlow
const onNodesChange = useCallback(
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
[setNodes]
);
const onEdgesChange = useCallback(
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
[setEdges]
);
const onConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges]
);
return (
<Fragment>
<Row>
<Col lg={9}>
<ReactFlow
className="Canvas mt-1 border border-secondary rounded"
nodes={nodes} //Node information is passed here
edges={edges} //Edges information is passed here
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
defaultEdgeOptions={defaultEdgeOptions}
style={{ width: "100%", height: "80vh" }}
fitView
nodeTypes={nodeTypes}
/>
</Col>
</Row>
</Fragment>
);
}
export default Flow;
I added more information inside the data property of my node.js. It ended up being initialize as empty but this template should be helpful in understanding how I saved the information for the node. The edge followed the standard format shown on react-flow documentation.
export default [
// {
// id: '1',
// type: 'customNode',
// data: { label: 'Input Node', info: [{id:1, action:"Everything is burning"}, {id:2, action:"I'm fine"}], noOfActions:2 },
// position: { x: 250, y: 25 },
// },
];
I hope this has been useful!
Accepted answer is about modifying properties of components which is not React way. That code may break easily.
There are other ways to bring callback to custom nodes.
Put callback into node's data
This is from React flow documentation: https://reactflow.dev/docs/examples/nodes/custom-node/
setNodes([
...
{
id: '2',
type: 'selectorNode',
data: { onChange: onChange, color: initBgColor },
...
Cons: you need pay extra attention when you modify or create new nodes dynamically
or Define custom types dynamically
In this approach, you keep node data and behavior concerns separate.
I'm using TypeScript in order to show types of data we operate along the way.
First, you extend your custom node properties with your callback:
import {NodeProps} from "react-flow-renderer/dist/esm/types/nodes";
// by default, custom node is provisioned with NodeProps<T>
// we extend it with additional property
export type CustomNodeProps = NodeProps<CustomData> & {
onClick: (id: string) => void
}
function CustomNode(props: CustomNodeProps) {
return <button onClick={() => props.onClick(props.id)}>Do it</button>
}
Then you create new constructor that provides callback and put it into custom nodes mapping using memoization:
function Flow() {
const [graph, dispatchAction] = useReducer(...);
...
// useMemo is neccessary https://reactflow.dev/docs/guides/troubleshooting/#it-looks-like-you-have-created-a-new-nodetypes-or-edgetypes-object-if-this-wasnt-on-purpose-please-define-the-nodetypesedgetypes-outside-of-the-component-or-memoize-them
const nodeTypes = useMemo(() => {
return {
custom: (props: NodeProps<CustomData>) => {
return CustomNode({...props, onClick: (id: string) => {
dispatchAction({
type: 'customNodeButtonClicked',
nodeId: id,
})
}})
}
}
}, [])
return (
<>
<ReactFlow nodeTypes={nodeTypes} ... />
</>
);
}

How to make all process entries in History button using typescript

Is that possible to fetch data or using function useEffect..I have tried all the way. any suggestion?**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
This is my processes.tsx file.
import React, { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { Link, RouteComponentProps, useHistory, withRouter } from 'react-router-dom';
import { People } from '#microsoft/mgt-react';
import { checkPermission } from '../../../config/permission-utils';
import { RootState } from '../../../config/store';
import { getDateFormatted, getQueryParams } from '../../../config/utils';
import { Modal } from '../../../components';
import __ from '../../../lang';
import {
addProcessAction,
clearSelectProcessAction,
deleteProcessAction,
makeProcessVersionAction,
searchProcessesAction,
selectProcessAction,
selectProcessByIdAction,
setMetaAction,
shareProcessAction,
updateProcessAction,
} from '../../../store/actions/process-actions';
import { addProcessInstanceAction, fetchModelingInstances } from '../../../store/actions/process-instance-actions';
import { Role, Department, Process } from '../../../ts/interfaces';
import { ProcessFilter } from '../process-filter';
import { ProcessForm } from './process-form';
import { SendForm } from './send-form';
import {
DetailsList,
DetailsListLayoutMode,
Selection,
SelectionMode,
IColumn,
IconButton,
PrimaryButton,
Text,
Stack,
TooltipHost,
DirectionalHint,
ActionButton,
ButtonType,
IDetailsRowStyles,
IDetailsListProps,
DetailsRow,
Spinner,
SpinnerSize,
} from '#fluentui/react';
import { Popover } from '../../../components';
import { getStyles, gridStyles } from './processes-styles';
import { ProcessActionsMenu } from './process-actions-menu';
import { useWindowSize } from '../../../hooks';
import { ProcessVersionsHistory } from '../../process-details/history/versions';
const Processes = (props: RouteComponentProps & PropsFromRedux) => {
const {
ProcessReducer: { processes, selected_process },
ProcessGroupReducer: { processgroups },
DepartmentReducer: { departments },
RoleReducer: { roles },
UserReducer,
location: { search },
selectProcessByIdAction,
clearSelectProcessAction,
selectProcessAction,
addProcessAction,
updateProcessAction,
shareProcessAction,
fetchModelingInstances,
addProcessInstanceAction,
makeProcessVersionAction,
deleteProcessAction,
searchProcessesAction,
} = props;
const [filterVisible, setFilterVisible] = useState(false);
const [modalVisible, setModalVisible] = useState(false);
const [sendVisible, setSendVisible] = useState(false);
const [enableDelete, setEnableDelete] = useState<boolean>(false);
const [selectedProcesses, setSelectedProcesses] = useState<Process[]>([]);
const [showSpinner, setShowSpinner] = useState<boolean>(false);
const [width] = useWindowSize({ checkDocumentSize: true });
const processesStyles = getStyles(width);
const [showHistoryModal, setShowHistoryModal] = useState<boolean>(false);
const history = useHistory();
const [selectedProcessId, setSelectedProcessId] = useState<number>();
const _rowsSelected: Selection = new Selection({
onSelectionChanged: () => _getSelectionDetails(),
});
const _getSelectionDetails = () => {
const selectionCount = _rowsSelected.getSelectedCount();
if (selectionCount > 0) {
setSelectedProcesses(_rowsSelected.getSelection() as Process[]);
setEnableDelete(true);
} else {
setSelectedProcesses([]);
setEnableDelete(false);
}
};
const columns: IColumn[] = [
{
key: 'process_name',
name: __('process'),
fieldName: 'process_name',
minWidth: 90,
maxWidth: 90,
isResizable: true,
onRender: (record: Process) =>
record && (
<Link className={processesStyles.cellText} to={`/process-management/processes/${record.id}`}>
{record.process_name}
</Link>
),
},
{
name: __('version'),
fieldName: 'version_number',
key: 'version_number',
minWidth: 30,
maxWidth: 60,
isResizable: true,
onRender: ({ version_number }: Process) => <div className={processesStyles.cellText}>{version_number}</div>,
},
{
name: __('process group'),
fieldName: 'group',
key: 'group',
minWidth: 90,
maxWidth: 120,
isResizable: true,
className: processesStyles.cellText,
onRender: (record: Process) =>
record.group && record.group.group_name.trim() !== '' ? (
<div className={processesStyles.cellText}>{record.group.group_name}</div>
) : (
<>
{
<div className="warning-icon blink">
<IconButton iconProps={{ iconName: 'Warning' }} onClick={() => onProcessEdit(record)} />
</div>
}
</>
),
},
{
name: __('department'),
fieldName: 'department',
key: 'department',
minWidth: 90,
maxWidth: 120,
isResizable: true,
onRender: (record: Process) =>
record.department.length > 0 ? (
record.department.map((item: Department, i: number) => (
<div className={processesStyles.cellText}>
{item.department_name}
{i < record.department.length - 1 ? ', ' : ''}
</div>
))
) : (
<div className="warning-icon blink">
<IconButton iconProps={{ iconName: 'Warning' }} onClick={() => onProcessEdit(record)} />
</div>
),
},
{
name: __('created at'),
fieldName: 'date_created',
key: 'date_created',
minWidth: 90,
maxWidth: 120,
isResizable: true,
onRender: ({ date_created }: Process) => (
<div className={processesStyles.cellText}>{date_created && getDateFormatted(date_created, 'lll')}</div>
),
},
{
name: __('location'),
fieldName: 'location',
key: 'location',
minWidth: 90,
maxWidth: 120,
isResizable: true,
onRender: ({ location }: Process) => <div className={processesStyles.cellText}>{location}</div>,
},
{
name: __('process owner'),
fieldName: 'process_owner',
key: 'process_owner',
minWidth: 90,
maxWidth: 120,
isResizable: true,
onRender: ({ process_owner, id }: Process) =>
process_owner && process_owner.length ? renderPersonsWithPopover(process_owner, id, 'process_owner') : '',
},
{
name: __('created by'),
fieldName: 'created_by',
key: 'created_by',
minWidth: 90,
maxWidth: 120,
isResizable: true,
onRender: ({ created_by }: Process) => created_by && <People userIds={created_by.username.split(',')}></People>,
},
{
name: __('sent to recording'),
fieldName: 'send_to',
key: 'send_to',
minWidth: 90,
maxWidth: 180,
onRender: ({ send_to, id }: Process) =>
send_to && send_to.length ? renderPersonsWithPopover(send_to, id, 'send_to') : '',
},
{
name: __('status'),
fieldName: 'status',
key: 'status',
minWidth: 200,
maxWidth: 200,
onRender: (record: Process) => {
return (
<>
<Stack wrap horizontal>
<Stack.Item>
<div className={processesStyles.tagStyles} style={{ background: record.status.color }}>
<Text variant={'smallPlus'}>{__(record.status.project_status_name)}</Text>
</div>
</Stack.Item>
<Stack.Item>
{record.status &&
checkPermission(UserReducer.permissions, 'change_processinstance') &&
record.status.project_status_name === 'in-process recording' && (
<TooltipHost content={__('view the process review')} directionalHint={DirectionalHint.bottomCenter}>
<Link to={`/process-management/processes/${record.id}/applications`}>
<IconButton iconProps={{ iconName: 'SingleColumnEdit' }} />
</Link>
</TooltipHost>
)}
{record.status &&
checkPermission(UserReducer.permissions, 'add_process') &&
(record.status.project_status_name === 'done' || record.status.project_status_name === 'rejected') &&
!hasCopiedProcess(record) && (
<Popover
content={__('are you sure to copy this process?')}
target={`process-${record.id}`}
enableConfirm={true}
onOk={() => onMakeVersion(record)}
>
<TooltipHost content={__('make new version')} directionalHint={DirectionalHint.bottomCenter}>
<IconButton id={`process-${record.id}`} iconProps={{ iconName: 'Copy' }} />
</TooltipHost>
</Popover>
)}
</Stack.Item>
</Stack>
</>
);
},
},
{
name: '',
key: 'actions',
minWidth: 30,
maxWidth: 30,
onRender: (record: Process) => {
const actions = [];
if (record.status && checkPermission(UserReducer.permissions, 'change_process')) {
{
(record.status.project_status_name === 'in-process recording' ||
record.status.project_status_name === 'new') &&
actions.push(
<TooltipHost content={__('edit process')} directionalHint={DirectionalHint.bottomCenter}>
<IconButton onClick={() => onProcessEdit(record)} iconProps={{ iconName: 'Edit' }} />
</TooltipHost>,
);
}
}
return actions;
},
},
];
useEffect(() => {
clearSelectProcessAction();
}, []);
here we can make something different..
useEffect(() => {
getProcesses();
}, [search]);
const getProcesses = () => {
const query =
search === '' ? '?order_by=-date_created&outdated=false' : `${search}&order_by=-date_created&outdated=false`;
searchProcessesAction(query);
};
/**
* checks if
* #param record a process in the process list
* #returns
*/
const hasCopiedProcess = (record: Process): boolean => {
const unDoneCopy = processes.find((process) => {
if (process && !process.root_version) {
return false;
}
return (
(process?.root_version?.id === record.id || process?.root_version?.id === record?.root_version?.id) &&
process.status.project_status_name !== 'done'
);
});
return unDoneCopy ? true : false;
};
const showProcessModal = () => {
selectProcessByIdAction(0);
setModalVisible(true);
};
const onProcessSend = (item: Process): void => {
selectProcessByIdAction(item.id);
setSendVisible(true);
};
const mapRaciFields = (process: any) => {
let { accountable, consulted, informed, responsible } = process;
// here a RACIField is overwritten bei {departments:string[]; roles:string[]; employees[string]}. Should be improved to be more readable
const fields = [accountable, consulted, informed, responsible];
[accountable, consulted, informed, responsible] = fields.map((field) => {
if (field) {
return {
departments: field.departments && field.departments.map((i: Department) => i.resource_uri),
roles: field.roles && field.roles.map((i: Role) => i.resource_uri),
employees: field.employees,
};
} else {
return null;
}
});
return [accountable, consulted, informed, responsible];
};
const startModeling = (process: Process) => {
fetchModelingInstances(process.id, (res: any) => {
if (res.data.objects.length) {
const redirect = `/process-management/processes/${res.data.objects[0].id}/modeling-tool/`;
history.push(redirect);
} else {
const { resource_uri, description, process_name } = process;
const [accountable, consulted, informed, responsible] = mapRaciFields(process);
const data = [
{
responsible: responsible ? { ...responsible, id: null } : null,
accountable: accountable ? { ...accountable, id: null } : null,
informed: informed ? { ...informed, id: null } : null,
consulted: consulted ? { ...consulted, id: null } : null,
source_process: resource_uri,
description: description ? description : null,
instance_name: process_name,
is_in_modeling: true,
is_sent: true,
},
];
addProcessInstanceAction({ objects: data }, (res: any) => {
const redirect = `/process-management/processes/${res.data.objects[0].id}/modeling-tool/`;
history.push(redirect);
});
}
});
};
//------------------
const onMakeVersion = (record: Process) => {
if (record.approved_by) {
delete record.approved_by;
}
setShowSpinner(true);
makeProcessVersionAction(record, (res) => {
setShowSpinner(false);
getProcesses();
});
};
const onProcessEdit = (item: Process) => {
selectProcessByIdAction(item.id);
setModalVisible(true);
};
const onDeleteProcesses = () => {
for (const process of selectedProcesses) {
deleteProcessAction(process);
}
getProcesses();
setEnableDelete(false);
};
const renderPersonsWithPopover = (persons: string, id: number, columnName: string) => {
const peopleArray = (persons && persons.split(',')) || [];
const popoverContent = peopleArray?.length > 3 ? getPopoverContent(peopleArray) : null;
return [
popoverContent ? (
<Popover content={popoverContent} target={`${columnName}-${id}`}>
<People id={`${columnName}-${id}`} userIds={peopleArray} showMax={3}></People>
</Popover>
) : (
<People userIds={peopleArray} showMax={3}></People>
),
];
};
const getPopoverContent = (peopleArray: string[]) => {
return <People userIds={peopleArray.slice(3)} showMax={peopleArray.length - 3}></People>;
};
const showProcessInstances = (id: number) => {
setSelectedProcessId(id);
};
const renderProcessesBtns = () => {
return (
<div className={processesStyles.btnsHolderContainer}>
<div className={processesStyles.btnsHolder}>
<Stack horizontal>
{selectedProcesses.length === 1 && (
<div className={processesStyles.processActions}>
<ProcessActionsMenu
UserReducer={UserReducer}
process={selectedProcesses[0]}
sendProcess={() => onProcessSend(selectedProcesses[0])}
// startModelling={() => onStartModeling(selectedProcesses[0])}
startModeling={() => startModeling(selectedProcesses[0])}
/>
</div>
)}
{enableDelete && checkPermission(UserReducer.permissions, 'delete_process') && (
<Popover
title={__('delete selected processes')}
content={__('are you sure to delete this processes?')}
target={'delete-processes'}
enableConfirm={true}
onOk={() => onDeleteProcesses()}
>
<ActionButton
id="delete-processes"
iconProps={{ iconName: 'Delete' }}
style={{ margin: '5px', float: 'right' }}
buttonType={ButtonType.default}
>
{__('delete')}
</ActionButton>
</Popover>
)}
{
<TooltipHost content={__('filter processes')} directionalHint={DirectionalHint.bottomCenter}>
<ActionButton
iconProps={{ iconName: 'Filter' }}
style={{ margin: '5px', float: 'right' }}
onClick={() => setFilterVisible(true)}
/>
</TooltipHost>
}
{
<TooltipHost content={__('History')} directionalHint={DirectionalHint.bottomCenter}>
<ActionButton
iconProps={{ iconName: 'History' }}
style={{ margin: '5px', float: 'right' }}
onClick={() => setShowHistoryModal(true)}
/>
{showHistoryModal && (
<Modal
title={__('history')}
isModalOpen={showHistoryModal}
hideFooter={true}
onCancel={() => {
setShowHistoryModal(false);
}}
>
<ProcessVersionsHistory selected_process={selected_process} showProcessInstances={showProcessInstances} />
</Modal>
)}
</TooltipHost>
}
{checkPermission(UserReducer.permissions, 'add_process') && (
<PrimaryButton
onClick={() => showProcessModal()}
style={{ margin: '5px', float: 'right' }}
iconProps={{ iconName: 'Add' }}
>
{__('new')}
</PrimaryButton>
)}
</Stack>
</div>
<div className={processesStyles.clear}></div>
</div>
);
};
const _onRenderRow: IDetailsListProps['onRenderRow'] = (props) => {
const customStyles: Partial<IDetailsRowStyles> = {};
if (props) {
customStyles.root = {
zIndex: 0,
transition: 'z-index 2s',
'&:hover': {
zIndex: 1000,
},
};
return <DetailsRow {...props} styles={customStyles} />;
}
return null;
};
return (
<>
{renderProcessesBtns()}
<div className={processesStyles.tableWrapper}>
<Stack className={processesStyles.table}>
<DetailsList
items={processes}
columns={columns}
selectionMode={SelectionMode.multiple}
setKey="none"
layoutMode={DetailsListLayoutMode.justified}
isHeaderVisible={true}
selection={_rowsSelected}
onRenderRow={_onRenderRow}
styles={gridStyles}
/>
</Stack>
</div>
{filterVisible && <ProcessFilter filterVisible={filterVisible} setFilterVisible={setFilterVisible} />}
{modalVisible && (
<ProcessForm
visible={modalVisible}
setVisible={setModalVisible}
add={addProcessAction}
update={updateProcessAction}
select={selectProcessAction}
selected={selected_process}
departments={departments}
roles={roles}
groups={processgroups}
UserReducer={UserReducer}
/>
)}
{sendVisible && selected_process && (
<SendForm
visible={sendVisible}
setVisible={setSendVisible}
select={selectProcessAction}
selected={selected_process}
departments={departments}
roles={roles}
send={shareProcessAction}
afterSend={() => getProcesses()}
mapRaciFields={mapRaciFields}
/>
)}
{showSpinner && (
<div className={processesStyles.spinnerOverlay}>
<Spinner size={SpinnerSize.large} className={processesStyles.spinner} />
</div>
)}
</>
);
};
type PropsFromRedux = ConnectedProps<typeof connector>;
const mapStateToProps = ({
UserReducer,
ProcessReducer,
ProcessGroupReducer,
StatusReducer,
DepartmentReducer,
RoleReducer,
}: RootState) => ({
UserReducer,
ProcessReducer,
ProcessGroupReducer,
StatusReducer,
DepartmentReducer,
RoleReducer,
});
const connector = connect(mapStateToProps, {
setMetaAction,
selectProcessByIdAction,
clearSelectProcessAction,
selectProcessAction,
addProcessAction,
updateProcessAction,
shareProcessAction,
fetchModelingInstances,
addProcessInstanceAction,
makeProcessVersionAction,
deleteProcessAction,
searchProcessesAction,
});
export default connector(withRouter(Processes));
for start and visible model is working but data can not be displayed.

Ant design Transform component extracting selected data

I need to extract selected/filtered data into the state. I tried everything with onChange and on select change but only I got is the ID of one specific item.
ex. extracted_data = [ '1','2','3'....]
But I need a complete Item with id, name, price, etc...
I am passing data as source data, and after selecting I want to send in the parent component because I need to send it on the server.
Code is below
import { Table, Transfer } from "antd";
import difference from "lodash/difference";
import React, { useState } from "react";
// Customize Table Transfer
const TableTransfer = ({ leftColumns, rightColumns, ...restProps }) => (
<Transfer {...restProps}>
{({
direction,
filteredItems,
onItemSelectAll,
onItemSelect,
selectedKeys: listSelectedKeys,
disabled: listDisabled,
}) => {
const columns = direction === "left" ? leftColumns : rightColumns;
const rowSelection = {
getCheckboxProps: (item) => ({
disabled: listDisabled || item.disabled,
}),
onSelectAll(selected, selectedRows) {
const treeSelectedKeys = selectedRows
.filter((item) => !item.disabled)
.map(({ key }) => key);
const diffKeys = selected
? difference(treeSelectedKeys, listSelectedKeys)
: difference(listSelectedKeys, treeSelectedKeys);
onItemSelectAll(diffKeys, selected);
},
onSelect({ key }, selected) {
onItemSelect(key, selected);
},
selectedRowKeys: listSelectedKeys,
};
return (
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={filteredItems}
size="small"
style={{
pointerEvents: listDisabled ? "none" : undefined,
}}
onRow={({ key, disabled: itemDisabled }) => ({
onClick: () => {
if (itemDisabled || listDisabled) return;
onItemSelect(key, !listSelectedKeys.includes(key));
},
})}
/>
);
}}
</Transfer>
);
const leftTableColumns = [
{
dataIndex: "name",
title: "Name",
},
{
dataIndex: "price",
title: "Price (€)",
},
{
dataIndex: "discount",
title: "Discount (%)",
},
];
const rightTableColumns = [
{
dataIndex: "name",
title: "Name",
},
{
dataIndex: "price",
title: "Price",
},
];
const App = ({ data, func }) => {
const mockData = data.map((item) => ({
key: item.id.toString(),
name: item.name,
price: item.price,
discount: item.discount,
}));
const originTargetKeys = mockData.map((item) => item.key);
const [targetKeys, setTargetKeys] = useState(originTargetKeys);
const [selected, setSelected] = useState([]);
const onSelectChange = (e) => {
setSelected(e);
};
const onChange = (e) => {
setTargetKeys(e);
func(selected);
};
return (
<>
<TableTransfer
dataSource={mockData}
targetKeys={targetKeys}
disabled={false}
showSearch={true}
onChange={onChange}
onSelectChange={onSelectChange}
filterOption={(inputValue, item) =>
item.name.indexOf(inputValue) !== -1
}
leftColumns={leftTableColumns}
rightColumns={rightTableColumns}
/>
</>
);
};
export default App;

How to render only 5 items in react autosuggest?

I'am using react autosuggest npm package to get the json data and display it. I want to display only 5 items. How to do it?
Form.js
import React from 'react'
import Autosuggest from 'react-autosuggest';
import cities from 'cities.json';
const getSuggestions = value => {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
// Here I get data from cities.json
return inputLength === 0 ? [] : cities.filter(lang =>
lang.name.toLowerCase().slice(0, inputLength) === inputValue
);
);
};
const getSuggestionValue = suggestion => suggestion.name;
const renderSuggestion = suggestion => (
<div>
{console.log('suggestion', suggestion)}
{suggestion.name}
</div>
);
class Form extends React.Component {
constructor() {
super();
this.state = {
value: '',
suggestions: []
};
}
onChange = (event, { newValue }) => {
this.setState({
value: newValue
});
};
onSuggestionsFetchRequested = ({ value }) => {
this.setState({
suggestions: getSuggestions(value)
});
};
onSuggestionsClearRequested = () => {
this.setState({
suggestions: []
});
};
render(){
const { value, suggestions } = this.state;
// Autosuggest will pass through all these props to the input.
const inputProps = {
placeholder: 'Search City...',
value,
onChange: this.onChange
};
return (
<div>
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
/>
<br/>
</div>
)
}
}
export default Form;
I want to render only 5 items, otherwise, computer hangs while loading huge data. Is there any other autocomplete react npm package, since I want only cities and country list. i.e when city is inputted, automatically the city name must be suggested with its relevant country.Any solution or suggestion highly appreciated. Thanks in advance
i modified you're getSuggestions() method a little i guess this should work for you.
const getSuggestions = value => {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
// Here I get data from cities.json
return inputLength === 0 ? [] : cities.filter(lang =>
lang.name.toLowerCase().slice(0, inputLength) === inputValue
).slice(0,5);
};
Use the Slice method with start index and last Index
suggestions={suggestions.slice(0, 5)}
import {
React
,Avatar
,axiosbase
} from '../../import-files';
import Autosuggest from 'react-autosuggest';
import './autosuggest.css';
import { withStyles } from '#material-ui/core/styles';
import TextField from '#material-ui/core/TextField';
import Paper from '#material-ui/core/Paper';
import MenuItem from '#material-ui/core/MenuItem';
let suggestions = [ { label: 'Afghanistan' } ];
function renderInputComponent(inputProps) {
const { classes, inputRef = () => {}, ref, ...other } = inputProps;
return (
<TextField
className={classes.textField}
fullWidth
variant="outlined"
InputProps={{
inputRef: node => {
ref(node);
inputRef(node);
},
classes: {
input: classes.input,
},
}}
{...other}
/>
);
}
function renderSuggestion(suggestion, { query, isHighlighted }) {
return (
<MenuItem selected={isHighlighted} component="div">
<div>
<strong key={String(suggestion.id)} style={{ fontWeight: 300 }}>
<span className="sugg-option">
<span className="icon-wrap">
<Avatar src={suggestion.Poster}></Avatar>
</span>
<span className="name">
{suggestion.Title}
</span>
</span>
</strong>
</div>
</MenuItem>
);
}
function initSuggestions(value) {
suggestions = value;
}
function getSuggestionValue(suggestion) {
return suggestion.Title;
}
function onSuggestionSelected(event, { suggestion, suggestionValue, suggestionIndex, sectionIndex, method }) {
console.log('HandleSuggestion() '+suggestionValue);
}
const styles = theme => ({
root: {
height: 50,
flexGrow: 1,
},
container: {
position: 'relative',
},
suggestionsContainerOpen: {
position: 'absolute',
zIndex: 998,
marginTop: theme.spacing.unit,
left: 0,
right: 0,
overflowY: 'scroll',
maxHeight:'376%'
},
suggestion: {
display: 'block',
},
suggestionsList: {
margin: 0,
padding: 0,
listStyleType: 'none',
},
divider: {
height: theme.spacing.unit * 2,
},
});
class IntegrationAutosuggest extends React.Component {
state = {
single: '',
popper: '',
suggestions: [],
};
componentDidMount() {
initSuggestions(suggestions);
}
// Filter logic
getSuggestions = async (value) => {
const inputValue = value.trim().toLowerCase();
var _filter = JSON.stringify({
filter : inputValue,
});
return await axiosbase.post(`${apiCall}`, _filter);
};
handleSuggestionsFetchRequested = ({ value }) => {
this.getSuggestions(value)
.then(data => {
if (data.Error) {
this.setState({
suggestions: []
});
} else {
const responseData = [];
data.data.itemsList.map((item, i) => {
let File = {
id: item.idEnc,
Title: item.englishFullName +' '+item.arabicFullName,
englishFullName: item.englishFullName,
arabicFullName: item.arabicFullName,
Poster: item.photoPath,
}
responseData.push(File);
});
this.setState({
suggestions: responseData
});
}
})
};
handleSuggestionsClearRequested = () => {
this.setState({
suggestions: [],
});
};
handleChange = name => (event, { newValue }) => {
this.setState({
[name]: newValue,
});
if(event.type=='click'){
if(typeof this.props.handleOrderUserFirstNameChange === "function"){
this.props.handleOrderUserFirstNameChange(newValue);
}
this.state.suggestions.filter(f=>f.Title===newValue).map((item, i) => {
//id
//Title
// Poster
if(typeof this.props.handleUserIDChange === "function"){
this.props.handleUserIDChange(item.id);
}
});
}
};
render() {
const { classes } = this.props;
// console.log('Re-render!!');
// console.log(this.props);
// console.log(this.state.suggestions);
const autosuggestProps = {
renderInputComponent,
suggestions: this.state.suggestions,
onSuggestionsFetchRequested: this.handleSuggestionsFetchRequested,
onSuggestionsClearRequested: this.handleSuggestionsClearRequested,
onSuggestionSelected: this.props.onSelect,
getSuggestionValue,
renderSuggestion,
};
return (
<div className={classes.root}>
<Autosuggest
{...autosuggestProps}
inputProps={{
classes,
placeholder: this.props.placeHolder,
value: this.state.single,
onChange: this.handleChange('single'),
}}
theme={{
container: classes.container,
suggestionsContainerOpen: classes.suggestionsContainerOpen,
suggestionsList: classes.suggestionsList,
suggestion: classes.suggestion,
}}
renderSuggestionsContainer={options => (
<Paper {...options.containerProps} square>
{options.children}
</Paper>
)}
/>
<div className={classes.divider} />
</div>
);
}
}
export default withStyles(styles)(IntegrationAutosuggest);

How to do search in table?

I want to search with all the pagination and sorter field on place.
That is i want to call handleChange with searchkeyword.
So how can i call handleSearch and than call handleChange from within handleSearch?
import React from "react";
import { withRouter } from "react-router-dom";
import { Table, Button, Icon, Row, Col, Input } from "antd";
import axios from "axios";
const Search = Input.Search;
class App extends React.Component {
state = {
data: [],
searchValue: "",
loading: false,
visible: false,
pagination: {}
};
componentDidMount() {
this.fetch();
}
handleTableChange = (pagination, filter, sorter, value) => {
console.log(pagination, value, sorter, "Table Change");
let sorterOrder = "";
let sorterField = "";
let searchVal = "";
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager
});
if (value) {
console.log("inside if");
searchVal = undefined;
} else {
console.log("inside else");
searchVal = value;
}
if (sorter) {
if (sorter.order === "ascend") {
sorterOrder = "ASC";
}
if (sorter.order === "descend") {
sorterOrder = "DESC";
}
sorterField = sorter.field;
}
this.fetch({
page: pagination.current,
sortField: sorterField,
sortOrder: sorterOrder,
...filter,
value: searchVal
});
};
fetch = (params = {}) => {
this.setState({ loading: true });
axios.post("***/****", params).then(res => {
const pagination = { ...this.state.pagination };
let apiData = res.data.result;
if (res.data.status === 1) {
const objects = apiData.map(row => ({
key: row.id,
id: row.id,
firstName: row.firstName,
lastName: row.lastName,
status: row.status,
email: row.email
}));
console.log(res.data);
pagination.total = res.data.count;
this.setState({
loading: false,
data: objects,
pagination
});
} else {
console.log("Database status is not 1!");
}
});
};
handleSearch = value => {
console.log("value", value);
this.setState({
searchValue: value
});
let searchkey = this.state.searchValue;
const pagination = { ...this.state.pagination };
const sorter = { ...this.state.sorter };
console.log("search", value, pagination, sorter);
this.handleTableChange({
value
});
};
render() {
const columns = [
{
title: "First Name",
dataIndex: "firstName",
sorter: true
},
{
title: "Email",
dataIndex: "email",
sorter: true
}
];
return (
<div>
<Search
placeholder="input search text"
className="searchBut"
onSearch={value => this.handleSearch(value)}
/>
<Button
className="addBut"
style={{ marginTop: "0" }}
type="primary"
onClick={() => this.openForm()}
>
+ Add Admin
</Button>
</div>
<Table
bordered
columns={columns}
dataSource={this.state.data}
pagination={{ total: this.state.pagination.total, pageSize: 4 }}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
);
}
}
export default withRouter(App);
here when i give value in search field it will call post request with request payload as follows:
{sortField: "", sortOrder: ""}
sortField: ""
sortOrder: ""
So how can i do that?
I'm not sure what you trying of achieve it here.
But you can always filter the source data of the table. Like following
<Table
bordered
columns={columns}
dataSource={this.state.data.filter(data=> Object.keys(data).filter(key => data[key].includes(searchValue)).length > 0 ? true: false)}
pagination={{ total: this.state.pagination.total, pageSize: 4 }}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
let me know if it helps.

Resources