diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Table/ProgramaticallyHandleProperties.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Table/ProgramaticallyHandleProperties.jsx
index e559369396..c3fb47d612 100644
--- a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Table/ProgramaticallyHandleProperties.jsx
+++ b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Table/ProgramaticallyHandleProperties.jsx
@@ -50,6 +50,8 @@ export const ProgramaticallyHandleProperties = ({
return props?.parseInUnixTimestamp;
case 'isDateSelectionEnabled':
return props?.isDateSelectionEnabled;
+ case 'jsonIndentation':
+ return props?.jsonIndentation;
default:
return;
}
@@ -81,6 +83,9 @@ export const ProgramaticallyHandleProperties = ({
if (property === 'linkColor') {
return definitionObj?.value ?? '#1B1F24';
}
+ if (property === 'jsonIndentation') {
+ return definitionObj?.value ?? `{{true}}`;
+ }
return definitionObj?.value ?? `{{false}}`;
};
@@ -111,7 +116,9 @@ export const ProgramaticallyHandleProperties = ({
const fxActiveFieldsPropExists = props?.hasOwnProperty('fxActiveFields') ?? false;
//to support backward compatibility, when fxActive is true for a particular column, we are passing all possible combinations which should render codehinter
const fxActive =
- props?.fxActive && resolveReferences(props.fxActive) ? ['isEditable', 'columnVisibility', 'linkTarget'] : [];
+ props?.fxActive && resolveReferences(props.fxActive)
+ ? ['isEditable', 'columnVisibility', 'jsonIndentation', 'linkTarget']
+ : [];
const checkFxActiveFieldIsArrray = (fxActiveFieldsProperty) => {
// adding error handling mechanism for fxActiveFieldsProperty , if props.fxActiveFields is array , then return props.fxActiveFields or else return [], this will make sure, fxActiveFields wil always be array
diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Table/Table.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Table/Table.jsx
index 5a2175cfe1..b11a675e80 100644
--- a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Table/Table.jsx
+++ b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Table/Table.jsx
@@ -624,6 +624,8 @@ class TableComponent extends React.Component {
return 'Select';
case 'newMultiSelect':
return 'Multiselect';
+ case 'json':
+ return 'JSON';
default:
capitalize(text ?? '');
}
diff --git a/frontend/src/AppBuilder/Widgets/Table/Json.jsx b/frontend/src/AppBuilder/Widgets/Table/Json.jsx
new file mode 100644
index 0000000000..fcae72459e
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/Table/Json.jsx
@@ -0,0 +1,191 @@
+/* eslint-disable no-undef */
+import React, { useState, useEffect } from 'react';
+import { determineJustifyContentValue } from '@/_helpers/utils';
+import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
+
+const Json = ({
+ isEditable,
+ jsonIndentation,
+ darkMode,
+ handleCellValueChange,
+ cellTextColor,
+ cellValue,
+ column,
+ containerWidth,
+ cell,
+ horizontalAlignment,
+ isMaxRowHeightAuto,
+ cellSize,
+ maxRowHeightValue,
+}) => {
+ const ref = React.useRef(null);
+
+ const [hovered, setHovered] = useState(false);
+ const [isEditing, setIsEditing] = useState(false);
+
+ const cellStyles = {
+ color: cellTextColor ?? 'inherit',
+ };
+
+ useEffect(() => {
+ if (!isEditable && isEditing) {
+ setIsEditing(false);
+ }
+ }, [isEditable]);
+
+ function format(obj) {
+ if (typeof obj !== 'object' || obj === null) {
+ return typeof obj === 'string' ? `"${obj}"` : obj;
+ }
+ if (Array.isArray(obj)) {
+ return `[ ${obj.map(format).join(', ')} ]`;
+ }
+ return `{ ${Object.entries(obj)
+ .map(([key, value]) => `"${key}": ${format(value)}`)
+ .join(', ')} }`;
+ }
+
+ const formatCellValue = (value, overlay = false) => {
+ try {
+ if (typeof value === 'object') {
+ if (jsonIndentation === true && !overlay) {
+ return JSON.stringify(value, null, 4).replace(/":/g, '": ');
+ }
+ const formattedJSON = format(value);
+ return formattedJSON;
+ } else {
+ if (jsonIndentation === true && !overlay) {
+ return JSON.stringify(JSON.parse(value), null, 4).replace(/":/g, '": ');
+ }
+ const formattedJSON = format(JSON.parse(value));
+ return formattedJSON;
+ }
+ } catch (error) {
+ return value;
+ }
+ };
+
+ const _renderString = () => (
+
{
+ setIsEditing(false);
+ if (cellValue !== e.target.textContent) {
+ const value = JSON.stringify(JSON.parse(e.target.textContent.replace(/\n/g, '')));
+ handleCellValueChange(cell.row.index, column.key || column.name, value, cell.row.original);
+ }
+ }}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ ref.current.blur();
+ if (cellValue !== e.target.textContent) {
+ const value = JSON.stringify(JSON.parse(e.target.textContent.replace(/\n/g, '')));
+ handleCellValueChange(cell.row.index, column.key || column.name, value, cell.row.original);
+ }
+ }
+ }}
+ onFocus={(e) => {
+ setIsEditing(true);
+ e.stopPropagation();
+ }}
+ >
+ {String(formatCellValue(cellValue))}
+
+ );
+
+ const getOverlay = () => {
+ return (
+
setHovered(true)}
+ onMouseLeave={() => setHovered(false)}
+ style={{ color: 'var(--text-primary)' }}
+ >
+
+ {String(formatCellValue(cellValue, true))}
+
+
+ );
+ };
+
+ const _showOverlay =
+ ref?.current &&
+ (ref?.current?.clientWidth < ref?.current?.children[0]?.offsetWidth ||
+ ref?.current?.clientHeight < ref?.current?.children[0]?.offsetHeight);
+
+ return (
+ <>
+
}
+ trigger={_showOverlay && ['hover', 'focus']}
+ rootClose={true}
+ show={_showOverlay && hovered && !isEditing}
+ >
+ {!isEditable ? (
+ {
+ if (!hovered) setHovered(true);
+ }}
+ onMouseLeave={() => {
+ setHovered(false);
+ }}
+ ref={ref}
+ >
+
+ {String(formatCellValue(cellValue))}
+
+
+ ) : (
+