[FE] Fix eslint errors
This commit is contained in:
parent
fb67b538c6
commit
cba12d4ff4
44 changed files with 2922 additions and 2400 deletions
|
@ -42,7 +42,8 @@
|
|||
{ "extensions": [".js", ".jsx", ".ts", ".tsx"] }
|
||||
],
|
||||
"jsx-a11y/label-has-associated-control": "off",
|
||||
"no-param-reassign": [2, { "props": false }]
|
||||
"no-param-reassign": [2, { "props": false }],
|
||||
"import/prefer-default-export": "off"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
|
|
4499
kafka-ui-react-app/package-lock.json
generated
4499
kafka-ui-react-app/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -4,11 +4,12 @@
|
|||
"private": true,
|
||||
"dependencies": {
|
||||
"@types/react-datepicker": "^3.0.2",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"bulma": "^0.8.0",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"classnames": "^2.2.6",
|
||||
"date-fns": "^2.14.0",
|
||||
"eslint-import-resolver-typescript": "^2.0.0",
|
||||
"eslint-import-resolver-typescript": "^2.3.0",
|
||||
"immer": "^6.0.5",
|
||||
"lodash": "^4.17.15",
|
||||
"pretty-ms": "^6.0.1",
|
||||
|
@ -24,25 +25,28 @@
|
|||
"redux-thunk": "^2.3.0",
|
||||
"reselect": "^4.0.0",
|
||||
"typesafe-actions": "^5.1.0",
|
||||
"use-debounce": "^3.4.3"
|
||||
"use-debounce": "^3.4.3",
|
||||
"uuid": "^8.3.1"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts,jsx,tsx}": [
|
||||
"eslint -c .eslintrc.json --fix"
|
||||
"eslint -c .eslintrc.json --fix",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"lint": "esprint check",
|
||||
"lint:fix": "esprint check --fix",
|
||||
"lint": "eslint --ext .tsx,.ts src/",
|
||||
"lint:fix": "eslint --ext .tsx,.ts src/ --fix",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"mock": "node ./mock/index.js"
|
||||
"mock": "node ./mock/index.js",
|
||||
"tsc": "tsc"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "yarn tsc --noEmit && lint-staged"
|
||||
"pre-commit": "npm run tsc --noEmit && lint-staged"
|
||||
}
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
@ -74,24 +78,24 @@
|
|||
"@types/react-router-dom": "^5.1.3",
|
||||
"@types/redux": "^3.6.0",
|
||||
"@types/redux-thunk": "^2.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.27.0",
|
||||
"@typescript-eslint/parser": "^2.27.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
||||
"@typescript-eslint/parser": "^2.34.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-airbnb": "^18.1.0",
|
||||
"eslint-config-prettier": "^6.10.1",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||
"eslint-plugin-prettier": "^3.1.2",
|
||||
"eslint-plugin-react": "^7.19.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"eslint-plugin-react": "^7.21.5",
|
||||
"eslint-plugin-react-hooks": "^2.5.1",
|
||||
"esprint": "^0.6.0",
|
||||
"husky": "^4.2.5",
|
||||
"husky": "^4.3.0",
|
||||
"json-server": "^0.15.1",
|
||||
"lint-staged": ">=10",
|
||||
"lint-staged": "^10.5.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"prettier": "^2.0.4",
|
||||
"react-scripts": "3.4.0",
|
||||
"prettier": "^2.1.2",
|
||||
"react-scripts": "3.4.4",
|
||||
"typescript": "~3.7.4"
|
||||
},
|
||||
"proxy": "http://localhost:8080"
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
fetchClustersList,
|
||||
} from 'redux/actions';
|
||||
import App from './App';
|
||||
import { fetchClustersList } from 'redux/actions';
|
||||
import { getIsClusterListFetched } from 'redux/reducers/clusters/selectors';
|
||||
import { RootState } from 'redux/interfaces';
|
||||
import App from './App';
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
isClusterListFetched: getIsClusterListFetched(state),
|
||||
|
@ -12,6 +10,6 @@ const mapStateToProps = (state: RootState) => ({
|
|||
|
||||
const mapDispatchToProps = {
|
||||
fetchClustersList,
|
||||
}
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
|
|
|
@ -27,15 +27,14 @@ const Topics: React.FC<Props> = ({
|
|||
fetchBrokers,
|
||||
fetchBrokerMetrics,
|
||||
}) => {
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
fetchBrokers(clusterName);
|
||||
fetchBrokerMetrics(clusterName);
|
||||
},
|
||||
[fetchBrokers, fetchBrokerMetrics, clusterName],
|
||||
);
|
||||
}, [fetchBrokers, fetchBrokerMetrics, clusterName]);
|
||||
|
||||
useInterval(() => { fetchBrokerMetrics(clusterName); }, 5000);
|
||||
useInterval(() => {
|
||||
fetchBrokerMetrics(clusterName);
|
||||
}, 5000);
|
||||
|
||||
const zkOnline = zooKeeperStatus === ZooKeeperStatus.online;
|
||||
|
||||
|
@ -44,12 +43,8 @@ const Topics: React.FC<Props> = ({
|
|||
<Breadcrumb>Brokers overview</Breadcrumb>
|
||||
|
||||
<MetricsWrapper title="Uptime">
|
||||
<Indicator label="Total Brokers">
|
||||
{brokerCount}
|
||||
</Indicator>
|
||||
<Indicator label="Active Controllers">
|
||||
{activeControllers}
|
||||
</Indicator>
|
||||
<Indicator label="Total Brokers">{brokerCount}</Indicator>
|
||||
<Indicator label="Active Controllers">{activeControllers}</Indicator>
|
||||
<Indicator label="Zookeeper Status">
|
||||
<span className={cx('tag', zkOnline ? 'is-primary' : 'is-danger')}>
|
||||
{zkOnline ? 'Online' : 'Offline'}
|
||||
|
@ -59,17 +54,21 @@ const Topics: React.FC<Props> = ({
|
|||
|
||||
<MetricsWrapper title="Partitions">
|
||||
<Indicator label="Online">
|
||||
<span className={cx({'has-text-danger': offlinePartitionCount !== 0})}>
|
||||
<span
|
||||
className={cx({ 'has-text-danger': offlinePartitionCount !== 0 })}
|
||||
>
|
||||
{onlinePartitionCount}
|
||||
</span>
|
||||
<span className="subtitle has-text-weight-light"> of {onlinePartitionCount + offlinePartitionCount}</span>
|
||||
<span className="subtitle has-text-weight-light">
|
||||
{' '}
|
||||
of
|
||||
{onlinePartitionCount + offlinePartitionCount}
|
||||
</span>
|
||||
</Indicator>
|
||||
<Indicator label="URP" title="Under replicated partitions">
|
||||
{underReplicatedPartitionCount}
|
||||
</Indicator>
|
||||
<Indicator label="In Sync Replicas">
|
||||
{inSyncReplicasCount}
|
||||
</Indicator>
|
||||
<Indicator label="In Sync Replicas">{inSyncReplicasCount}</Indicator>
|
||||
<Indicator label="Out of Sync Replicas">
|
||||
{outOfSyncReplicasCount}
|
||||
</Indicator>
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
fetchBrokers,
|
||||
fetchBrokerMetrics,
|
||||
} from 'redux/actions';
|
||||
import Brokers from './Brokers';
|
||||
import { fetchBrokers, fetchBrokerMetrics } from 'redux/actions';
|
||||
import * as brokerSelectors from 'redux/reducers/brokers/selectors';
|
||||
import { RootState, ClusterName } from 'redux/interfaces';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import Brokers from './Brokers';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { clusterName } }}: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
isFetched: brokerSelectors.getIsBrokerListFetched(state),
|
||||
clusterName,
|
||||
brokerCount: brokerSelectors.getBrokerCount(state),
|
||||
|
@ -24,12 +28,15 @@ const mapStateToProps = (state: RootState, { match: { params: { clusterName } }}
|
|||
offlinePartitionCount: brokerSelectors.getOfflinePartitionCount(state),
|
||||
inSyncReplicasCount: brokerSelectors.getInSyncReplicasCount(state),
|
||||
outOfSyncReplicasCount: brokerSelectors.getOutOfSyncReplicasCount(state),
|
||||
underReplicatedPartitionCount: brokerSelectors.getUnderReplicatedPartitionCount(state)
|
||||
underReplicatedPartitionCount: brokerSelectors.getUnderReplicatedPartitionCount(
|
||||
state
|
||||
),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchBrokers: (clusterName: ClusterName) => fetchBrokers(clusterName),
|
||||
fetchBrokerMetrics: (clusterName: ClusterName) => fetchBrokerMetrics(clusterName),
|
||||
fetchBrokerMetrics: (clusterName: ClusterName) =>
|
||||
fetchBrokerMetrics(clusterName),
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Brokers);
|
||||
|
|
|
@ -5,20 +5,27 @@ import { RouteComponentProps } from 'react-router-dom';
|
|||
import ConsumerGroups from './ConsumerGroups';
|
||||
import { getIsConsumerGroupsListFetched } from '../../redux/reducers/consumerGroups/selectors';
|
||||
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { clusterName } }}: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
isFetched: getIsConsumerGroupsListFetched(state),
|
||||
clusterName,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchConsumerGroupsList: (clusterName: ClusterName) => fetchConsumerGroupsList(clusterName),
|
||||
fetchConsumerGroupsList: (clusterName: ClusterName) =>
|
||||
fetchConsumerGroupsList(clusterName),
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ConsumerGroups);
|
||||
|
|
|
@ -1,27 +1,40 @@
|
|||
import { connect } from 'react-redux';
|
||||
import Details from './Details';
|
||||
import {ClusterName, RootState} from 'redux/interfaces';
|
||||
import { ClusterName, RootState } from 'redux/interfaces';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { getIsConsumerGroupDetailsFetched, getConsumerGroupByID } from 'redux/reducers/consumerGroups/selectors';
|
||||
import {
|
||||
getIsConsumerGroupDetailsFetched,
|
||||
getConsumerGroupByID,
|
||||
} from 'redux/reducers/consumerGroups/selectors';
|
||||
import { ConsumerGroupID } from 'redux/interfaces/consumerGroup';
|
||||
import { fetchConsumerGroupDetails } from 'redux/actions/thunks';
|
||||
import Details from './Details';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
consumerGroupID: string;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { consumerGroupID, clusterName } } }: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { consumerGroupID, clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
clusterName,
|
||||
consumerGroupID,
|
||||
isFetched: getIsConsumerGroupDetailsFetched(state),
|
||||
...getConsumerGroupByID(state, consumerGroupID)
|
||||
...getConsumerGroupByID(state, consumerGroupID),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchConsumerGroupDetails: (clusterName: ClusterName, consumerGroupID: ConsumerGroupID) => fetchConsumerGroupDetails(clusterName, consumerGroupID),
|
||||
fetchConsumerGroupDetails: (
|
||||
clusterName: ClusterName,
|
||||
consumerGroupID: ConsumerGroupID
|
||||
) => fetchConsumerGroupDetails(clusterName, consumerGroupID),
|
||||
};
|
||||
|
||||
export default withRouter(
|
||||
|
|
|
@ -1,20 +1,25 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {ClusterName, RootState} from 'redux/interfaces';
|
||||
import { ClusterName, RootState } from 'redux/interfaces';
|
||||
import { getConsumerGroupsList } from 'redux/reducers/consumerGroups/selectors';
|
||||
import List from './List';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import List from './List';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { clusterName } } }: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
clusterName,
|
||||
consumerGroups: getConsumerGroupsList(state)
|
||||
consumerGroups: getConsumerGroupsList(state),
|
||||
});
|
||||
|
||||
export default withRouter(
|
||||
connect(mapStateToProps)(List)
|
||||
);
|
||||
export default withRouter(connect(mapStateToProps)(List));
|
||||
|
|
|
@ -4,7 +4,12 @@ import formatBytes from 'lib/utils/formatBytes';
|
|||
import { NavLink } from 'react-router-dom';
|
||||
import { clusterBrokersPath } from 'lib/paths';
|
||||
|
||||
const ClusterWidget: React.FC<Cluster> = ({
|
||||
interface ClusterWidgetProps {
|
||||
cluster: Cluster;
|
||||
}
|
||||
|
||||
const ClusterWidget: React.FC<ClusterWidgetProps> = ({
|
||||
cluster: {
|
||||
name,
|
||||
status,
|
||||
topicCount,
|
||||
|
@ -12,15 +17,15 @@ const ClusterWidget: React.FC<Cluster> = ({
|
|||
bytesInPerSec,
|
||||
bytesOutPerSec,
|
||||
onlinePartitionCount,
|
||||
},
|
||||
}) => (
|
||||
<NavLink to={clusterBrokersPath(name)} className="column is-full-modile is-6">
|
||||
<div className="box is-hoverable">
|
||||
<div className="title is-6 has-text-overflow-ellipsis" title={name}>
|
||||
<div
|
||||
className="title is-6 has-text-overflow-ellipsis"
|
||||
title={name}
|
||||
>
|
||||
<div
|
||||
className={`tag has-margin-right ${status === ClusterStatus.Online ? 'is-primary' : 'is-danger'}`}
|
||||
className={`tag has-margin-right ${
|
||||
status === ClusterStatus.Online ? 'is-primary' : 'is-danger'
|
||||
}`}
|
||||
>
|
||||
{status}
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { chunk } from 'lodash';
|
||||
import { v4 } from 'uuid';
|
||||
import { Cluster } from 'redux/interfaces';
|
||||
import MetricsWrapper from 'components/common/Dashboard/MetricsWrapper';
|
||||
import Indicator from 'components/common/Dashboard/Indicator';
|
||||
|
@ -26,28 +27,20 @@ const ClustersWidget: React.FC<Props> = ({
|
|||
}
|
||||
|
||||
return chunk(list, 2);
|
||||
},
|
||||
[clusters, offlineClusters, showOfflineOnly],
|
||||
);
|
||||
}, [clusters, offlineClusters, showOfflineOnly]);
|
||||
|
||||
const handleSwitch = () => setShowOfflineOnly(!showOfflineOnly);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h5 className="title is-5">
|
||||
Clusters
|
||||
</h5>
|
||||
<h5 className="title is-5">Clusters</h5>
|
||||
|
||||
<MetricsWrapper>
|
||||
<Indicator label="Online Clusters" >
|
||||
<span className="tag is-primary">
|
||||
{onlineClusters.length}
|
||||
</span>
|
||||
<Indicator label="Online Clusters">
|
||||
<span className="tag is-primary">{onlineClusters.length}</span>
|
||||
</Indicator>
|
||||
<Indicator label="Offline Clusters">
|
||||
<span className="tag is-danger">
|
||||
{offlineClusters.length}
|
||||
</span>
|
||||
<span className="tag is-danger">{offlineClusters.length}</span>
|
||||
</Indicator>
|
||||
<Indicator label="Hide online clusters">
|
||||
<input
|
||||
|
@ -58,20 +51,19 @@ const ClustersWidget: React.FC<Props> = ({
|
|||
checked={showOfflineOnly}
|
||||
onChange={handleSwitch}
|
||||
/>
|
||||
<label htmlFor="switchRoundedDefault">
|
||||
</label>
|
||||
<label htmlFor="switchRoundedDefault" />
|
||||
</Indicator>
|
||||
</MetricsWrapper>
|
||||
|
||||
{clusterList.map((chunk, idx) => (
|
||||
<div className="columns" key={`dashboard-cluster-list-row-key-${idx}`}>
|
||||
{chunk.map((cluster, idx) => (
|
||||
<ClusterWidget {...cluster} key={`dashboard-cluster-list-item-key-${idx}`}/>
|
||||
{clusterList.map((chunkItem) => (
|
||||
<div className="columns" key={v4()}>
|
||||
{chunkItem.map((cluster) => (
|
||||
<ClusterWidget cluster={cluster} key={cluster.id} />
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default ClustersWidget;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ClustersWidget from './ClustersWidget';
|
||||
import {
|
||||
getClusterList,
|
||||
getOnlineClusters,
|
||||
getOfflineClusters,
|
||||
} from 'redux/reducers/clusters/selectors';
|
||||
import { RootState } from 'redux/interfaces';
|
||||
import ClustersWidget from './ClustersWidget';
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
clusters: getClusterList(state),
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { connect } from 'react-redux';
|
||||
import Nav from './Nav';
|
||||
import { getIsClusterListFetched, getClusterList } from 'redux/reducers/clusters/selectors';
|
||||
import {
|
||||
getIsClusterListFetched,
|
||||
getClusterList,
|
||||
} from 'redux/reducers/clusters/selectors';
|
||||
import { RootState } from 'redux/interfaces';
|
||||
import Nav from './Nav';
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
isClusterListFetched: getIsClusterListFetched(state),
|
||||
|
|
|
@ -1,20 +1,25 @@
|
|||
import { connect } from 'react-redux';
|
||||
import Details from './Details';
|
||||
import {ClusterName, RootState} from 'redux/interfaces';
|
||||
import { ClusterName, RootState } from 'redux/interfaces';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import Details from './Details';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
topicName: string;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterName } } }: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { topicName, clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
clusterName,
|
||||
topicName,
|
||||
});
|
||||
|
||||
export default withRouter(
|
||||
connect(mapStateToProps)(Details)
|
||||
);
|
||||
export default withRouter(connect(mapStateToProps)(Details));
|
||||
|
|
|
@ -177,7 +177,7 @@ const Messages: React.FC<Props> = ({
|
|||
}, [clusterName, topicName, queryParams]);
|
||||
|
||||
const getTimestampDate = (timestamp: string) => {
|
||||
if (!Date.parse(timestamp)) return;
|
||||
if (!Date.parse(timestamp)) return null;
|
||||
return format(Date.parse(timestamp), 'yyyy-MM-dd HH:mm:ss');
|
||||
};
|
||||
|
||||
|
@ -359,7 +359,7 @@ const Messages: React.FC<Props> = ({
|
|||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column is-full" style={{textAlign: "right"}}>
|
||||
<div className="column is-full" style={{ textAlign: 'right' }}>
|
||||
<input
|
||||
type="submit"
|
||||
className="button is-primary"
|
||||
|
|
|
@ -1,20 +1,28 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
fetchTopicDetails,
|
||||
} from 'redux/actions';
|
||||
import Overview from './Overview';
|
||||
import { fetchTopicDetails } from 'redux/actions';
|
||||
import { RootState, TopicName, ClusterName } from 'redux/interfaces';
|
||||
import { getTopicByName, getIsTopicDetailsFetched } from 'redux/reducers/topics/selectors';
|
||||
import {
|
||||
getTopicByName,
|
||||
getIsTopicDetailsFetched,
|
||||
} from 'redux/reducers/topics/selectors';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import Overview from './Overview';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
topicName: TopicName;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterName } } }: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { topicName, clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
clusterName,
|
||||
topicName,
|
||||
isFetched: getIsTopicDetailsFetched(state),
|
||||
|
@ -22,7 +30,8 @@ const mapStateToProps = (state: RootState, { match: { params: { topicName, clust
|
|||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchTopicDetails: (clusterName: ClusterName, topicName: TopicName) => fetchTopicDetails(clusterName, topicName),
|
||||
fetchTopicDetails: (clusterName: ClusterName, topicName: TopicName) =>
|
||||
fetchTopicDetails(clusterName, topicName),
|
||||
};
|
||||
|
||||
export default withRouter(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
import { ClusterName, TopicName, TopicConfig } from 'redux/interfaces';
|
||||
|
||||
interface Props {
|
||||
|
@ -9,29 +10,24 @@ interface Props {
|
|||
fetchTopicConfig: (clusterName: ClusterName, topicName: TopicName) => void;
|
||||
}
|
||||
|
||||
const ConfigListItem: React.FC<TopicConfig> = ({
|
||||
name,
|
||||
value,
|
||||
defaultValue,
|
||||
interface ListItemProps {
|
||||
config: TopicConfig;
|
||||
}
|
||||
|
||||
const ConfigListItem: React.FC<ListItemProps> = ({
|
||||
config: { name, value, defaultValue },
|
||||
}) => {
|
||||
const hasCustomValue = value !== defaultValue;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td className={hasCustomValue ? 'has-text-weight-bold' : ''}>
|
||||
{name}
|
||||
</td>
|
||||
<td className={hasCustomValue ? 'has-text-weight-bold' : ''}>
|
||||
{value}
|
||||
</td>
|
||||
<td
|
||||
className="has-text-grey"
|
||||
title="Default Value"
|
||||
>
|
||||
<td className={hasCustomValue ? 'has-text-weight-bold' : ''}>{name}</td>
|
||||
<td className={hasCustomValue ? 'has-text-weight-bold' : ''}>{value}</td>
|
||||
<td className="has-text-grey" title="Default Value">
|
||||
{hasCustomValue && defaultValue}
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const Sertings: React.FC<Props> = ({
|
||||
|
@ -41,10 +37,9 @@ const Sertings: React.FC<Props> = ({
|
|||
fetchTopicConfig,
|
||||
config,
|
||||
}) => {
|
||||
React.useEffect(
|
||||
() => { fetchTopicConfig(clusterName, topicName); },
|
||||
[fetchTopicConfig, clusterName, topicName],
|
||||
);
|
||||
React.useEffect(() => {
|
||||
fetchTopicConfig(clusterName, topicName);
|
||||
}, [fetchTopicConfig, clusterName, topicName]);
|
||||
|
||||
if (!isFetched || !config) {
|
||||
return null;
|
||||
|
@ -61,7 +56,9 @@ const Sertings: React.FC<Props> = ({
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{config.map((item, index) => <ConfigListItem key={`config-list-item-key-${index}`} {...item} />)}
|
||||
{config.map((item) => (
|
||||
<ConfigListItem key={v4()} config={item} />
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { RootState, ClusterName, TopicName } from 'redux/interfaces';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import {
|
||||
fetchTopicConfig,
|
||||
} from 'redux/actions';
|
||||
import Settings from './Settings';
|
||||
import { fetchTopicConfig } from 'redux/actions';
|
||||
import {
|
||||
getTopicConfig,
|
||||
getTopicConfigFetched,
|
||||
} from 'redux/reducers/topics/selectors';
|
||||
|
||||
import Settings from './Settings';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
topicName: TopicName;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterName } } }: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { topicName, clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
clusterName,
|
||||
topicName,
|
||||
config: getTopicConfig(state, topicName),
|
||||
|
@ -26,7 +30,8 @@ const mapStateToProps = (state: RootState, { match: { params: { topicName, clust
|
|||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchTopicConfig: (clusterName: ClusterName, topicName: TopicName) => fetchTopicConfig(clusterName, topicName),
|
||||
fetchTopicConfig: (clusterName: ClusterName, topicName: TopicName) =>
|
||||
fetchTopicConfig(clusterName, topicName),
|
||||
};
|
||||
|
||||
export default withRouter(
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import React from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
import { TopicWithDetailedInfo, ClusterName } from 'redux/interfaces';
|
||||
import ListItem from './ListItem';
|
||||
import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { clusterTopicNewPath } from 'lib/paths';
|
||||
import ListItem from './ListItem';
|
||||
|
||||
interface Props {
|
||||
clusterName: ClusterName;
|
||||
topics: (TopicWithDetailedInfo)[];
|
||||
externalTopics: (TopicWithDetailedInfo)[];
|
||||
topics: TopicWithDetailedInfo[];
|
||||
externalTopics: TopicWithDetailedInfo[];
|
||||
}
|
||||
|
||||
const List: React.FC<Props> = ({
|
||||
clusterName,
|
||||
topics,
|
||||
externalTopics,
|
||||
}) => {
|
||||
const List: React.FC<Props> = ({ clusterName, topics, externalTopics }) => {
|
||||
const [showInternal, setShowInternal] = React.useState<boolean>(true);
|
||||
|
||||
const handleSwitch = () => setShowInternal(!showInternal);
|
||||
|
@ -38,9 +35,7 @@ const List: React.FC<Props> = ({
|
|||
checked={showInternal}
|
||||
onChange={handleSwitch}
|
||||
/>
|
||||
<label htmlFor="switchRoundedDefault">
|
||||
Show Internal Topics
|
||||
</label>
|
||||
<label htmlFor="switchRoundedDefault">Show Internal Topics</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-right">
|
||||
|
@ -64,11 +59,8 @@ const List: React.FC<Props> = ({
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.map((topic, index) => (
|
||||
<ListItem
|
||||
key={`topic-list-item-key-${index}`}
|
||||
{...topic}
|
||||
/>
|
||||
{items.map((topic) => (
|
||||
<ListItem key={v4()} topic={topic} />
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {ClusterName, RootState} from 'redux/interfaces';
|
||||
import { getTopicList, getExternalTopicList } from 'redux/reducers/topics/selectors';
|
||||
import List from './List';
|
||||
import { ClusterName, RootState } from 'redux/interfaces';
|
||||
import {
|
||||
getTopicList,
|
||||
getExternalTopicList,
|
||||
} from 'redux/reducers/topics/selectors';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import List from './List';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { clusterName } } }: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
clusterName,
|
||||
topics: getTopicList(state),
|
||||
externalTopics: getExternalTopicList(state),
|
||||
});
|
||||
|
||||
export default withRouter(
|
||||
connect(mapStateToProps)(List)
|
||||
);
|
||||
export default withRouter(connect(mapStateToProps)(List));
|
||||
|
|
|
@ -3,10 +3,12 @@ import cx from 'classnames';
|
|||
import { NavLink } from 'react-router-dom';
|
||||
import { TopicWithDetailedInfo } from 'redux/interfaces';
|
||||
|
||||
const ListItem: React.FC<TopicWithDetailedInfo> = ({
|
||||
name,
|
||||
internal,
|
||||
partitions,
|
||||
interface ListItemProps {
|
||||
topic: TopicWithDetailedInfo;
|
||||
}
|
||||
|
||||
const ListItem: React.FC<ListItemProps> = ({
|
||||
topic: { name, internal, partitions },
|
||||
}) => {
|
||||
const outOfSyncReplicas = React.useMemo(() => {
|
||||
if (partitions === undefined || partitions.length === 0) {
|
||||
|
@ -14,27 +16,34 @@ const ListItem: React.FC<TopicWithDetailedInfo> = ({
|
|||
}
|
||||
|
||||
return partitions.reduce((memo: number, { replicas }) => {
|
||||
const outOfSync = replicas.filter(({ inSync }) => !inSync)
|
||||
const outOfSync = replicas.filter(({ inSync }) => !inSync);
|
||||
return memo + outOfSync.length;
|
||||
}, 0);
|
||||
}, [partitions])
|
||||
}, [partitions]);
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<NavLink exact to={`topics/${name}`} activeClassName="is-active" className="title is-6">
|
||||
<NavLink
|
||||
exact
|
||||
to={`topics/${name}`}
|
||||
activeClassName="is-active"
|
||||
className="title is-6"
|
||||
>
|
||||
{name}
|
||||
</NavLink>
|
||||
</td>
|
||||
<td>{partitions.length}</td>
|
||||
<td>{outOfSyncReplicas}</td>
|
||||
<td>
|
||||
<div className={cx('tag is-small', internal ? 'is-light' : 'is-success')}>
|
||||
<div
|
||||
className={cx('tag is-small', internal ? 'is-light' : 'is-success')}
|
||||
>
|
||||
{internal ? 'Internal' : 'External'}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default ListItem;
|
||||
|
|
|
@ -1,35 +1,48 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { RootState, ClusterName, TopicFormData, TopicName, Action } from 'redux/interfaces';
|
||||
import New from './New';
|
||||
import {
|
||||
RootState,
|
||||
ClusterName,
|
||||
TopicFormData,
|
||||
TopicName,
|
||||
Action,
|
||||
} from 'redux/interfaces';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { createTopic } from 'redux/actions';
|
||||
import { getTopicCreated } from 'redux/reducers/topics/selectors';
|
||||
import { clusterTopicPath } from 'lib/paths';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import * as actions from "../../../redux/actions/actions";
|
||||
import New from './New';
|
||||
import * as actions from '../../../redux/actions/actions';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { clusterName } } }: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
clusterName,
|
||||
isTopicCreated: getTopicCreated(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: ThunkDispatch<RootState, undefined, Action>, { history }: OwnProps) => ({
|
||||
const mapDispatchToProps = (
|
||||
dispatch: ThunkDispatch<RootState, undefined, Action>,
|
||||
{ history }: OwnProps
|
||||
) => ({
|
||||
createTopic: (clusterName: ClusterName, form: TopicFormData) => {
|
||||
dispatch(createTopic(clusterName, form));
|
||||
},
|
||||
redirectToTopicPath: (clusterName: ClusterName, topicName: TopicName) => {
|
||||
history.push(clusterTopicPath(clusterName, topicName));
|
||||
},
|
||||
resetUploadedState: (() => dispatch(actions.createTopicAction.failure()))
|
||||
resetUploadedState: () => dispatch(actions.createTopicAction.failure()),
|
||||
});
|
||||
|
||||
|
||||
export default withRouter(
|
||||
connect(mapStateToProps, mapDispatchToProps)(New)
|
||||
);
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(New));
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { fetchTopicList } from 'redux/actions';
|
||||
import Topics from './Topics';
|
||||
import { getIsTopicListFetched } from 'redux/reducers/topics/selectors';
|
||||
import { RootState, ClusterName } from 'redux/interfaces';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import Topics from './Topics';
|
||||
|
||||
interface RouteProps {
|
||||
clusterName: ClusterName;
|
||||
}
|
||||
|
||||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
type OwnProps = RouteComponentProps<RouteProps>;
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { clusterName } }}: OwnProps) => ({
|
||||
const mapStateToProps = (
|
||||
state: RootState,
|
||||
{
|
||||
match: {
|
||||
params: { clusterName },
|
||||
},
|
||||
}: OwnProps
|
||||
) => ({
|
||||
isFetched: getIsTopicListFetched(state),
|
||||
clusterName,
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
interface Link {
|
||||
label: string;
|
||||
|
@ -10,15 +11,13 @@ interface Props {
|
|||
links?: Link[];
|
||||
}
|
||||
|
||||
const Breadcrumb: React.FC<Props> = ({
|
||||
links,
|
||||
children,
|
||||
}) => {
|
||||
const Breadcrumb: React.FC<Props> = ({ links, children }) => {
|
||||
return (
|
||||
<nav className="breadcrumb" aria-label="breadcrumbs">
|
||||
<ul>
|
||||
{links && links.map(({ label, href }, index) => (
|
||||
<li key={`breadcrumb-item-key-${index}`}>
|
||||
{links &&
|
||||
links.map(({ label, href }) => (
|
||||
<li key={v4()}>
|
||||
<NavLink to={href}>{label}</NavLink>
|
||||
</li>
|
||||
))}
|
||||
|
@ -29,6 +28,6 @@ const Breadcrumb: React.FC<Props> = ({
|
|||
</ul>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Breadcrumb;
|
||||
|
|
|
@ -5,19 +5,15 @@ interface Props {
|
|||
title?: string;
|
||||
}
|
||||
|
||||
const Indicator: React.FC<Props> = ({
|
||||
label,
|
||||
title,
|
||||
children,
|
||||
}) => {
|
||||
const Indicator: React.FC<Props> = ({ label, title, children }) => {
|
||||
return (
|
||||
<div className="level-item level-left">
|
||||
<div title={title ? title : label}>
|
||||
<div title={title || label}>
|
||||
<p className="heading">{label}</p>
|
||||
<p className="title">{children}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Indicator;
|
||||
|
|
|
@ -13,16 +13,10 @@ const MetricsWrapper: React.FC<Props> = ({
|
|||
}) => {
|
||||
return (
|
||||
<div className={cx('box', wrapperClassName)}>
|
||||
{title && (
|
||||
<h5 className="subtitle is-6">
|
||||
{title}
|
||||
</h5>
|
||||
)}
|
||||
<div className="level">
|
||||
{children}
|
||||
</div>
|
||||
{title && <h5 className="subtitle is-6">{title}</h5>}
|
||||
<div className="level">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default MetricsWrapper;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
@ -16,7 +15,7 @@ ReactDOM.render(
|
|||
<AppContainer />
|
||||
</BrowserRouter>
|
||||
</Provider>,
|
||||
document.getElementById('root'),
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
|
|
|
@ -5,26 +5,21 @@ type Callback = () => any;
|
|||
const useInterval = (callback: Callback, delay: number) => {
|
||||
const savedCallback = React.useRef<Callback>();
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
savedCallback.current = callback;
|
||||
},
|
||||
[callback],
|
||||
);
|
||||
}, [callback]);
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
// eslint-disable-next-line consistent-return
|
||||
React.useEffect(() => {
|
||||
const tick = () => {
|
||||
savedCallback.current && savedCallback.current()
|
||||
if (savedCallback.current) savedCallback.current();
|
||||
};
|
||||
|
||||
if (delay !== null) {
|
||||
const id = setInterval(tick, delay);
|
||||
return () => clearInterval(id);
|
||||
}
|
||||
},
|
||||
[delay],
|
||||
);
|
||||
}
|
||||
}, [delay]);
|
||||
};
|
||||
|
||||
export default useInterval;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
function formatBytes(bytes: number, decimals: number = 0) {
|
||||
function formatBytes(bytes: number, decimals = 0) {
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
if (bytes === 0) return [0, sizes[0]];
|
||||
|
||||
|
@ -7,7 +7,7 @@ function formatBytes(bytes: number, decimals: number = 0) {
|
|||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return [parseFloat((bytes / Math.pow(k, i)).toFixed(dm)), sizes[i]];
|
||||
return [parseFloat((bytes / k ** i).toFixed(dm)), sizes[i]];
|
||||
}
|
||||
|
||||
export default formatBytes;
|
||||
|
|
2
kafka-ui-react-app/src/react-app-env.d.ts
vendored
2
kafka-ui-react-app/src/react-app-env.d.ts
vendored
|
@ -1 +1 @@
|
|||
/// <reference types="react-scripts" />
|
||||
// / <reference types="react-scripts" />
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import {
|
||||
Cluster,
|
||||
} from 'redux/interfaces';
|
||||
import {
|
||||
BASE_URL,
|
||||
BASE_PARAMS,
|
||||
} from 'lib/constants';
|
||||
import { Cluster } from 'redux/interfaces';
|
||||
import { BASE_URL, BASE_PARAMS } from 'lib/constants';
|
||||
|
||||
export const getClusters = (): Promise<Cluster[]> =>
|
||||
fetch(`${BASE_URL}/clusters`, { ...BASE_PARAMS })
|
||||
.then(res => res.json());
|
||||
fetch(`${BASE_URL}/clusters`, { ...BASE_PARAMS }).then((res) => res.json());
|
||||
|
|
|
@ -1,12 +1,23 @@
|
|||
import { ClusterName } from '../interfaces/cluster';
|
||||
import { ConsumerGroup, ConsumerGroupID, ConsumerGroupDetails } from '../interfaces/consumerGroup';
|
||||
import {
|
||||
ConsumerGroup,
|
||||
ConsumerGroupID,
|
||||
ConsumerGroupDetails,
|
||||
} from '../interfaces/consumerGroup';
|
||||
import { BASE_PARAMS, BASE_URL } from '../../lib/constants';
|
||||
|
||||
export const getConsumerGroups = (
|
||||
clusterName: ClusterName
|
||||
): Promise<ConsumerGroup[]> =>
|
||||
fetch(`${BASE_URL}/clusters/${clusterName}/consumerGroups`, {
|
||||
...BASE_PARAMS,
|
||||
}).then((res) => res.json());
|
||||
|
||||
export const getConsumerGroups = (clusterName: ClusterName): Promise<ConsumerGroup[]> =>
|
||||
fetch(`${BASE_URL}/clusters/${clusterName}/consumerGroups`, { ...BASE_PARAMS })
|
||||
.then(res => res.json());
|
||||
|
||||
export const getConsumerGroupDetails = (clusterName: ClusterName, consumerGroupID: ConsumerGroupID): Promise<ConsumerGroupDetails> =>
|
||||
fetch(`${BASE_URL}/clusters/${clusterName}/consumer-groups/${consumerGroupID}`, { ...BASE_PARAMS })
|
||||
.then(res => res.json());
|
||||
export const getConsumerGroupDetails = (
|
||||
clusterName: ClusterName,
|
||||
consumerGroupID: ConsumerGroupID
|
||||
): Promise<ConsumerGroupDetails> =>
|
||||
fetch(
|
||||
`${BASE_URL}/clusters/${clusterName}/consumer-groups/${consumerGroupID}`,
|
||||
{ ...BASE_PARAMS }
|
||||
).then((res) => res.json());
|
||||
|
|
|
@ -6,9 +6,12 @@ export interface Broker {
|
|||
segmentSize: number;
|
||||
partitionReplicas: number;
|
||||
bytesOutPerSec: number;
|
||||
};
|
||||
}
|
||||
|
||||
export enum ZooKeeperStatus { offline, online };
|
||||
export enum ZooKeeperStatus {
|
||||
offline,
|
||||
online,
|
||||
}
|
||||
|
||||
export interface BrokerDiskUsage {
|
||||
brokerId: BrokerId;
|
||||
|
@ -21,8 +24,8 @@ export interface BrokerMetrics {
|
|||
activeControllers: number;
|
||||
onlinePartitionCount: number;
|
||||
offlinePartitionCount: number;
|
||||
inSyncReplicasCount: number,
|
||||
outOfSyncReplicasCount: number,
|
||||
inSyncReplicasCount: number;
|
||||
outOfSyncReplicasCount: number;
|
||||
underReplicatedPartitionCount: number;
|
||||
diskUsage: BrokerDiskUsage[];
|
||||
}
|
||||
|
|
|
@ -33,4 +33,9 @@ export interface RootState {
|
|||
|
||||
export type Action = ActionType<typeof actions>;
|
||||
|
||||
export type PromiseThunk<T> = ThunkAction<Promise<T>, RootState, undefined, AnyAction>;
|
||||
export type PromiseThunk<T> = ThunkAction<
|
||||
Promise<T>,
|
||||
RootState,
|
||||
undefined,
|
||||
AnyAction
|
||||
>;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import { Cluster, RootState, FetchStatus, ClusterStatus } from 'redux/interfaces';
|
||||
import {
|
||||
Cluster,
|
||||
RootState,
|
||||
FetchStatus,
|
||||
ClusterStatus,
|
||||
} from 'redux/interfaces';
|
||||
import { createFetchingSelector } from 'redux/reducers/loader/selectors';
|
||||
|
||||
const clustersState = ({ clusters }: RootState): Cluster[] => clusters;
|
||||
|
@ -8,21 +13,18 @@ const getClusterListFetchingStatus = createFetchingSelector('GET_CLUSTERS');
|
|||
|
||||
export const getIsClusterListFetched = createSelector(
|
||||
getClusterListFetchingStatus,
|
||||
(status) => status === FetchStatus.fetched,
|
||||
(status) => status === FetchStatus.fetched
|
||||
);
|
||||
|
||||
export const getClusterList = createSelector(clustersState, (clusters) => clusters);
|
||||
|
||||
export const getOnlineClusters = createSelector(
|
||||
getClusterList,
|
||||
(clusters) => clusters.filter(
|
||||
({ status }) => status === ClusterStatus.Online,
|
||||
),
|
||||
export const getClusterList = createSelector(
|
||||
clustersState,
|
||||
(clusters) => clusters
|
||||
);
|
||||
|
||||
export const getOfflineClusters = createSelector(
|
||||
getClusterList,
|
||||
(clusters) => clusters.filter(
|
||||
({ status }) => status === ClusterStatus.Offline,
|
||||
),
|
||||
export const getOnlineClusters = createSelector(getClusterList, (clusters) =>
|
||||
clusters.filter(({ status }) => status === ClusterStatus.Online)
|
||||
);
|
||||
|
||||
export const getOfflineClusters = createSelector(getClusterList, (clusters) =>
|
||||
clusters.filter(({ status }) => status === ClusterStatus.Offline)
|
||||
);
|
||||
|
|
|
@ -1,25 +1,35 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import { RootState, FetchStatus } from 'redux/interfaces';
|
||||
import { createFetchingSelector } from 'redux/reducers/loader/selectors';
|
||||
import { ConsumerGroupID, ConsumerGroupsState } from '../../interfaces/consumerGroup';
|
||||
import {
|
||||
ConsumerGroupID,
|
||||
ConsumerGroupsState,
|
||||
} from '../../interfaces/consumerGroup';
|
||||
|
||||
const consumerGroupsState = ({
|
||||
consumerGroups,
|
||||
}: RootState): ConsumerGroupsState => consumerGroups;
|
||||
|
||||
const consumerGroupsState = ({ consumerGroups }: RootState): ConsumerGroupsState => consumerGroups;
|
||||
const getConsumerGroupsMap = (state: RootState) =>
|
||||
consumerGroupsState(state).byID;
|
||||
const getConsumerGroupsIDsList = (state: RootState) =>
|
||||
consumerGroupsState(state).allIDs;
|
||||
|
||||
const getConsumerGroupsMap = (state: RootState) => consumerGroupsState(state).byID;
|
||||
const getConsumerGroupsIDsList = (state: RootState) => consumerGroupsState(state).allIDs;
|
||||
|
||||
const getConsumerGroupsListFetchingStatus = createFetchingSelector('GET_CONSUMER_GROUPS');
|
||||
const getConsumerGroupDetailsFetchingStatus = createFetchingSelector('GET_CONSUMER_GROUP_DETAILS');
|
||||
const getConsumerGroupsListFetchingStatus = createFetchingSelector(
|
||||
'GET_CONSUMER_GROUPS'
|
||||
);
|
||||
const getConsumerGroupDetailsFetchingStatus = createFetchingSelector(
|
||||
'GET_CONSUMER_GROUP_DETAILS'
|
||||
);
|
||||
|
||||
export const getIsConsumerGroupsListFetched = createSelector(
|
||||
getConsumerGroupsListFetchingStatus,
|
||||
(status) => status === FetchStatus.fetched,
|
||||
(status) => status === FetchStatus.fetched
|
||||
);
|
||||
|
||||
export const getIsConsumerGroupDetailsFetched = createSelector(
|
||||
getConsumerGroupDetailsFetchingStatus,
|
||||
(status) => status === FetchStatus.fetched,
|
||||
(status) => status === FetchStatus.fetched
|
||||
);
|
||||
|
||||
export const getConsumerGroupsList = createSelector(
|
||||
|
@ -31,14 +41,15 @@ export const getConsumerGroupsList = createSelector(
|
|||
return [];
|
||||
}
|
||||
|
||||
return ids.map(key => byID[key]);
|
||||
},
|
||||
return ids.map((key) => byID[key]);
|
||||
}
|
||||
);
|
||||
|
||||
const getConsumerGroupID = (_: RootState, consumerGroupID: ConsumerGroupID) => consumerGroupID;
|
||||
const getConsumerGroupID = (_: RootState, consumerGroupID: ConsumerGroupID) =>
|
||||
consumerGroupID;
|
||||
|
||||
export const getConsumerGroupByID = createSelector(
|
||||
getConsumerGroupsMap,
|
||||
getConsumerGroupID,
|
||||
(consumerGroups, consumerGroupID) => consumerGroups[consumerGroupID],
|
||||
(consumerGroups, consumerGroupID) => consumerGroups[consumerGroupID]
|
||||
);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import { RootState } from 'redux/interfaces';
|
||||
import topics from './topics/reducer';
|
||||
import clusters from './clusters/reducer';
|
||||
import brokers from './brokers/reducer';
|
||||
import consumerGroups from './consumerGroups/reducer';
|
||||
import loader from './loader/reducer';
|
||||
import { RootState } from 'redux/interfaces';
|
||||
|
||||
export default combineReducers<RootState>({
|
||||
topics,
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
import {
|
||||
FetchStatus,
|
||||
Action,
|
||||
LoaderState,
|
||||
} from 'redux/interfaces';
|
||||
import { FetchStatus, Action, LoaderState } from 'redux/interfaces';
|
||||
|
||||
export const initialState: LoaderState = {};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { RootState, FetchStatus } from 'redux/interfaces';
|
||||
|
||||
export const createFetchingSelector = (action: string) =>
|
||||
(state: RootState) => (state.loader[action] || FetchStatus.notFetched);
|
||||
export const createFetchingSelector = (action: string) => (state: RootState) =>
|
||||
state.loader[action] || FetchStatus.notFetched;
|
||||
|
|
|
@ -5,13 +5,12 @@ import rootReducer from '../../reducers';
|
|||
export default () => {
|
||||
const middlewares = [thunk];
|
||||
|
||||
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
const composeEnhancers =
|
||||
(window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
|
||||
const enhancer = composeEnhancers(
|
||||
applyMiddleware(...middlewares),
|
||||
);
|
||||
const enhancer = composeEnhancers(applyMiddleware(...middlewares));
|
||||
|
||||
const store = createStore(rootReducer, undefined, enhancer);
|
||||
|
||||
return store
|
||||
return store;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import devConfigureStore from './dev';
|
||||
import prodConfigureStore from './prod';
|
||||
|
||||
const configureStore = (process.env.NODE_ENV === 'production') ? prodConfigureStore : devConfigureStore
|
||||
const configureStore =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? prodConfigureStore
|
||||
: devConfigureStore;
|
||||
|
||||
export default configureStore;
|
||||
|
|
|
@ -3,11 +3,11 @@ import thunk from 'redux-thunk';
|
|||
import rootReducer from '../../reducers';
|
||||
|
||||
export default () => {
|
||||
const middlewares = [thunk]
|
||||
const middlewares = [thunk];
|
||||
|
||||
const enhancer = applyMiddleware(...middlewares);
|
||||
|
||||
const store = createStore(rootReducer, undefined, enhancer);
|
||||
|
||||
return store
|
||||
return store;
|
||||
};
|
||||
|
|
|
@ -25,47 +25,10 @@ type Config = {
|
|||
onUpdate?: (registration: ServiceWorkerRegistration) => void;
|
||||
};
|
||||
|
||||
export function register(config?: Config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(
|
||||
process.env.PUBLIC_URL,
|
||||
window.location.href
|
||||
);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerValidSW(swUrl: string, config?: Config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
|
@ -101,7 +64,7 @@ function registerValidSW(swUrl: string, config?: Config) {
|
|||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error) => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
@ -109,9 +72,9 @@ function registerValidSW(swUrl: string, config?: Config) {
|
|||
function checkValidServiceWorker(swUrl: string, config?: Config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl, {
|
||||
headers: { 'Service-Worker': 'script' }
|
||||
headers: { 'Service-Worker': 'script' },
|
||||
})
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
|
@ -119,7 +82,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
|
|||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
|
@ -136,9 +99,44 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
|
|||
});
|
||||
}
|
||||
|
||||
export function register(config?: Config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
const url = process.env.PUBLIC_URL || 'localhost';
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(url, window.location.href);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
|
Loading…
Add table
Reference in a new issue