This is an automated email from the ASF dual-hosted git repository.

kharekartik pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new c894265b1f Allow raw JSON as input for Add table button in Pinot UI 
(#15647)
c894265b1f is described below

commit c894265b1f65b957b6c0ec44e3c944b5a2dd3f7c
Author: Kartik Khare <kharekar...@gmail.com>
AuthorDate: Mon Apr 28 10:55:26 2025 +0530

    Allow raw JSON as input for Add table button in Pinot UI (#15647)
    
    Co-authored-by: KKCorps <kar...@startee.ai>
---
 .../Homepage/Operations/AddOfflineTableOp.tsx      | 90 ++++++++++++++++++----
 .../Homepage/Operations/AddRealtimeTableOp.tsx     | 89 ++++++++++++++++++---
 2 files changed, 154 insertions(+), 25 deletions(-)

diff --git 
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/AddOfflineTableOp.tsx
 
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/AddOfflineTableOp.tsx
index 0c18dc10e4..03d19226ed 100644
--- 
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/AddOfflineTableOp.tsx
+++ 
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/AddOfflineTableOp.tsx
@@ -18,7 +18,7 @@
  */
 
 import React, { useEffect, useState } from 'react';
-import { createStyles, DialogContent, Grid, makeStyles, Theme} from 
'@material-ui/core';
+import { createStyles, DialogContent, Grid, makeStyles, Theme, Button, 
ButtonGroup } from '@material-ui/core';
 import Dialog from '../../CustomDialog';
 import SimpleAccordion from '../../SimpleAccordion';
 import AddTableComponent from './AddTableComponent';
@@ -46,7 +46,11 @@ const useStyles = makeStyles((theme: Theme) =>
     },
   })
 );
-
+// View modes for simple form or raw JSON editing
+enum EditView {
+  SIMPLE = "SIMPLE",
+  JSON = "JSON"
+}
 type Props = {
   hideModal: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void,
   fetchData: Function,
@@ -130,7 +134,9 @@ export default function AddOfflineTableOp({
   tableType
 }: Props) {
   const classes = useStyles();
+  const [editView, setEditView] = useState<EditView>(EditView.SIMPLE);
   const [tableObj, setTableObj] = 
useState(JSON.parse(JSON.stringify(defaultTableObj)));
+  const [jsonTableObj, setJsonTableObj] = 
useState(JSON.parse(JSON.stringify(defaultTableObj)));
   const [schemaObj, setSchemaObj] = 
useState(JSON.parse(JSON.stringify(defaultSchemaObj)));
   const [tableName, setTableName] = useState('');
   const [columnName, setColumnName] = useState([]);
@@ -150,6 +156,14 @@ export default function AddOfflineTableOp({
   useEffect(()=>{
     setTableObj({...tableObj,"tableType":tableType})
   },[])
+  // Sync state when toggling between simple and JSON view
+  useEffect(() => {
+    if (editView === EditView.JSON) {
+      setJsonTableObj(JSON.parse(JSON.stringify(tableObj)));
+    } else {
+      setTableObj(JSON.parse(JSON.stringify(jsonTableObj)));
+    }
+  }, [editView]);
 
   const updateSchemaObj = async (tableName) => {
     //table name is same as schema name
@@ -226,15 +240,33 @@ const checkFields = (tableObj,fields) => {
   };
 
   const handleSave = async () => {
-    if(await validateTableConfig()){
-      const tableCreationResp = await 
PinotMethodUtils.saveTableAction(tableObj);
-      dispatch({
-        type: (tableCreationResp.error || typeof tableCreationResp === 
'string') ? 'error' : 'success',
-        message: tableCreationResp.error || tableCreationResp.status || 
tableCreationResp,
-        show: true
-      });
-      tableCreationResp.status && fetchData();
-      tableCreationResp.status && hideModal(null);
+    // Determine which config to save based on view
+    const configToSave = editView === EditView.SIMPLE ? tableObj : 
jsonTableObj;
+    // Validate based on view
+    if (editView === EditView.SIMPLE) {
+      if (!await validateTableConfig()) {
+        return;
+      }
+    } else {
+      const validTable = await 
PinotMethodUtils.validateTableAction(configToSave);
+      if (validTable.error || typeof validTable === 'string') {
+        dispatch({
+          type: 'error',
+          message: validTable.error || validTable,
+          show: true
+        });
+        return;
+      }
+    }
+    const tableCreationResp = await 
PinotMethodUtils.saveTableAction(configToSave);
+    dispatch({
+      type: (tableCreationResp.error || typeof tableCreationResp === 'string') 
? 'error' : 'success',
+      message: tableCreationResp.error || tableCreationResp.status || 
tableCreationResp,
+      show: true
+    });
+    if (tableCreationResp.status) {
+      fetchData();
+      hideModal(null);
     }
   };
 
@@ -255,13 +287,32 @@ const checkFields = (tableObj,fields) => {
       open={true}
       handleClose={hideModal}
       handleSave={handleSave}
-      title={`Add ${tableType} Table`}
+      title={
+        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 
'space-between' }}>
+          <span>Add {tableType} Table</span>
+          <ButtonGroup size="small" color="primary">
+            <Button
+              variant={editView === EditView.SIMPLE ? 'contained' : 'outlined'}
+              onClick={() => setEditView(EditView.SIMPLE)}
+            >
+              Simple
+            </Button>
+            <Button
+              variant={editView === EditView.JSON ? 'contained' : 'outlined'}
+              onClick={() => setEditView(EditView.JSON)}
+            >
+              Json
+            </Button>
+          </ButtonGroup>
+        </div>
+      }
       size="xl"
       disableBackdropClick={true}
       disableEscapeKeyDown={true}
     >
       <DialogContent>
-        <Grid container spacing={2}>
+        {editView === EditView.SIMPLE && (
+          <Grid container spacing={2}>
           <Grid item xs={12}>
             <SimpleAccordion
               headerTitle="Add Table"
@@ -383,6 +434,19 @@ const checkFields = (tableObj,fields) => {
             </div>
           </Grid>
         </Grid>
+        )}
+        {editView === EditView.JSON && (
+          <CustomCodemirror
+            data={jsonTableObj}
+            isEditable={true}
+            returnCodemirrorValue={(newValue) => {
+              try {
+                const jsonObj = JSON.parse(newValue);
+                setJsonTableObj(jsonObj);
+              } catch (e) {}
+            }}
+          />
+        )}
       </DialogContent>
     </Dialog>
   );
diff --git 
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/AddRealtimeTableOp.tsx
 
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/AddRealtimeTableOp.tsx
index bdaa79350d..8ddd36910d 100644
--- 
a/pinot-controller/src/main/resources/app/components/Homepage/Operations/AddRealtimeTableOp.tsx
+++ 
b/pinot-controller/src/main/resources/app/components/Homepage/Operations/AddRealtimeTableOp.tsx
@@ -18,7 +18,7 @@
  */
 
 import React, { useEffect, useState } from 'react';
-import { createStyles, DialogContent, Grid, makeStyles, Theme} from 
'@material-ui/core';
+import { createStyles, DialogContent, Grid, makeStyles, Theme, Button, 
ButtonGroup } from '@material-ui/core';
 import Dialog from '../../CustomDialog';
 import SimpleAccordion from '../../SimpleAccordion';
 import AddTableComponent from './AddTableComponent';
@@ -47,6 +47,11 @@ const useStyles = makeStyles((theme: Theme) =>
     },
   })
 );
+// View modes for simple form or raw JSON editing
+enum EditView {
+  SIMPLE = "SIMPLE",
+  JSON = "JSON"
+}
 
 type Props = {
   hideModal: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void,
@@ -143,6 +148,8 @@ export default function AddRealtimeTableOp({
   tableType
 }: Props) {
   const classes = useStyles();
+  const [editView, setEditView] = useState<EditView>(EditView.SIMPLE);
+  const [jsonTableObj, setJsonTableObj] = 
useState(JSON.parse(JSON.stringify(defaultTableObj)));
   const [tableObj, setTableObj] = 
useState(JSON.parse(JSON.stringify(defaultTableObj)));
   const [schemaObj, setSchemaObj] = 
useState(JSON.parse(JSON.stringify(defaultSchemaObj)));
   const [tableName, setTableName] = useState('');
@@ -163,6 +170,14 @@ export default function AddRealtimeTableOp({
   useEffect(()=>{
     setTableObj({...tableObj,"tableType":tableType})
   },[])
+  // Sync state when toggling between simple and JSON view
+  useEffect(() => {
+    if (editView === EditView.JSON) {
+      setJsonTableObj(JSON.parse(JSON.stringify(tableObj)));
+    } else {
+      setTableObj(JSON.parse(JSON.stringify(jsonTableObj)));
+    }
+  }, [editView]);
 
   const updateSchemaObj = async (tableName) => {
     //table name is same as schema name
@@ -238,15 +253,33 @@ const checkFields = (tableObj,fields) => {
   };
 
   const handleSave = async () => {
-    if(await validateTableConfig()){
-      const tableCreationResp = await 
PinotMethodUtils.saveTableAction(tableObj);
-      dispatch({
-        type: (tableCreationResp.error || typeof tableCreationResp === 
'string') ? 'error' : 'success',
-        message: tableCreationResp.error || tableCreationResp.status || 
tableCreationResp,
-        show: true
-      });
-      tableCreationResp.status && fetchData();
-      tableCreationResp.status && hideModal(null);
+    // Determine which config to save based on view
+    const configToSave = editView === EditView.SIMPLE ? tableObj : 
jsonTableObj;
+    // Validate based on view
+    if (editView === EditView.SIMPLE) {
+      if (!await validateTableConfig()) {
+        return;
+      }
+    } else {
+      const validTable = await 
PinotMethodUtils.validateTableAction(configToSave);
+      if (validTable.error || typeof validTable === 'string') {
+        dispatch({
+          type: 'error',
+          message: validTable.error || validTable,
+          show: true
+        });
+        return;
+      }
+    }
+    const tableCreationResp = await 
PinotMethodUtils.saveTableAction(configToSave);
+    dispatch({
+      type: (tableCreationResp.error || typeof tableCreationResp === 'string') 
? 'error' : 'success',
+      message: tableCreationResp.error || tableCreationResp.status || 
tableCreationResp,
+      show: true
+    });
+    if (tableCreationResp.status) {
+      fetchData();
+      hideModal(null);
     }
   };
 
@@ -267,13 +300,32 @@ const checkFields = (tableObj,fields) => {
       open={true}
       handleClose={hideModal}
       handleSave={handleSave}
-      title={`Add ${tableType} Table`}
+      title={
+        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 
'space-between' }}>
+          <span>Add {tableType} Table</span>
+          <ButtonGroup size="small" color="primary">
+            <Button
+              variant={editView === EditView.SIMPLE ? 'contained' : 'outlined'}
+              onClick={() => setEditView(EditView.SIMPLE)}
+            >
+              Simple
+            </Button>
+            <Button
+              variant={editView === EditView.JSON ? 'contained' : 'outlined'}
+              onClick={() => setEditView(EditView.JSON)}
+            >
+              Json
+            </Button>
+          </ButtonGroup>
+        </div>
+      }
       size="xl"
       disableBackdropClick={true}
       disableEscapeKeyDown={true}
     >
       <DialogContent>
-        <Grid container spacing={2}>
+        {editView === EditView.SIMPLE && (
+          <Grid container spacing={2}>
           <Grid item xs={12}>
             <SimpleAccordion
               headerTitle="Add Table"
@@ -395,6 +447,19 @@ const checkFields = (tableObj,fields) => {
             </div>
           </Grid>
         </Grid>
+        )}
+        {editView === EditView.JSON && (
+          <CustomCodemirror
+            data={jsonTableObj}
+            isEditable={true}
+            returnCodemirrorValue={(newValue) => {
+              try {
+                const jsonObj = JSON.parse(newValue);
+                setJsonTableObj(jsonObj);
+              } catch (e) {}
+            }}
+          />
+        )}
       </DialogContent>
     </Dialog>
   );


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to