This is an automated email from the ASF dual-hosted git repository.
kishoreg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
The following commit(s) were added to refs/heads/master by this push:
new 02dd3e2 Adding Tenants, Instances, Tables, Segments count tiles and
their respective pages (#6117)
02dd3e2 is described below
commit 02dd3e2f9dcb9df79f911fbe010a2d5e9db4721a
Author: Sanket Shah <[email protected]>
AuthorDate: Thu Oct 8 00:22:44 2020 +0530
Adding Tenants, Instances, Tables, Segments count tiles and their
respective pages (#6117)
* Adding Tenants, Instances, Tables, Segments count tiles and their
respective pages
* removed segment count from homepage
---
.../main/resources/app/components/Breadcrumbs.tsx | 5 +
.../src/main/resources/app/components/Header.tsx | 4 +-
.../app/components/Homepage/InstanceTable.tsx | 2 +-
.../app/components/Homepage/InstancesTables.tsx | 34 +-----
.../{TenantsTable.tsx => TenantsListing.tsx} | 26 +----
.../src/main/resources/app/components/Table.tsx | 34 +++---
.../src/main/resources/app/interfaces/types.d.ts | 13 ++-
.../src/main/resources/app/pages/HomePage.tsx | 126 +++++++++++++++++++--
.../InstanceListingPage.tsx} | 54 +++++----
.../src/main/resources/app/pages/Query.tsx | 2 +-
.../pages/{Tenants.tsx => TablesListingPage.tsx} | 65 +++++++----
.../src/main/resources/app/pages/Tenants.tsx | 40 ++++++-
.../TenantsListingPage.tsx} | 50 ++++----
.../src/main/resources/app/requests/index.ts | 15 ++-
pinot-controller/src/main/resources/app/router.tsx | 8 ++
.../main/resources/app/utils/PinotMethodUtils.ts | 74 ++++++++----
16 files changed, 381 insertions(+), 171 deletions(-)
diff --git a/pinot-controller/src/main/resources/app/components/Breadcrumbs.tsx
b/pinot-controller/src/main/resources/app/components/Breadcrumbs.tsx
index 3249af6..b77104f 100644
--- a/pinot-controller/src/main/resources/app/components/Breadcrumbs.tsx
+++ b/pinot-controller/src/main/resources/app/components/Breadcrumbs.tsx
@@ -47,6 +47,11 @@ const LinkRouter = (props: LinkRouterProps) => (
const breadcrumbNameMap: { [key: string]: string } = {
'/': 'Home',
+ '/tenants': 'Tenants',
+ '/controllers': 'Controllers',
+ '/brokers': 'Brokers',
+ '/servers': 'Servers',
+ '/tables': 'Tables',
'/query': 'Query Console',
'/cluster': 'Cluster Manager',
'/zookeeper': 'Zookeeper Browser'
diff --git a/pinot-controller/src/main/resources/app/components/Header.tsx
b/pinot-controller/src/main/resources/app/components/Header.tsx
index 08817b0..89532a8 100644
--- a/pinot-controller/src/main/resources/app/components/Header.tsx
+++ b/pinot-controller/src/main/resources/app/components/Header.tsx
@@ -34,10 +34,10 @@ const Header = ({ highlightSidebarLink,
showHideSideBarHandler, openSidebar, ...
<AppBar position="static">
<Box display="flex">
<Box textAlign="center" marginY="12.5px" width={openSidebar ? 250 : 90}
borderRight="1px solid rgba(255,255,255,0.5)">
- <Link to="/"><Logo onClick={() => highlightSidebarLink(1)}
fulllogo={openSidebar.toString()} /></Link>
+ <Link to="/" style={{color: '#ffffff'}}><Logo onClick={() =>
highlightSidebarLink(1)} fulllogo={openSidebar.toString()} /></Link>
</Box>
<Box display="flex" alignItems="center">
- <Box marginY="auto" padding="0.25rem 0 0.25rem 1.5rem" display="flex">
+ <Box marginY="auto" padding="0.25rem 0 0.25rem 1.5rem" display="flex"
style={{cursor: 'pointer'}}>
<MenuIcon onClick={() => showHideSideBarHandler()} />
</Box>
<BreadcrumbsComponent {...props}/>
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/InstanceTable.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/InstanceTable.tsx
index 3e2da1c..60b9018 100644
---
a/pinot-controller/src/main/resources/app/components/Homepage/InstanceTable.tsx
+++
b/pinot-controller/src/main/resources/app/components/Homepage/InstanceTable.tsx
@@ -25,7 +25,7 @@ import PinotMethodUtils from '../../utils/PinotMethodUtils';
type Props = {
name: string,
- instances: string[],
+ instances: Array<String>,
clusterName: string
};
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/InstancesTables.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/InstancesTables.tsx
index bca24ca..6f09121 100644
---
a/pinot-controller/src/main/resources/app/components/Homepage/InstancesTables.tsx
+++
b/pinot-controller/src/main/resources/app/components/Homepage/InstancesTables.tsx
@@ -17,42 +17,16 @@
* under the License.
*/
-import React, { useEffect, useState } from 'react';
+import React, { } from 'react';
import map from 'lodash/map';
-import AppLoader from '../AppLoader';
import InstanceTable from './InstanceTable';
-import PinotMethodUtils from '../../utils/PinotMethodUtils';
-type DataTable = {
- [name: string]: string[]
-};
-
-const Instances = () => {
- const [fetching, setFetching] = useState(true);
- const [instances, setInstances] = useState<DataTable>();
- const [clusterName, setClusterName] = useState('');
-
- const fetchData = async () => {
- const result = await PinotMethodUtils.getAllInstances();
- let clusterNameRes = localStorage.getItem('pinot_ui:clusterName');
- if(!clusterNameRes){
- clusterNameRes = await PinotMethodUtils.getClusterName();
- }
- setInstances(result);
- setClusterName(clusterNameRes);
- setFetching(false);
- };
- useEffect(() => {
- fetchData();
- }, []);
-
- return fetching ? (
- <AppLoader />
- ) : (
+const Instances = ({instances, clusterName}) => {
+ return (
<>
{
map(instances, (value, key) => {
- return <InstanceTable key={key} name={key} instances={value}
clusterName={clusterName} />;
+ return <InstanceTable key={key} name={`${key}s`} instances={value}
clusterName={clusterName} />;
})
}
</>
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/TenantsTable.tsx
b/pinot-controller/src/main/resources/app/components/Homepage/TenantsListing.tsx
similarity index 62%
copy from
pinot-controller/src/main/resources/app/components/Homepage/TenantsTable.tsx
copy to
pinot-controller/src/main/resources/app/components/Homepage/TenantsListing.tsx
index 0696961..d711109 100644
---
a/pinot-controller/src/main/resources/app/components/Homepage/TenantsTable.tsx
+++
b/pinot-controller/src/main/resources/app/components/Homepage/TenantsListing.tsx
@@ -17,31 +17,15 @@
* under the License.
*/
-import React, { useEffect, useState } from 'react';
-import { TableData } from 'Models';
-import AppLoader from '../AppLoader';
+import React from 'react';
import CustomizedTables from '../Table';
-import PinotMethodUtils from '../../utils/PinotMethodUtils';
-const TenantsTable = () => {
- const [fetching, setFetching] = useState(true);
- const [tableData, setTableData] = useState<TableData>({ records: [],
columns: [] });
-
- const fetchData = async () => {
- const result = await PinotMethodUtils.getTenantsData();
- setTableData(result);
- setFetching(false);
- };
- useEffect(() => {
- fetchData();
- }, []);
-
- return fetching ? (
- <AppLoader />
- ) : (
+const TenantsTable = ({tenantsData}) => {
+
+ return (
<CustomizedTables
title="Tenants"
- data={tableData}
+ data={tenantsData}
addLinks
isPagination
baseURL="/tenants/"
diff --git a/pinot-controller/src/main/resources/app/components/Table.tsx
b/pinot-controller/src/main/resources/app/components/Table.tsx
index 98b3e6c..7dac1f3 100644
--- a/pinot-controller/src/main/resources/app/components/Table.tsx
+++ b/pinot-controller/src/main/resources/app/components/Table.tsx
@@ -49,19 +49,20 @@ import TableToolbar from './TableToolbar';
import SimpleAccordion from './SimpleAccordion';
type Props = {
- title?: string;
- data: TableData;
- noOfRows?: number;
- addLinks?: boolean;
- isPagination?: boolean;
+ title?: string,
+ data: TableData,
+ noOfRows?: number,
+ addLinks?: boolean,
+ isPagination?: boolean,
cellClickCallback?: Function,
isCellClickable?: boolean,
highlightBackground?: boolean,
- isSticky?: boolean
+ isSticky?: boolean,
baseURL?: string,
recordsCount?: number,
showSearchBox: boolean,
- inAccordionFormat?: boolean
+ inAccordionFormat?: boolean,
+ regexReplace?: boolean
};
const StyledTableRow = withStyles((theme) =>
@@ -140,7 +141,7 @@ const useStyles = makeStyles((theme) => ({
textAlign: 'center',
},
link: {
- color: 'inherit',
+ color: '#4285f4',
},
spacer: {
flex: '0 1 auto',
@@ -249,7 +250,8 @@ export default function CustomizedTables({
baseURL,
recordsCount,
showSearchBox,
- inAccordionFormat
+ inAccordionFormat,
+ regexReplace
}: Props) {
const [finalData, setFinalData] = React.useState(Utils.tableFormat(data));
@@ -382,12 +384,18 @@ export default function CustomizedTables({
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => (
<StyledTableRow key={index} hover>
- {Object.values(row).map((cell, idx) =>
- addLinks && !idx ? (
+ {Object.values(row).map((cell, idx) =>{
+ let url = baseURL;
+ if(regexReplace){
+ let regex = /\:.*?:/;
+ let matches = baseURL.match(regex);
+ url = baseURL.replace(matches[0],
row[matches[0].replace(/:/g, '')]);
+ }
+ return addLinks && !idx ? (
<StyledTableCell key={idx}>
<NavLink
className={classes.link}
- to={`${baseURL}${cell}`}
+ to={`${url}${cell}`}
>
{cell}
</NavLink>
@@ -401,7 +409,7 @@ export default function CustomizedTables({
{styleCell(cell.toString())}
</StyledTableCell>
)
- )}
+ })}
</StyledTableRow>
))
)}
diff --git a/pinot-controller/src/main/resources/app/interfaces/types.d.ts
b/pinot-controller/src/main/resources/app/interfaces/types.d.ts
index 4199174..7cc6211 100644
--- a/pinot-controller/src/main/resources/app/interfaces/types.d.ts
+++ b/pinot-controller/src/main/resources/app/interfaces/types.d.ts
@@ -20,7 +20,7 @@
declare module 'Models' {
export type TableData = {
records: Array<Array<string | number | boolean>>;
- columns: string[];
+ columns: Array<string>;
};
export type Tenants = {
@@ -117,4 +117,15 @@ declare module 'Models' {
export type ZKConfig = Object;
export type ZKOperationResponsne = any;
+
+ export type DataTable = {
+ [name: string]: Array<string>
+ };
+
+ export type BrokerList = Array<string>;
+
+ export type ServerList = {
+ ServerInstances: Array<string>,
+ tenantName: string
+ }
}
diff --git a/pinot-controller/src/main/resources/app/pages/HomePage.tsx
b/pinot-controller/src/main/resources/app/pages/HomePage.tsx
index bb7a8c3..5c2c69a 100644
--- a/pinot-controller/src/main/resources/app/pages/HomePage.tsx
+++ b/pinot-controller/src/main/resources/app/pages/HomePage.tsx
@@ -17,17 +17,129 @@
* under the License.
*/
-import * as React from 'react';
-import { Grid } from '@material-ui/core';
-import TenantsTable from '../components/Homepage/TenantsTable';
+import React, {useState, useEffect} from 'react';
+import { Grid, makeStyles, Paper } from '@material-ui/core';
+import { TableData, DataTable } from 'Models';
+import AppLoader from '../components/AppLoader';
+import PinotMethodUtils from '../utils/PinotMethodUtils';
+import TenantsListing from '../components/Homepage/TenantsListing';
import Instances from '../components/Homepage/InstancesTables';
import ClusterConfig from '../components/Homepage/ClusterConfig';
+import { Link } from 'react-router-dom';
+
+const useStyles = makeStyles((theme) => ({
+ paper:{
+ padding: '10px 0',
+ color: '#4285f4',
+ borderRadius: 4,
+ marginBottom: 15,
+ textAlign: 'center',
+ backgroundColor: 'rgba(66, 133, 244, 0.1)',
+ borderColor: 'rgba(66, 133, 244, 0.5)',
+ borderStyle: 'solid',
+ borderWidth: '1px',
+ '& h2, h4': {
+ margin: 0,
+ },
+ '& h4':{
+ textTransform: 'uppercase',
+ letterSpacing: 1,
+ fontWeight: 600
+ },
+ '&:hover': {
+ borderColor: '#4285f4'
+ }
+ },
+ gridContainer: {
+ padding: 20,
+ backgroundColor: 'white',
+ maxHeight: 'calc(100vh - 70px)',
+ overflowY: 'auto'
+ },
+ paperLinks: {
+ textDecoration: 'none'
+ }
+}));
const HomePage = () => {
- return (
- <Grid item xs style={{ padding: 20, backgroundColor: 'white', maxHeight:
'calc(100vh - 70px)', overflowY: 'auto' }}>
- <TenantsTable />
- <Instances />
+ const classes = useStyles();
+
+ const [fetching, setFetching] = useState(true);
+ const [tenantsData, setTenantsData] = useState<TableData>({ records: [],
columns: [] });
+ const [instances, setInstances] = useState<DataTable>();
+ const [clusterName, setClusterName] = useState('');
+ const [tables, setTables] = useState([]);
+
+ const fetchData = async () => {
+ const tenantsDataResponse = await PinotMethodUtils.getTenantsData();
+ const instanceResponse = await PinotMethodUtils.getAllInstances();
+ const tablesResponse = await
PinotMethodUtils.getQueryTablesList({bothType: true});
+ const tablesList = [];
+ tablesResponse.records.map((record)=>{
+ tablesList.push(...record);
+ });
+ setTenantsData(tenantsDataResponse);
+ setInstances(instanceResponse);
+ setTables(tablesList);
+ let clusterNameRes = localStorage.getItem('pinot_ui:clusterName');
+ if(!clusterNameRes){
+ clusterNameRes = await PinotMethodUtils.getClusterName();
+ }
+ setClusterName(clusterNameRes);
+ setFetching(false);
+ };
+ useEffect(() => {
+ fetchData();
+ }, []);
+
+ return fetching ? (
+ <AppLoader />
+ ) : (
+ <Grid item xs className={classes.gridContainer}>
+ <Grid container spacing={3}>
+ <Grid item xs={2}>
+ <Link to="/tenants" className={classes.paperLinks}>
+ <Paper className={classes.paper}>
+ <h4>Tenants</h4>
+ <h2>{tenantsData.records.length}</h2>
+ </Paper>
+ </Link>
+ </Grid>
+ <Grid item xs={2}>
+ <Link to="/controllers" className={classes.paperLinks}>
+ <Paper className={classes.paper}>
+ <h4>Controllers</h4>
+ <h2>{instances.Controller.length}</h2>
+ </Paper>
+ </Link>
+ </Grid>
+ <Grid item xs={2}>
+ <Link to="/brokers" className={classes.paperLinks}>
+ <Paper className={classes.paper}>
+ <h4>Brokers</h4>
+ <h2>{instances.Broker.length}</h2>
+ </Paper>
+ </Link>
+ </Grid>
+ <Grid item xs={2}>
+ <Link to="/servers" className={classes.paperLinks}>
+ <Paper className={classes.paper}>
+ <h4>Servers</h4>
+ <h2>{instances.Server.length}</h2>
+ </Paper>
+ </Link>
+ </Grid>
+ <Grid item xs={2}>
+ <Link to="/tables" className={classes.paperLinks}>
+ <Paper className={classes.paper}>
+ <h4>Tables</h4>
+ <h2>{tables.length}</h2>
+ </Paper>
+ </Link>
+ </Grid>
+ </Grid>
+ <TenantsListing tenantsData={tenantsData}/>
+ <Instances instances={instances} clusterName={clusterName}/>
<ClusterConfig />
</Grid>
);
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/InstancesTables.tsx
b/pinot-controller/src/main/resources/app/pages/InstanceListingPage.tsx
similarity index 57%
copy from
pinot-controller/src/main/resources/app/components/Homepage/InstancesTables.tsx
copy to pinot-controller/src/main/resources/app/pages/InstanceListingPage.tsx
index bca24ca..30ddf79 100644
---
a/pinot-controller/src/main/resources/app/components/Homepage/InstancesTables.tsx
+++ b/pinot-controller/src/main/resources/app/pages/InstanceListingPage.tsx
@@ -17,46 +17,54 @@
* under the License.
*/
-import React, { useEffect, useState } from 'react';
-import map from 'lodash/map';
-import AppLoader from '../AppLoader';
-import InstanceTable from './InstanceTable';
-import PinotMethodUtils from '../../utils/PinotMethodUtils';
-
-type DataTable = {
- [name: string]: string[]
-};
+import React, {useState, useEffect} from 'react';
+import { Grid, makeStyles } from '@material-ui/core';
+import _ from 'lodash';
+import { DataTable } from 'Models';
+import AppLoader from '../components/AppLoader';
+import PinotMethodUtils from '../utils/PinotMethodUtils';
+import Instances from '../components/Homepage/InstancesTables';
+
+const useStyles = makeStyles(() => ({
+ gridContainer: {
+ padding: 20,
+ backgroundColor: 'white',
+ maxHeight: 'calc(100vh - 70px)',
+ overflowY: 'auto'
+ },
+
+}));
+
+const InstanceListingPage = () => {
+ const classes = useStyles();
-const Instances = () => {
const [fetching, setFetching] = useState(true);
const [instances, setInstances] = useState<DataTable>();
const [clusterName, setClusterName] = useState('');
const fetchData = async () => {
- const result = await PinotMethodUtils.getAllInstances();
+ const instanceResponse = await PinotMethodUtils.getAllInstances();
+ const instanceType = _.startCase(location.hash.split('/')[1].slice(0, -1));
+ setInstances(_.pick(instanceResponse, instanceType));
let clusterNameRes = localStorage.getItem('pinot_ui:clusterName');
if(!clusterNameRes){
clusterNameRes = await PinotMethodUtils.getClusterName();
}
- setInstances(result);
setClusterName(clusterNameRes);
setFetching(false);
- };
+ }
+
useEffect(() => {
fetchData();
}, []);
return fetching ? (
- <AppLoader />
+ <AppLoader/>
) : (
- <>
- {
- map(instances, (value, key) => {
- return <InstanceTable key={key} name={key} instances={value}
clusterName={clusterName} />;
- })
- }
- </>
- );
+ <Grid item xs className={classes.gridContainer}>
+ <Instances instances={instances} clusterName={clusterName}/>
+ </Grid>
+ )
};
-export default Instances;
\ No newline at end of file
+export default InstanceListingPage;
\ No newline at end of file
diff --git a/pinot-controller/src/main/resources/app/pages/Query.tsx
b/pinot-controller/src/main/resources/app/pages/Query.tsx
index 53fd15d..84a1b11 100644
--- a/pinot-controller/src/main/resources/app/pages/Query.tsx
+++ b/pinot-controller/src/main/resources/app/pages/Query.tsx
@@ -237,7 +237,7 @@ const QueryPage = () => {
};
const fetchData = async () => {
- const result = await PinotMethodUtils.getQueryTablesList();
+ const result = await PinotMethodUtils.getQueryTablesList({bothType:
false});
setTableList(result);
setFetching(false);
};
diff --git a/pinot-controller/src/main/resources/app/pages/Tenants.tsx
b/pinot-controller/src/main/resources/app/pages/TablesListingPage.tsx
similarity index 51%
copy from pinot-controller/src/main/resources/app/pages/Tenants.tsx
copy to pinot-controller/src/main/resources/app/pages/TablesListingPage.tsx
index f425f47..fe29f61 100644
--- a/pinot-controller/src/main/resources/app/pages/Tenants.tsx
+++ b/pinot-controller/src/main/resources/app/pages/TablesListingPage.tsx
@@ -17,50 +17,73 @@
* under the License.
*/
-import React, { useState, useEffect } from 'react';
-import { Grid } from '@material-ui/core';
+import React, {useState, useEffect} from 'react';
+import { Grid, makeStyles } from '@material-ui/core';
import { TableData } from 'Models';
-import { RouteComponentProps } from 'react-router-dom';
-import CustomizedTables from '../components/Table';
import AppLoader from '../components/AppLoader';
import PinotMethodUtils from '../utils/PinotMethodUtils';
+import CustomizedTables from '../components/Table';
-type Props = {
- tenantName: string
-};
+const useStyles = makeStyles(() => ({
+ gridContainer: {
+ padding: 20,
+ backgroundColor: 'white',
+ maxHeight: 'calc(100vh - 70px)',
+ overflowY: 'auto'
+ },
-const TenantPage = ({ match }: RouteComponentProps<Props>) => {
+}));
+
+const TablesListingPage = () => {
+ const classes = useStyles();
- const tenantName = match.params.tenantName;
- const columnHeaders = ['Table Name', 'Reported Size', 'Estimated Size',
'Number of Segments', 'Status'];
const [fetching, setFetching] = useState(true);
+ const columnHeaders = ['Table Name', 'Tenant Name', 'Reported Size',
'Estimated Size', 'Number of Segments', 'Status'];
+ const records = [];
const [tableData, setTableData] = useState<TableData>({
columns: columnHeaders,
records: []
});
const fetchData = async () => {
- const result = await PinotMethodUtils.getTenantTableData(tenantName);
- setTableData(result);
- setFetching(false);
- };
+ const tenantsDataResponse = await PinotMethodUtils.getTenantsData();
+ let promiseArr = [];
+ tenantsDataResponse.records.map((tenantRecord)=>{
+ promiseArr.push(PinotMethodUtils.getTenantTableData(tenantRecord[0]));
+ });
+ Promise.all(promiseArr).then((results)=>{
+ results.map((result, index)=>{
+ const tenantName = tenantsDataResponse.records[index][0];
+ records.push(...result.records.map((record)=>{
+ record.splice(1,0,tenantName);
+ return record;
+ }));
+ });
+ setTableData({columns: columnHeaders, records});
+ setFetching(false);
+ });
+ }
+
useEffect(() => {
fetchData();
}, []);
- return (
- fetching ? <AppLoader /> :
- <Grid item xs style={{ padding: 20, backgroundColor: 'white', maxHeight:
'calc(100vh - 70px)', overflowY: 'auto' }}>
+
+ return fetching ? (
+ <AppLoader/>
+ ) : (
+ <Grid item xs className={classes.gridContainer}>
<CustomizedTables
- title={tenantName}
+ title="Tables"
data={tableData}
isPagination
addLinks
- baseURL={`/tenants/${tenantName}/table/`}
+ baseURL={`/tenants/:Tenant Name:/table/`} // TODO
+ regexReplace={true}
showSearchBox={true}
inAccordionFormat={true}
/>
</Grid>
- );
+ )
};
-export default TenantPage;
+export default TablesListingPage;
\ No newline at end of file
diff --git a/pinot-controller/src/main/resources/app/pages/Tenants.tsx
b/pinot-controller/src/main/resources/app/pages/Tenants.tsx
index f425f47..9c87678 100644
--- a/pinot-controller/src/main/resources/app/pages/Tenants.tsx
+++ b/pinot-controller/src/main/resources/app/pages/Tenants.tsx
@@ -38,10 +38,16 @@ const TenantPage = ({ match }: RouteComponentProps<Props>)
=> {
columns: columnHeaders,
records: []
});
+ const [brokerData, setBrokerData] = useState([]);
+ const [serverData, setServerData] = useState([]);
const fetchData = async () => {
- const result = await PinotMethodUtils.getTenantTableData(tenantName);
- setTableData(result);
+ const tenantData = await PinotMethodUtils.getTenantTableData(tenantName);
+ const brokersData = await PinotMethodUtils.getBrokerOfTenant(tenantName);
+ const serversData = await PinotMethodUtils.getServerOfTenant(tenantName);
+ setTableData(tenantData);
+ setBrokerData(brokersData);
+ setServerData(serversData);
setFetching(false);
};
useEffect(() => {
@@ -59,6 +65,36 @@ const TenantPage = ({ match }: RouteComponentProps<Props>)
=> {
showSearchBox={true}
inAccordionFormat={true}
/>
+ <Grid container spacing={2}>
+ <Grid item xs={6}>
+ <CustomizedTables
+ title="Brokers"
+ data={{
+ columns: ['Instance Name'],
+ records: [brokerData]
+ }}
+ isPagination
+ addLinks
+ baseURL={'/instance/'}
+ showSearchBox={true}
+ inAccordionFormat={true}
+ />
+ </Grid>
+ <Grid item xs={6}>
+ <CustomizedTables
+ title="Servers"
+ data={{
+ columns: ['Instance Name'],
+ records: [serverData]
+ }}
+ isPagination
+ addLinks
+ baseURL={'/instance/'}
+ showSearchBox={true}
+ inAccordionFormat={true}
+ />
+ </Grid>
+ </Grid>
</Grid>
);
};
diff --git
a/pinot-controller/src/main/resources/app/components/Homepage/TenantsTable.tsx
b/pinot-controller/src/main/resources/app/pages/TenantsListingPage.tsx
similarity index 53%
rename from
pinot-controller/src/main/resources/app/components/Homepage/TenantsTable.tsx
rename to pinot-controller/src/main/resources/app/pages/TenantsListingPage.tsx
index 0696961..0b78ce2 100644
---
a/pinot-controller/src/main/resources/app/components/Homepage/TenantsTable.tsx
+++ b/pinot-controller/src/main/resources/app/pages/TenantsListingPage.tsx
@@ -17,38 +17,46 @@
* under the License.
*/
-import React, { useEffect, useState } from 'react';
+import React, {useState, useEffect} from 'react';
+import { Grid, makeStyles } from '@material-ui/core';
import { TableData } from 'Models';
-import AppLoader from '../AppLoader';
-import CustomizedTables from '../Table';
-import PinotMethodUtils from '../../utils/PinotMethodUtils';
+import AppLoader from '../components/AppLoader';
+import PinotMethodUtils from '../utils/PinotMethodUtils';
+import TenantsListing from '../components/Homepage/TenantsListing';
+
+const useStyles = makeStyles(() => ({
+ gridContainer: {
+ padding: 20,
+ backgroundColor: 'white',
+ maxHeight: 'calc(100vh - 70px)',
+ overflowY: 'auto'
+ },
+
+}));
+
+const TenantsListingPage = () => {
+ const classes = useStyles();
-const TenantsTable = () => {
const [fetching, setFetching] = useState(true);
- const [tableData, setTableData] = useState<TableData>({ records: [],
columns: [] });
+ const [tenantsData, setTenantsData] = useState<TableData>({ records: [],
columns: [] });
const fetchData = async () => {
- const result = await PinotMethodUtils.getTenantsData();
- setTableData(result);
+ const tenantsDataResponse = await PinotMethodUtils.getTenantsData();
+ setTenantsData(tenantsDataResponse);
setFetching(false);
- };
+ }
+
useEffect(() => {
fetchData();
}, []);
return fetching ? (
- <AppLoader />
+ <AppLoader/>
) : (
- <CustomizedTables
- title="Tenants"
- data={tableData}
- addLinks
- isPagination
- baseURL="/tenants/"
- showSearchBox={true}
- inAccordionFormat={true}
- />
- );
+ <Grid item xs className={classes.gridContainer}>
+ <TenantsListing tenantsData={tenantsData}/>
+ </Grid>
+ )
};
-export default TenantsTable;
+export default TenantsListingPage;
\ No newline at end of file
diff --git a/pinot-controller/src/main/resources/app/requests/index.ts
b/pinot-controller/src/main/resources/app/requests/index.ts
index 373c9e7..60e5ad6 100644
--- a/pinot-controller/src/main/resources/app/requests/index.ts
+++ b/pinot-controller/src/main/resources/app/requests/index.ts
@@ -19,7 +19,8 @@
import { AxiosResponse } from 'axios';
import { TableData, Instances, Instance, Tenants, ClusterConfig, TableName,
TableSize,
- IdealState, QueryTables, TableSchema, SQLResult, ClusterName, ZKGetList,
ZKConfig, ZKOperationResponsne
+ IdealState, QueryTables, TableSchema, SQLResult, ClusterName, ZKGetList,
ZKConfig, ZKOperationResponsne,
+ BrokerList, ServerList
} from 'Models';
import { baseApi } from '../utils/axios-config';
@@ -56,8 +57,8 @@ export const getInstance = (name: string):
Promise<AxiosResponse<Instance>> =>
export const getClusterConfig = (): Promise<AxiosResponse<ClusterConfig>> =>
baseApi.get('/cluster/configs');
-export const getQueryTables = (): Promise<AxiosResponse<QueryTables>> =>
- baseApi.get('/tables');
+export const getQueryTables = (type?: string):
Promise<AxiosResponse<QueryTables>> =>
+ baseApi.get(`/tables${type ? "?type="+type: ""}`);
export const getTableSchema = (name: string):
Promise<AxiosResponse<TableSchema>> =>
baseApi.get(`/tables/${name}/schema`);
@@ -84,4 +85,10 @@ export const zookeeperPutData = (params: string):
Promise<AxiosResponse<ZKOperat
baseApi.put(`/zk/put?${params}`, null, { headers: { 'Content-Type':
'application/json; charset=UTF-8', 'Accept': 'text/plain, */*; q=0.01' } });
export const zookeeperDeleteNode = (params: string):
Promise<AxiosResponse<ZKOperationResponsne>> =>
- baseApi.delete(`/zk/delete?path=${params}`);
\ No newline at end of file
+ baseApi.delete(`/zk/delete?path=${params}`);
+
+export const getBrokerListOfTenant = (name: string):
Promise<AxiosResponse<BrokerList>> =>
+ baseApi.get(`/brokers/tenants/${name}`);
+
+export const getServerListOfTenant = (name: string):
Promise<AxiosResponse<ServerList>> =>
+ baseApi.get(`/tenants/${name}?type=server`);
diff --git a/pinot-controller/src/main/resources/app/router.tsx
b/pinot-controller/src/main/resources/app/router.tsx
index d15b07d..86b700c 100644
--- a/pinot-controller/src/main/resources/app/router.tsx
+++ b/pinot-controller/src/main/resources/app/router.tsx
@@ -18,6 +18,9 @@
*/
import HomePage from './pages/HomePage';
+import TenantsListingPage from './pages/TenantsListingPage';
+import InstanceListingPage from './pages/InstanceListingPage';
+import TablesListingPage from './pages/TablesListingPage';
import TenantsPage from './pages/Tenants';
import TenantPageDetails from './pages/TenantDetails';
import QueryPage from './pages/Query';
@@ -28,6 +31,11 @@ import ZookeeperPage from './pages/ZookeeperPage';
export default [
{ path: "/", Component: HomePage },
{ path: "/query", Component: QueryPage },
+ { path: "/tenants", Component: TenantsListingPage },
+ { path: "/controllers", Component: InstanceListingPage },
+ { path: "/brokers", Component: InstanceListingPage },
+ { path: "/servers", Component: InstanceListingPage },
+ { path: "/tables", Component: TablesListingPage },
{ path: "/tenants/:tenantName", Component: TenantsPage },
{ path: "/tenants/:tenantName/table/:tableName", Component:
TenantPageDetails },
{ path: "/tenants/:tenantName/table/:tableName/:segmentName", Component:
SegmentDetails },
diff --git a/pinot-controller/src/main/resources/app/utils/PinotMethodUtils.ts
b/pinot-controller/src/main/resources/app/utils/PinotMethodUtils.ts
index 35a2c9e..165ab76 100644
--- a/pinot-controller/src/main/resources/app/utils/PinotMethodUtils.ts
+++ b/pinot-controller/src/main/resources/app/utils/PinotMethodUtils.ts
@@ -18,7 +18,7 @@
*/
import _ from 'lodash';
-import { SQLResult } from 'Models';
+import { DataTable, SQLResult } from 'Models';
import moment from 'moment';
import {
getTenants,
@@ -40,7 +40,9 @@ import {
zookeeperGetListWithStat,
zookeeperGetStat,
zookeeperPutData,
- zookeeperDeleteNode
+ zookeeperDeleteNode,
+ getBrokerListOfTenant,
+ getServerListOfTenant
} from '../requests';
import Utils from './Utils';
@@ -50,24 +52,28 @@ import Utils from './Utils';
const getTenantsData = () => {
return getTenants().then(({ data }) => {
const records = _.union(data.SERVER_TENANTS, data.BROKER_TENANTS);
- return {
+ let promiseArr = [];
+ let finalResponse = {
columns: ['Tenant Name', 'Server', 'Broker', 'Tables'],
- records: [
- ...records.map((record) => [
- record,
- data.SERVER_TENANTS.indexOf(record) > -1 ? 1 : 0,
- data.BROKER_TENANTS.indexOf(record) > -1 ? 1 : 0,
- '-',
- ]),
- ],
+ records: []
};
+ records.map((record)=>{
+ finalResponse.records.push([
+ record,
+ data.SERVER_TENANTS.indexOf(record) > -1 ? 1 : 0,
+ data.BROKER_TENANTS.indexOf(record) > -1 ? 1 : 0
+ ]);
+ promiseArr.push(getTenantTable(record));
+ });
+ return Promise.all(promiseArr).then((results)=>{
+ results.map((result, index)=>{
+ finalResponse.records[index].push(result.data.tables.length);
+ });
+ return finalResponse;
+ });
});
};
-type DataTable = {
- [name: string]: string[];
-};
-
// This method is used to fetch all instances on cluster manager home page
// API: /instances
// Expected Output: {Controller: ['Controller1', 'Controller2'], Broker:
['Broker1', 'Broker2']}
@@ -82,7 +88,7 @@ const getAllInstances = () => {
r[key] = [...(r[key] || []), a];
return r;
}, initialVal);
- return groupedData;
+ return {"Controller": groupedData.Controller, ...groupedData};
});
};
@@ -142,14 +148,20 @@ const getClusterConfigData = () => {
// This method is used to display table listing on query page
// API: /tables
// Expected Output: {columns: [], records: []}
-const getQueryTablesList = () => {
- return getQueryTables().then(({ data }) => {
- return {
+const getQueryTablesList = ({bothType = false}) => {
+ let promiseArr = bothType ? [getQueryTables('realtime'),
getQueryTables('offline')] : [getQueryTables()];
+
+ return Promise.all(promiseArr).then((results) => {
+ let responseObj = {
columns: ['Tables'],
- records: data.tables.map((table) => {
- return [table];
- }),
- };
+ records: []
+ }
+ results.map((result)=>{
+ result.data.tables.map((table)=>{
+ responseObj.records.push([table]);
+ });
+ });
+ return responseObj;
});
};
@@ -562,6 +574,18 @@ const deleteNode = (path) => {
});
};
+const getBrokerOfTenant = (tenantName) => {
+ return getBrokerListOfTenant(tenantName).then((response)=>{
+ return response.data;
+ });
+};
+
+const getServerOfTenant = (tenantName) => {
+ return getServerListOfTenant(tenantName).then((response)=>{
+ return response.data.ServerInstances;
+ });
+};
+
export default {
getTenantsData,
getAllInstances,
@@ -583,5 +607,7 @@ export default {
getZookeeperData,
getNodeData,
putNodeData,
- deleteNode
+ deleteNode,
+ getBrokerOfTenant,
+ getServerOfTenant
};
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]