Copilot commented on code in PR #17878:
URL: https://github.com/apache/pinot/pull/17878#discussion_r2933816546


##########
pinot-controller/src/main/resources/app/pages/LogicalTableDetails.tsx:
##########
@@ -0,0 +1,346 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React, { useState, useEffect } from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import { Grid } from '@material-ui/core';
+import { RouteComponentProps, useHistory } from 'react-router-dom';
+import { UnControlled as CodeMirror } from 'react-codemirror2';
+import { Link } from 'react-router-dom';
+import AppLoader from '../components/AppLoader';
+import CustomizedTables from '../components/Table';
+import TableToolbar from '../components/TableToolbar';
+import SimpleAccordion from '../components/SimpleAccordion';
+import PinotMethodUtils from '../utils/PinotMethodUtils';
+import CustomButton from '../components/CustomButton';
+import EditConfigOp from '../components/Homepage/Operations/EditConfigOp';
+import Confirm from '../components/Confirm';
+import { NotificationContext } from 
'../components/Notification/NotificationContext';
+import NotFound from '../components/NotFound';
+import 'codemirror/lib/codemirror.css';
+import 'codemirror/theme/material.css';
+import 'codemirror/mode/javascript/javascript';
+
+const useStyles = makeStyles((theme) => ({
+  highlightBackground: {
+    border: '1px #4285f4 solid',
+    backgroundColor: 'rgba(66, 133, 244, 0.05)',
+    borderRadius: 4,
+    marginBottom: '20px',
+  },
+  body: {
+    borderTop: '1px solid #BDCCD9',
+    fontSize: '16px',
+    lineHeight: '3rem',
+    paddingLeft: '15px',
+  },
+  queryOutput: {
+    border: '1px solid #BDCCD9',
+    '& .CodeMirror': { height: 532 },
+  },
+  sqlDiv: {
+    border: '1px #BDCCD9 solid',
+    borderRadius: 4,
+    marginBottom: '20px',
+  },
+  operationDiv: {
+    border: '1px #BDCCD9 solid',
+    borderRadius: 4,
+    marginBottom: 20,
+  },
+  link: {
+    color: '#4285f4',
+    textDecoration: 'none',
+    '&:hover': {
+      textDecoration: 'underline',
+    },
+  },
+}));
+
+const jsonoptions = {
+  lineNumbers: true,
+  mode: 'application/json',
+  styleActiveLine: true,
+  gutters: ['CodeMirror-lint-markers'],
+  theme: 'default',
+  readOnly: true,
+};
+
+type Props = {
+  logicalTableName: string;
+};
+
+const ConfigSection = ({ title, data, classes }: { title: string; data: any; 
classes: any }) => {
+  if (!data) return null;
+  return (
+    <div className={classes.sqlDiv}>
+      <SimpleAccordion headerTitle={title} showSearchBox={false}>
+        <CodeMirror
+          options={jsonoptions}
+          value={JSON.stringify(data, null, 2)}
+          className={classes.queryOutput}
+          autoCursor={false}
+        />
+      </SimpleAccordion>
+    </div>
+  );
+};
+
+const LogicalTableDetails = ({ match }: RouteComponentProps<Props>) => {
+  const { logicalTableName } = match.params;
+  const classes = useStyles();
+  const history = useHistory();
+  const [fetching, setFetching] = useState(true);
+  const [notFound, setNotFound] = useState(false);
+  const [logicalTableConfig, setLogicalTableConfig] = useState<any>(null);
+  const [configJSON, setConfigJSON] = useState('');
+
+  const [showEditConfig, setShowEditConfig] = useState(false);
+  const [config, setConfig] = useState('{}');
+  const [confirmDialog, setConfirmDialog] = useState(false);
+  const [dialogDetails, setDialogDetails] = useState(null);
+  const { dispatch } = React.useContext(NotificationContext);
+
+  const fetchData = async () => {
+    setFetching(true);
+    try {
+      const result = await 
PinotMethodUtils.getLogicalTableConfig(logicalTableName);
+      if (result.error || !result) {
+        setNotFound(true);
+      } else {
+        const parsed = typeof result === 'string' ? JSON.parse(result) : 
result;
+        setLogicalTableConfig(parsed);
+        setConfigJSON(JSON.stringify(parsed, null, 2));
+      }
+    } catch (e) {
+      setNotFound(true);
+    }
+    setFetching(false);
+  };

Review Comment:
   `notFound` is set to `true` on failures but never reset to `false` on 
subsequent successful fetches (or when starting a new fetch). If a user 
navigates from a missing logical table to an existing one without unmounting 
this component (same route, different `logicalTableName`), the page will keep 
rendering the NotFound state. Reset `notFound` to `false` at the start of 
`fetchData()` (or explicitly on the success path).



##########
pinot-controller/src/main/resources/app/utils/PinotMethodUtils.ts:
##########
@@ -1458,6 +1461,29 @@ const getPackageVersionsData = () => {
   });
 };
 
+const getLogicalTablesList = async () => {
+  const { data } = await getLogicalTables();
+  return {
+    columns: ['Logical Table Name'],
+    records: data.map((name) => [name])
+  };
+};
+

Review Comment:
   `getLogicalTablesList()` duplicates the same endpoint + mapping logic 
already implemented in `getQueryLogicalTablesList()` (both call 
`/logicalTables` and convert `string[]` into `{ columns, records }`). Consider 
consolidating into a single helper (e.g., a shared formatter that takes the 
column header label) to avoid the two implementations drifting over time.
   



##########
pinot-controller/src/main/resources/app/components/Breadcrumbs.tsx:
##########
@@ -98,7 +99,12 @@ const BreadcrumbsComponent = ({ ...props }) => {
     const breadcrumbs = [getClickableLabel(breadcrumbNameMap['/'], '/')];
     const paramsKeys = keys(props.match.params);
     if(paramsKeys.length){
-      const {tenantName, tableName, segmentName, instanceName, schemaName, 
query, taskType, queueTableName, taskID, subTaskID} = props.match.params;
+      const {tenantName, tableName, segmentName, instanceName, schemaName, 
query, taskType, queueTableName, taskID, subTaskID, logicalTableName} = 
props.match.params;
+      if (logicalTableName) {
+        breadcrumbs.push(
+          getClickableLabel('Tables', '/tables'),

Review Comment:
   For logical table details routes, the breadcrumb builder currently inserts a 
clickable "Tables" crumb when `logicalTableName` is present, but never inserts 
a "Logical Tables" crumb (even though `breadcrumbNameMap` defines 
`/logical-tables`). This makes the breadcrumb trail misleading for the new 
logical-table flow. Consider adding a "Logical Tables" breadcrumb (likely 
linking back to `/tables` where the logical tables list is shown, or to a 
dedicated `/logical-tables` listing route if one is added).
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to