Skip to content

Commit

Permalink
Feature/cldn 1968 (Display JSON data inline) (#268)
Browse files Browse the repository at this point in the history
* Add buttons to expand and minimize JSON data as well as ability to expand and/or collapse all rows in a certain column

* [CLDN-1968] Added expand button for full row

* [CLDN-1968] Resize JSON columns

* [CLDN-1968] Added new array which tracks JSON cell state

* Revert "[CLDN-1968] Added new array which tracks JSON cell state"

This reverts commit dabc3da.

* [CLDN-1968] Added ability for row level expand all button to track if cells are expanded or not

* [CLDN-1968] Ran pre-commit hook

* [CLDN-1968] Improved UI

* [CLDN-1968] Update image tag for testing

* [CLDN-1968] Revert image tag for testing

* [CLDN-1968] Added multiple UI/UX changes based on QA feedback

* [CLDN-1968] Added more UI/UX changes based on QA feedback

* [CLDN-1968] Temp change to image

* Revert "[CLDN-1968] Temp change to image"

This reverts commit 57490bd.

* Update superset-frontend/src/cccs-viz/plugins/plugin-chart-cccs-grid/src/CccsGrid.tsx

Co-authored-by: cccs-rc <62034438+cccs-rc@users.noreply.github.com>

* [CLDN-1968] Remove 'TODO's as they are no longer needed

* [CLDN-1968] Changed a variable name, and condensed a few lines

* [CLDN-1968] Modified a setState so that only one is needed instead of 2

---------

Co-authored-by: cccs-rc <62034438+cccs-rc@users.noreply.github.com>
  • Loading branch information
cccs-Dustin and cccs-rc committed Mar 15, 2023
1 parent c088022 commit 592337e
Show file tree
Hide file tree
Showing 14 changed files with 934 additions and 585 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.Button {
background-color: transparent;
border: solid rgb(137, 137, 137);
border-width: 0 2px 2px 0;
display: inline-block;
padding-right: 3px;
padding-left: 3px;
padding-top: 3px;
padding-bottom: 3px;
vertical-align: middle;
margin-right: 10px;
margin-left: 5px;
}

.Expand {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}

.Collapse {
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
}

.Row-Expand {
background-color: transparent;
text-decoration: underline;
vertical-align: middle;
border: none;
color: rgb(31, 167, 201);
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { GroupCellRenderer } from '@ag-grid-enterprise/all-modules';
import React, { Component } from 'react';
import './Buttons.css';

// Show a button to collapse all of the JSON blobs in the row
function collapseJSON(this: any, reverseState: any) {
return (
<button className="Row-Expand" type="button" onClick={reverseState}>
Collapse Row
</button>
);
}

// Show a button to expand all of the JSON blobs in the row
function expandJSON(this: any, reverseState: any) {
return (
<>
<button className="Row-Expand" type="button" onClick={reverseState}>
Expand Row
</button>
</>
);
}

export default class ExpandAllValueRenderer extends Component<
{},
{ api: any; expanded: boolean; rowIndex: number }
> {
constructor(props: any) {
super(props);

this.state = {
api: props.api,
expanded: false,
rowIndex: props.rowIndex,
};
}

// Get all of the cells in the AG Grid and only keep the ones that
// are in the same row as the current expand all button, and make
// sure that they have a JSON blob
getJSONCells = () => {
const instances = this.state.api.getCellRendererInstances();

// Make sure row grouping is not enabled, but if it is, don't
// try to find all of the JSON blobs in the row
if (
instances.filter((instance: any) => instance instanceof GroupCellRenderer)
.length === 0
) {
const newInstances = instances.filter(
(instance: any) =>
instance.params.rowIndex === this.state.rowIndex &&
instance.params.column.colDef.cellRenderer === 'jsonValueRenderer',
);

return newInstances;
}
return [];
};

// Set the current `expanded` field to the opposite of what it currently is
// as well as go through each cell renderer and if it's in the same row &
// it's a cell with a JSON blob, update whether it is expanded or not
reverseState = () => {
this.setState(prevState => ({
...prevState,
expanded: !prevState.expanded,
}));

const newInstances = this.getJSONCells();

newInstances.map((instance: any) =>
instance.componentInstance.updateState(!this.state.expanded),
);
};

// Set the current `expanded` field to be equal to the boolean being passed in
// as well as go through each cell renderer and if it's in the same row &
// it's a cell with a JSON blob, update whether it is expanded or not
updateState = (newFlag: any) => {
this.setState(prevState => ({ ...prevState, expanded: newFlag }));

const newInstances = this.getJSONCells();

newInstances.map((instance: any) =>
instance.componentInstance.updateState(newFlag),
);
};

// Get all of the cells in the AG Grid and only keep the ones
// that are in the same row as the current expand all button and
// make sure that they have a JSON blob (and see whether they are
// expanded or not)
checkState = () => {
const newInstances = this.getJSONCells();

const jsonCellExpandedValues = newInstances.map((instance: any) =>
instance.componentInstance.getExpandedValue(),
);

// If there is at least one cell that can expand, the expand all
// button for the row should show 'Expand'
this.setState(prevState => ({
...prevState,
expanded: !jsonCellExpandedValues.includes(false),
}));
};

// Show either the expand or collapse button dependent
// on the value of the `expanded` field
render() {
if (this.state.expanded === false) {
return expandJSON(this.reverseState);
}
return collapseJSON(this.reverseState);
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,7 @@
import { GroupCellRenderer } from '@ag-grid-enterprise/all-modules';
import React, { Component } from 'react';
import ModalTrigger from 'src/components/ModalTrigger';
import JSONTree from 'react-json-tree';
import Button from 'src/components/Button';
import CopyToClipboard from 'src/components/CopyToClipboard';

const JSON_TREE_THEME = {
scheme: 'monokai',
base00: '#272822',
base01: '#383830',
base02: '#49483e',
base03: '#75715e',
base04: '#a59f85',
base05: '#f8f8f2',
base06: '#f5f4f1',
base07: '#f9f8f5',
base08: '#f92672',
base09: '#fd971f',
base0A: '#f4bf75',
base0B: '#a6e22e',
base0C: '#a1efe4',
base0D: '#66d9ef',
base0E: '#ae81ff',
base0F: '#cc6633',
};
import './Buttons.css';

function safeJsonObjectParse(
data: unknown,
Expand All @@ -48,34 +27,60 @@ function safeJsonObjectParse(
}
}

function addJsonModal(
node: React.ReactNode,
jsonObject: Record<string, unknown> | unknown[],
jsonString: String,
) {
// JSX which shows the JSON tree inline, and a button to collapse it
function collapseJSON(this: any, reverseState: any, jsonObject: any) {
return (
<ModalTrigger
modalBody={<JSONTree data={jsonObject} theme={JSON_TREE_THEME} />}
modalFooter={
<Button>
<CopyToClipboard shouldShowText={false} text={jsonString} />
</Button>
}
modalTitle="Cell content as JSON"
triggerNode={node}
/>
<>
<div style={{ float: 'left' }}>
<button
className="Button Collapse"
type="button"
title="Collapse"
onClick={reverseState}
>
{' '}
</button>
</div>
<div style={{ float: 'left' }}>
<JSONTree
data={jsonObject}
theme="default"
shouldExpandNode={() => true}
/>
</div>
</>
);
}

// JSX which shows the JSON data on one line, and a button to open the JSON tree
function expandJSON(this: any, reverseState: any, cellData: any) {
return (
<>
<button
className="Button Expand"
type="button"
title="Expand"
onClick={reverseState}
>
{' '}
</button>
{cellData}
</>
);
}

export default class JsonValueRenderer extends Component<
{},
{ cellValue: any }
{ api: any; cellValue: any; expanded: boolean; rowIndex: number }
> {
constructor(props: any) {
super(props);

this.state = {
api: props.api,
cellValue: JsonValueRenderer.getValueToDisplay(props),
expanded: false,
rowIndex: props.rowIndex,
};
}

Expand All @@ -86,14 +91,56 @@ export default class JsonValueRenderer extends Component<
};
}

// Set the current `expanded` field to the opposite of what it currently is
// and trigger the 'checkState` function in the expand all button for the row
reverseState = () => {
this.setState(
prevState => ({ ...prevState, expanded: !prevState.expanded }),
() => {
const instances = this.state.api.getCellRendererInstances();

// Make sure row grouping is not enabled, but if it is, don't
// trigger the 'checkState` function in the expand all button for the row
if (
instances.filter(
(instance: any) => instance instanceof GroupCellRenderer,
).length === 0
) {
instances
.filter(
(instance: any) =>
instance.params.rowIndex === this.state.rowIndex &&
instance.params.column.colDef.cellRenderer ===
'expandAllValueRenderer',
)
.map((instance: any) => instance.componentInstance.checkState());
}
},
);
};

// Take the boolean value passed in and set the `expanded` field equal to it
updateState = (newFlag: any) => {
this.setState(prevState => ({ ...prevState, expanded: newFlag }));
};

// Return whether 'expanded' is set to true or false
getExpandedValue = () => this.state.expanded;

render() {
const cellData = this.state.cellValue;
const jsonObject = safeJsonObjectParse(this.state.cellValue);
const cellNode = <div>{cellData}</div>;

// If there is a JSON object, either show it expanded or collapsed based
// on the value which the `expanded` field is set to
if (jsonObject) {
return addJsonModal(cellNode, jsonObject, cellData);
if (this.state.expanded === false) {
return expandJSON(this.reverseState, cellData);
}
return collapseJSON(this.reverseState, jsonObject);
}
return cellData ?? null;
// If the cellData is set to 'null' or undefined, return null
return cellData !== 'null' && cellData !== undefined ? cellData : null;
}

static getValueToDisplay(params: { valueFormatted: any; value: any }) {
Expand Down
Loading

0 comments on commit 592337e

Please sign in to comment.