Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
242 changes: 99 additions & 143 deletions samples/interactions/query-builder/overview/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import { useRef, useEffect } from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import {
Expand All @@ -24,151 +24,66 @@ interface Entity {
fields: Field[];
}

interface SampleState {
expressionTree: IgrExpressionTree | null;
}

export default class Sample extends React.Component<any, SampleState> {
private queryBuilderRef: React.RefObject<IgrQueryBuilder>;
private gridRef: React.RefObject<IgrGrid>;

constructor(props: any) {
super(props);

this.queryBuilderRef = React.createRef();
this.gridRef = React.createRef();

this.state = {
expressionTree: null
};
}

componentDidMount() {
// Initialize expression tree
const tree = new IgrFilteringExpressionsTree();
tree.operator = FilteringLogic.And;
tree.entity = 'Orders';
tree.returnFields = [
'orderId',
'customerId',
'employeeId',
'shipperId',
'orderDate',
'requiredDate',
'shipVia',
'freight',
'shipName',
'completed'
];

this.setState({ expressionTree: tree });

// Set up query builder
if (this.queryBuilderRef.current && tree) {
const queryBuilder = this.queryBuilderRef.current;
queryBuilder.entities = this.entities as any;
queryBuilder.expressionTree = tree;

queryBuilder.addEventListener('expressionTreeChange', this.handleExpressionTreeChange);
}

// Set up grid
if (this.gridRef.current) {
const grid = this.gridRef.current;
grid.height = '420px';
grid.autoGenerate = true;
}
}

componentDidUpdate(prevProps: any, prevState: any) {
// Fetch data when expression tree changes
if (prevState.expressionTree !== this.state.expressionTree && this.state.expressionTree) {
this.fetchData();
}

// Update query builder if expression tree changed
if (this.queryBuilderRef.current && this.state.expressionTree &&
prevState.expressionTree !== this.state.expressionTree) {
const queryBuilder = this.queryBuilderRef.current;
queryBuilder.expressionTree = this.state.expressionTree;
}
}

componentWillUnmount() {
if (this.queryBuilderRef.current) {
this.queryBuilderRef.current.removeEventListener('expressionTreeChange', this.handleExpressionTreeChange);
}
}

private handleExpressionTreeChange = (event: any) => {
this.setState({ expressionTree: event.detail });
};

private get customersFields(): Field[] {
return [
{ field: 'customerId', dataType: 'string' },
{ field: 'companyName', dataType: 'string' },
{ field: 'contactName', dataType: 'string' },
{ field: 'contactTitle', dataType: 'string' }
];
}

private get ordersFields(): Field[] {
return [
{ field: 'orderId', dataType: 'number' },
{ field: 'customerId', dataType: 'string' },
{ field: 'employeeId', dataType: 'number' },
{ field: 'shipperId', dataType: 'number' },
{ field: 'orderDate', dataType: 'date' },
{ field: 'requiredDate', dataType: 'date' },
{ field: 'shipVia', dataType: 'string' },
{ field: 'freight', dataType: 'number' },
{ field: 'shipName', dataType: 'string' },
{ field: 'completed', dataType: 'boolean' }
];
}

private get entities(): Entity[] {
return [
{ name: 'Customers', fields: this.customersFields },
{ name: 'Orders', fields: this.ordersFields }
];
}

private calculateColumnsInView = () => {
if (!this.gridRef.current || !this.state.expressionTree) return;

const grid = this.gridRef.current;
const expressionTree = this.state.expressionTree;
const returnFields = expressionTree.returnFields ?? [];
const customersFields: Field[] = [
{ field: 'customerId', dataType: 'string' },
{ field: 'companyName', dataType: 'string' },
{ field: 'contactName', dataType: 'string' },
{ field: 'contactTitle', dataType: 'string' }
];

const ordersFields: Field[] = [
{ field: 'orderId', dataType: 'number' },
{ field: 'customerId', dataType: 'string' },
{ field: 'employeeId', dataType: 'number' },
{ field: 'shipperId', dataType: 'number' },
{ field: 'orderDate', dataType: 'date' },
{ field: 'requiredDate', dataType: 'date' },
{ field: 'shipVia', dataType: 'string' },
{ field: 'freight', dataType: 'number' },
{ field: 'shipName', dataType: 'string' },
{ field: 'completed', dataType: 'boolean' }
];

const entities: Entity[] = [
{ name: 'Customers', fields: customersFields },
{ name: 'Orders', fields: ordersFields }
];

function Sample() {
const queryBuilderRef = useRef<IgrQueryBuilder>(null);
const gridRef = useRef<IgrGrid>(null);

const calculateColumnsInView = (tree: IgrExpressionTree) => {
if (!gridRef.current) return;

const grid = gridRef.current;
const returnFields = tree.returnFields ?? [];

if (returnFields.length === 0 || returnFields[0] === '*') {
const selectedEntity = this.entities.find(e => e.name === expressionTree.entity);
const selectedEntity = entities.find(e => e.name === tree.entity);
const selectedEntityFields = (selectedEntity?.fields ?? []).map(f => f.field);
grid.columns.forEach(column => {

grid.columns.forEach((column: any) => {
column.hidden = !selectedEntityFields.includes(column.field);
});
} else {
grid.columns.forEach(column => {
grid.columns.forEach((column: any) => {
column.hidden = !returnFields.includes(column.field);
});
}
};

private async fetchData() {
const grid = this.gridRef.current;
const expressionTree = this.state.expressionTree;

if (!grid || !expressionTree) return;
const fetchData = async (tree: IgrExpressionTree) => {
const grid = gridRef.current;
if (!grid) return;

grid.isLoading = true;

try {
const response = await fetch(`${API_ENDPOINT}/QueryBuilder/ExecuteQuery`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(expressionTree)
body: JSON.stringify(tree)
});

if (!response.ok) {
Expand All @@ -179,32 +94,73 @@ export default class Sample extends React.Component<any, SampleState> {
const data = (Object.values(json)[0] as any[]) ?? [];
grid.data = data;

// Calculate column visibility after data loads
await new Promise(resolve => requestAnimationFrame(() => resolve(null)));
this.calculateColumnsInView();
calculateColumnsInView(tree);
} catch (err) {
console.error(err);
grid.data = [];
} finally {
grid.isLoading = false;
}
}

public render(): JSX.Element {
return (
<div className="container sample ig-typography">
<div className="wrapper">
<IgrQueryBuilder ref={this.queryBuilderRef} id="queryBuilder"></IgrQueryBuilder>

<div className="output-area">
<IgrGrid ref={this.gridRef} id="grid"></IgrGrid>
</div>
};

const handleExpressionTreeChange = (event: any) => {
fetchData(event.detail);
};

useEffect(() => {
const tree = new IgrFilteringExpressionsTree();
tree.operator = FilteringLogic.And;
tree.entity = 'Orders';
tree.returnFields = [
'orderId',
'customerId',
'employeeId',
'shipperId',
'orderDate',
'requiredDate',
'shipVia',
'freight',
'shipName',
'completed'
];

if (gridRef.current) {
gridRef.current.height = '420px';
gridRef.current.autoGenerate = true;
}

if (queryBuilderRef.current) {
const queryBuilder = queryBuilderRef.current;
queryBuilder.entities = entities as any;
queryBuilder.expressionTree = tree;
queryBuilder.addEventListener('expressionTreeChange', handleExpressionTreeChange);
}

fetchData(tree);

return () => {
if (queryBuilderRef.current) {
queryBuilderRef.current.removeEventListener('expressionTreeChange', handleExpressionTreeChange);
}
};
}, []);

return (
<div className="container sample ig-typography">
<div className="wrapper">
<IgrQueryBuilder ref={queryBuilderRef} id="queryBuilder"></IgrQueryBuilder>

<div className="output-area">
<IgrGrid ref={gridRef} id="grid"></IgrGrid>
</div>
</div>
);
}
</div>
);
}

export default Sample;

// rendering above component in the React DOM
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Sample/>);
Loading