use cluster name instead of cluster id

This commit is contained in:
Zhenya Taran 2020-03-01 16:07:33 +02:00
parent 01c2c8b20b
commit 8b64575bd5
34 changed files with 224 additions and 234 deletions

View file

@ -16,11 +16,8 @@ public class ClustersProperties {
@Data @Data
public static class Cluster { public static class Cluster {
String id;
String name; String name;
String bootstrapServers; String bootstrapServers;
String jmxHost;
String jmxPort;
String zookeeper; String zookeeper;
} }
} }

View file

@ -7,14 +7,13 @@ import org.mapstruct.factory.Mappers;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.util.ArrayList; import java.util.*;
import java.util.List;
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class ClustersStorage { public class ClustersStorage {
private final List<KafkaCluster> kafkaClusters = new ArrayList<>(); private final Map<String, KafkaCluster> kafkaClusters = new HashMap<>();
private final ClustersProperties clusterProperties; private final ClustersProperties clusterProperties;
@ -23,18 +22,18 @@ public class ClustersStorage {
@PostConstruct @PostConstruct
public void init() { public void init() {
for (ClustersProperties.Cluster clusterProperties : clusterProperties.getClusters()) { for (ClustersProperties.Cluster clusterProperties : clusterProperties.getClusters()) {
kafkaClusters.add(clusterMapper.toKafkaCluster(clusterProperties)); if (kafkaClusters.get(clusterProperties.getName()) != null) {
throw new IllegalStateException("Application config isn't correct. Two clusters can't have the same name");
}
kafkaClusters.put(clusterProperties.getName(), clusterMapper.toKafkaCluster(clusterProperties));
} }
} }
public List<KafkaCluster> getKafkaClusters() { public Collection<KafkaCluster> getKafkaClusters() {
return kafkaClusters; return kafkaClusters.values();
} }
public KafkaCluster getClusterById(String clusterId) { public KafkaCluster getClusterByName(String clusterName) {
return kafkaClusters.stream() return kafkaClusters.get(clusterName);
.filter(cluster -> cluster.getId() != null && cluster.getId().equals(clusterId))
.findFirst()
.orElse(null);
} }
} }

View file

@ -29,32 +29,32 @@ public class ClusterService {
return Mono.just(ResponseEntity.ok(Flux.fromIterable(clusters))); return Mono.just(ResponseEntity.ok(Flux.fromIterable(clusters)));
} }
public Mono<ResponseEntity<BrokersMetrics>> getBrokersMetrics(String clusterId) { public Mono<ResponseEntity<BrokersMetrics>> getBrokersMetrics(String name) {
KafkaCluster cluster = clustersStorage.getClusterById(clusterId); KafkaCluster cluster = clustersStorage.getClusterByName(name);
if (cluster == null) return null; if (cluster == null) return null;
return Mono.just(ResponseEntity.ok(cluster.getBrokersMetrics())); return Mono.just(ResponseEntity.ok(cluster.getBrokersMetrics()));
} }
public Mono<ResponseEntity<Flux<Topic>>> getTopics(String clusterId) { public Mono<ResponseEntity<Flux<Topic>>> getTopics(String name) {
KafkaCluster cluster = clustersStorage.getClusterById(clusterId); KafkaCluster cluster = clustersStorage.getClusterByName(name);
if (cluster == null) return null; if (cluster == null) return null;
return Mono.just(ResponseEntity.ok(Flux.fromIterable(cluster.getTopics()))); return Mono.just(ResponseEntity.ok(Flux.fromIterable(cluster.getTopics())));
} }
public Mono<ResponseEntity<TopicDetails>> getTopicDetails(String clusterId, String topicName) { public Mono<ResponseEntity<TopicDetails>> getTopicDetails(String name, String topicName) {
KafkaCluster cluster = clustersStorage.getClusterById(clusterId); KafkaCluster cluster = clustersStorage.getClusterByName(name);
if (cluster == null) return null; if (cluster == null) return null;
return Mono.just(ResponseEntity.ok(cluster.getOrCreateTopicDetails(topicName))); return Mono.just(ResponseEntity.ok(cluster.getOrCreateTopicDetails(topicName)));
} }
public Mono<ResponseEntity<Flux<TopicConfig>>> getTopicConfigs(String clusterId, String topicName) { public Mono<ResponseEntity<Flux<TopicConfig>>> getTopicConfigs(String name, String topicName) {
KafkaCluster cluster = clustersStorage.getClusterById(clusterId); KafkaCluster cluster = clustersStorage.getClusterByName(name);
if (cluster == null) return null; if (cluster == null) return null;
return Mono.just(ResponseEntity.ok(Flux.fromIterable(cluster.getTopicConfigsMap().get(topicName)))); return Mono.just(ResponseEntity.ok(Flux.fromIterable(cluster.getTopicConfigsMap().get(topicName))));
} }
public Mono<ResponseEntity<Topic>> createTopic(String clusterId, Mono<TopicFormData> topicFormData) { public Mono<ResponseEntity<Topic>> createTopic(String name, Mono<TopicFormData> topicFormData) {
KafkaCluster cluster = clustersStorage.getClusterById(clusterId); KafkaCluster cluster = clustersStorage.getClusterByName(name);
if (cluster == null) return null; if (cluster == null) return null;
return kafkaService.createTopic(cluster, topicFormData); return kafkaService.createTopic(cluster, topicFormData);
} }

View file

@ -139,7 +139,7 @@ public class KafkaService {
} }
private Topic collectTopicData(KafkaCluster kafkaCluster, TopicDescription topicDescription) { private Topic collectTopicData(KafkaCluster kafkaCluster, TopicDescription topicDescription) {
var topic = new Topic().clusterId(kafkaCluster.getId()); var topic = new Topic();
topic.setInternal(topicDescription.isInternal()); topic.setInternal(topicDescription.isInternal());
topic.setName(topicDescription.name()); topic.setName(topicDescription.name());

View file

@ -30,14 +30,14 @@ paths:
items: items:
$ref: '#/components/schemas/Cluster' $ref: '#/components/schemas/Cluster'
/api/clusters/{clusterId}/brokers: /api/clusters/{clusterName}/brokers:
get: get:
tags: tags:
- /api/clusters - /api/clusters
summary: getBrokers summary: getBrokers
operationId: getBrokers operationId: getBrokers
parameters: parameters:
- name: clusterId - name: clusterName
in: path in: path
required: true required: true
schema: schema:
@ -52,14 +52,14 @@ paths:
items: items:
$ref: '#/components/schemas/Broker' $ref: '#/components/schemas/Broker'
/api/clusters/{clusterId}/metrics/broker: /api/clusters/{clusterName}/metrics/broker:
get: get:
tags: tags:
- /api/clusters - /api/clusters
summary: getBrokersMetrics summary: getBrokersMetrics
operationId: getBrokersMetrics operationId: getBrokersMetrics
parameters: parameters:
- name: clusterId - name: clusterName
in: path in: path
required: true required: true
schema: schema:
@ -72,14 +72,14 @@ paths:
schema: schema:
$ref: '#/components/schemas/BrokersMetrics' $ref: '#/components/schemas/BrokersMetrics'
/api/clusters/{clusterId}/topics: /api/clusters/{clusterName}/topics:
get: get:
tags: tags:
- /api/clusters - /api/clusters
summary: getTopics summary: getTopics
operationId: getTopics operationId: getTopics
parameters: parameters:
- name: clusterId - name: clusterName
in: path in: path
required: true required: true
schema: schema:
@ -99,7 +99,7 @@ paths:
summary: createTopic summary: createTopic
operationId: createTopic operationId: createTopic
parameters: parameters:
- name: clusterId - name: clusterName
in: path in: path
required: true required: true
schema: schema:
@ -117,14 +117,14 @@ paths:
schema: schema:
$ref: '#/components/schemas/Topic' $ref: '#/components/schemas/Topic'
/api/clusters/{clusterId}/topics/{topicName}: /api/clusters/{clusterName}/topics/{topicName}:
get: get:
tags: tags:
- /api/clusters - /api/clusters
summary: getTopicDetails summary: getTopicDetails
operationId: getTopicDetails operationId: getTopicDetails
parameters: parameters:
- name: clusterId - name: clusterName
in: path in: path
required: true required: true
schema: schema:
@ -142,14 +142,14 @@ paths:
schema: schema:
$ref: '#/components/schemas/TopicDetails' $ref: '#/components/schemas/TopicDetails'
/api/clusters/{clusterId}/topics/{topicName}/config: /api/clusters/{clusterName}/topics/{topicName}/config:
get: get:
tags: tags:
- /api/clusters - /api/clusters
summary: getTopicConfigs summary: getTopicConfigs
operationId: getTopicConfigs operationId: getTopicConfigs
parameters: parameters:
- name: clusterId - name: clusterName
in: path in: path
required: true required: true
schema: schema:
@ -228,8 +228,6 @@ components:
Topic: Topic:
type: object type: object
properties: properties:
clusterId:
type: string
name: name:
type: string type: string
internal: internal:

View file

@ -1,5 +1,4 @@
const jsonServer = require('json-server'); const jsonServer = require('json-server');
const _ = require('lodash');
const clusters = require('./payload/clusters.json'); const clusters = require('./payload/clusters.json');
const brokers = require('./payload/brokers.json'); const brokers = require('./payload/brokers.json');
const brokerMetrics = require('./payload/brokerMetrics.json'); const brokerMetrics = require('./payload/brokerMetrics.json');
@ -8,13 +7,13 @@ const topicDetails = require('./payload/topicDetails.json');
const topicConfigs = require('./payload/topicConfigs.json'); const topicConfigs = require('./payload/topicConfigs.json');
const db = { const db = {
clusters, clusters,
brokers, brokers,
brokerMetrics: brokerMetrics.map(({ clusterId, ...rest }) => ({ ...rest, id: clusterId })), brokerMetrics: brokerMetrics.map(({clusterName, ...rest}) => ({...rest, id: clusterName})),
topics: topics.map((topic) => ({ ...topic, id: topic.name })), topics: topics.map((topic) => ({...topic, id: topic.name})),
topicDetails, topicDetails,
topicConfigs, topicConfigs,
} };
const server = jsonServer.create(); const server = jsonServer.create();
const router = jsonServer.router(db); const router = jsonServer.router(db);
const middlewares = jsonServer.defaults(); const middlewares = jsonServer.defaults();
@ -29,11 +28,10 @@ server.use((_req, _res, next) => {
server.use( server.use(
jsonServer.rewriter({ jsonServer.rewriter({
'/*': '/$1', '/api/*': '/$1',
'/clusters/:clusterId/metrics/broker': '/brokerMetrics/:clusterId', '/clusters/:clusterName/metrics/broker': '/brokerMetrics/:clusterName',
'/clusters/:clusterId/topics/:id': '/topicDetails', '/clusters/:clusterName/topics/:id': '/topicDetails',
'/clusters/:clusterId/topics/:id/config': '/topicDetails', '/clusters/:clusterName/topics/:id/config': '/topicConfigs',
'/clusters/:clusterId/topics/:id/config': '/topicConfigs',
}) })
); );

View file

@ -1,6 +1,6 @@
[ [
{ {
"clusterId": "wrYGf-csNgiGdK7B_ADF7Z", "clusterName": "fake.cluster",
"bytesInPerSec": 8027, "bytesInPerSec": 8027,
"brokerCount": 1, "brokerCount": 1,
"zooKeeperStatus": 1, "zooKeeperStatus": 1,
@ -20,7 +20,7 @@
"diskUsageDistribution": "even" "diskUsageDistribution": "even"
}, },
{ {
"clusterId": "dMMQx-WRh77BKYas_g2ZTz", "clusterName": "kafka-ui.cluster",
"bytesInPerSec": 8194, "bytesInPerSec": 8194,
"brokerCount": 1, "brokerCount": 1,
"zooKeeperStatus": 1, "zooKeeperStatus": 1,

View file

@ -1,7 +1,7 @@
[ [
{ {
"brokerId": 1, "brokerId": 1,
"clusterId": "wrYGf-csNgiGdK7B_ADF7Z", "name": "fake.cluster",
"bytesInPerSec": 1234, "bytesInPerSec": 1234,
"bytesOutPerSec": 3567, "bytesOutPerSec": 3567,
"segmentSize": 912360707, "segmentSize": 912360707,
@ -9,7 +9,7 @@
}, },
{ {
"brokerId": 2, "brokerId": 2,
"clusterId": "dMMQx-WRh77BKYas_g2ZTz", "name": "kafka-ui.cluster",
"bytesInPerSec": 9194, "bytesInPerSec": 9194,
"bytesOutPerSec": 7924, "bytesOutPerSec": 7924,
"segmentSize": 840060707, "segmentSize": 840060707,

View file

@ -1,6 +1,6 @@
[ [
{ {
"id": "wrYGf-csNgiGdK7B_ADF7Z", "id": "fake.cluster",
"name": "fake.cluster", "name": "fake.cluster",
"defaultCluster": true, "defaultCluster": true,
"status": "online", "status": "online",
@ -11,7 +11,7 @@
"bytesOutPerSec": 4320 "bytesOutPerSec": 4320
}, },
{ {
"id": "dMMQx-WRh77BKYas_g2ZTz", "id": "kafka-ui.cluster",
"name": "kafka-ui.cluster", "name": "kafka-ui.cluster",
"defaultCluster": false, "defaultCluster": false,
"status": "offline", "status": "offline",

View file

@ -1,6 +1,6 @@
[ [
{ {
"clusterId": "wrYGf-csNgiGdK7B_ADF7Z", "clusterId": "fake.cluster",
"name": "docker-connect-status", "name": "docker-connect-status",
"internal": true, "internal": true,
"partitions": [ "partitions": [
@ -62,7 +62,7 @@
] ]
}, },
{ {
"clusterId": "wrYGf-csNgiGdK7B_ADF7Z", "clusterId": "fake.cluster",
"name": "dsadsda", "name": "dsadsda",
"internal": false, "internal": false,
"partitions": [ "partitions": [
@ -80,7 +80,7 @@
] ]
}, },
{ {
"clusterId": "wrYGf-csNgiGdK7B_ADF7Z", "clusterId": "fake.cluster",
"name": "my-topic", "name": "my-topic",
"internal": false, "internal": false,
"partitions": [ "partitions": [
@ -98,7 +98,7 @@
] ]
}, },
{ {
"clusterId": "wrYGf-csNgiGdK7B_ADF7Z", "clusterId": "fake.cluster",
"name": "docker-connect-offsets", "name": "docker-connect-offsets",
"internal": false, "internal": false,
"partitions": [ "partitions": [
@ -171,7 +171,7 @@
] ]
}, },
{ {
"clusterId": "dMMQx-WRh77BKYas_g2ZTz", "clusterId": "kafka-ui.cluster",
"name": "_schemas", "name": "_schemas",
"internal": false, "internal": false,
"partitions": [ "partitions": [
@ -189,7 +189,7 @@
] ]
}, },
{ {
"clusterId": "dMMQx-WRh77BKYas_g2ZTz", "clusterId": "kafka-ui.cluster",
"name": "docker-connect-configs", "name": "docker-connect-configs",
"internal": false, "internal": false,
"partitions": [ "partitions": [
@ -207,7 +207,7 @@
] ]
}, },
{ {
"clusterId": "dMMQx-WRh77BKYas_g2ZTz", "clusterId": "kafka-ui.cluster",
"name": "_kafka-ui-test-topic-monitoring-message-rekey-store", "name": "_kafka-ui-test-topic-monitoring-message-rekey-store",
"internal": false, "internal": false,
"partitions": [ "partitions": [

View file

@ -37,9 +37,9 @@ const App: React.FC<AppProps> = ({
<Switch> <Switch>
<Route exact path="/" component={Dashboard} /> <Route exact path="/" component={Dashboard} />
<Route exact path="/clusters" component={Dashboard} /> <Route exact path="/clusters" component={Dashboard} />
<Route path="/clusters/:clusterId/topics" component={TopicsContainer} /> <Route path="/clusters/:clusterName/topics" component={TopicsContainer} />
<Route path="/clusters/:clusterId/brokers" component={BrokersContainer} /> <Route path="/clusters/:clusterName/brokers" component={BrokersContainer} />
<Redirect from="/clusters/:clusterId" to="/clusters/:clusterId/brokers" /> <Redirect from="/clusters/:clusterName" to="/clusters/:clusterName/brokers" />
</Switch> </Switch>
) : ( ) : (
<PageLoader /> <PageLoader />
@ -48,6 +48,6 @@ const App: React.FC<AppProps> = ({
</main> </main>
</div> </div>
); );
} };
export default App; export default App;

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { ClusterId, BrokerMetrics, ZooKeeperStatus } from 'redux/interfaces'; import { ClusterName, BrokerMetrics, ZooKeeperStatus } from 'redux/interfaces';
import useInterval from 'lib/hooks/useInterval'; import useInterval from 'lib/hooks/useInterval';
import formatBytes from 'lib/utils/formatBytes'; import formatBytes from 'lib/utils/formatBytes';
import cx from 'classnames'; import cx from 'classnames';
@ -8,16 +8,16 @@ import Indicator from 'components/common/Dashboard/Indicator';
import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb'; import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb';
interface Props extends BrokerMetrics { interface Props extends BrokerMetrics {
clusterId: string; clusterName: ClusterName;
isFetched: boolean; isFetched: boolean;
minDiskUsage: number; minDiskUsage: number;
maxDiskUsage: number; maxDiskUsage: number;
fetchBrokers: (clusterId: ClusterId) => void; fetchBrokers: (clusterName: ClusterName) => void;
fetchBrokerMetrics: (clusterId: ClusterId) => void; fetchBrokerMetrics: (clusterName: ClusterName) => void;
} }
const Topics: React.FC<Props> = ({ const Topics: React.FC<Props> = ({
clusterId, clusterName,
isFetched, isFetched,
brokerCount, brokerCount,
activeControllers, activeControllers,
@ -35,13 +35,13 @@ const Topics: React.FC<Props> = ({
}) => { }) => {
React.useEffect( React.useEffect(
() => { () => {
fetchBrokers(clusterId); fetchBrokers(clusterName);
fetchBrokerMetrics(clusterId); fetchBrokerMetrics(clusterName);
}, },
[fetchBrokers, fetchBrokerMetrics, clusterId], [fetchBrokers, fetchBrokerMetrics, clusterName],
); );
useInterval(() => { fetchBrokerMetrics(clusterId); }, 5000); useInterval(() => { fetchBrokerMetrics(clusterName); }, 5000);
const [minDiskUsageValue, minDiskUsageSize] = formatBytes(minDiskUsage); const [minDiskUsageValue, minDiskUsageSize] = formatBytes(minDiskUsage);
const [maxDiskUsageValue, maxDiskUsageSize] = formatBytes(maxDiskUsage); const [maxDiskUsageValue, maxDiskUsageSize] = formatBytes(maxDiskUsage);
@ -116,6 +116,6 @@ const Topics: React.FC<Props> = ({
</MetricsWrapper> </MetricsWrapper>
</div> </div>
); );
} };
export default Topics; export default Topics;

View file

@ -5,18 +5,18 @@ import {
} from 'redux/actions'; } from 'redux/actions';
import Brokers from './Brokers'; import Brokers from './Brokers';
import * as brokerSelectors from 'redux/reducers/brokers/selectors'; import * as brokerSelectors from 'redux/reducers/brokers/selectors';
import { RootState, ClusterId } from 'redux/interfaces'; import { RootState, ClusterName } from 'redux/interfaces';
import { RouteComponentProps } from 'react-router-dom'; import { RouteComponentProps } from 'react-router-dom';
interface RouteProps { interface RouteProps {
clusterId: string; clusterName: ClusterName;
} }
interface OwnProps extends RouteComponentProps<RouteProps> { } interface OwnProps extends RouteComponentProps<RouteProps> { }
const mapStateToProps = (state: RootState, { match: { params: { clusterId } }}: OwnProps) => ({ const mapStateToProps = (state: RootState, { match: { params: { clusterName } }}: OwnProps) => ({
isFetched: brokerSelectors.getIsBrokerListFetched(state), isFetched: brokerSelectors.getIsBrokerListFetched(state),
clusterId, clusterName,
brokerCount: brokerSelectors.getBrokerCount(state), brokerCount: brokerSelectors.getBrokerCount(state),
zooKeeperStatus: brokerSelectors.getZooKeeperStatus(state), zooKeeperStatus: brokerSelectors.getZooKeeperStatus(state),
activeControllers: brokerSelectors.getActiveControllers(state), activeControllers: brokerSelectors.getActiveControllers(state),
@ -31,8 +31,8 @@ const mapStateToProps = (state: RootState, { match: { params: { clusterId } }}:
}); });
const mapDispatchToProps = { const mapDispatchToProps = {
fetchBrokers: (clusterId: ClusterId) => fetchBrokers(clusterId), fetchBrokers: (clusterName: ClusterName) => fetchBrokers(clusterName),
fetchBrokerMetrics: (clusterId: ClusterId) => fetchBrokerMetrics(clusterId), fetchBrokerMetrics: (clusterName: ClusterName) => fetchBrokerMetrics(clusterName),
} };
export default connect(mapStateToProps, mapDispatchToProps)(Brokers); export default connect(mapStateToProps, mapDispatchToProps)(Brokers);

View file

@ -5,7 +5,6 @@ import { NavLink } from 'react-router-dom';
import { clusterBrokersPath } from 'lib/paths'; import { clusterBrokersPath } from 'lib/paths';
const ClusterWidget: React.FC<Cluster> = ({ const ClusterWidget: React.FC<Cluster> = ({
id,
name, name,
status, status,
topicCount, topicCount,
@ -14,7 +13,7 @@ const ClusterWidget: React.FC<Cluster> = ({
bytesOutPerSec, bytesOutPerSec,
onlinePartitionCount, onlinePartitionCount,
}) => ( }) => (
<NavLink to={clusterBrokersPath(id)} className="column is-full-modile is-6"> <NavLink to={clusterBrokersPath(name)} className="column is-full-modile is-6">
<div className="box is-hoverable"> <div className="box is-hoverable">
<div <div
className="title is-6 has-text-overflow-ellipsis" className="title is-6 has-text-overflow-ellipsis"

View file

@ -21,21 +21,20 @@ const DefaultIcon: React.FC = () => {
}; };
const ClusterMenu: React.FC<Props> = ({ const ClusterMenu: React.FC<Props> = ({
id,
name, name,
defaultCluster, defaultCluster,
}) => ( }) => (
<ul className="menu-list"> <ul className="menu-list">
<li> <li>
<NavLink exact to={clusterBrokersPath(id)} title={name} className="has-text-overflow-ellipsis"> <NavLink exact to={clusterBrokersPath(name)} title={name} className="has-text-overflow-ellipsis">
{defaultCluster && <DefaultIcon />} {defaultCluster && <DefaultIcon />}
{name} {name}
</NavLink> </NavLink>
<ul> <ul>
<NavLink to={clusterBrokersPath(id)} activeClassName="is-active" title="Brokers"> <NavLink to={clusterBrokersPath(name)} activeClassName="is-active" title="Brokers">
Brokers Brokers
</NavLink> </NavLink>
<NavLink to={clusterTopicsPath(id)} activeClassName="is-active" title="Topics"> <NavLink to={clusterTopicsPath(name)} activeClassName="is-active" title="Topics">
Topics Topics
</NavLink> </NavLink>
</ul> </ul>

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { ClusterId, Topic, TopicDetails, TopicName } from 'redux/interfaces'; import { ClusterName, Topic, TopicDetails, TopicName } from 'redux/interfaces';
import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb'; import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb';
import { NavLink, Switch, Route } from 'react-router-dom'; import { NavLink, Switch, Route } from 'react-router-dom';
import { clusterTopicsPath, clusterTopicSettingsPath, clusterTopicPath, clusterTopicMessagesPath } from 'lib/paths'; import { clusterTopicsPath, clusterTopicSettingsPath, clusterTopicPath, clusterTopicMessagesPath } from 'lib/paths';
@ -8,12 +8,12 @@ import MessagesContainer from './Messages/MessagesContainer';
import SettingsContainer from './Settings/SettingsContainer'; import SettingsContainer from './Settings/SettingsContainer';
interface Props extends Topic, TopicDetails { interface Props extends Topic, TopicDetails {
clusterId: ClusterId; clusterName: ClusterName;
topicName: TopicName; topicName: TopicName;
} }
const Details: React.FC<Props> = ({ const Details: React.FC<Props> = ({
clusterId, clusterName,
topicName, topicName,
}) => { }) => {
return ( return (
@ -21,7 +21,7 @@ const Details: React.FC<Props> = ({
<div className="level"> <div className="level">
<div className="level-item level-left"> <div className="level-item level-left">
<Breadcrumb links={[ <Breadcrumb links={[
{ href: clusterTopicsPath(clusterId), label: 'All Topics' }, { href: clusterTopicsPath(clusterName), label: 'All Topics' },
]}> ]}>
{topicName} {topicName}
</Breadcrumb> </Breadcrumb>
@ -32,7 +32,7 @@ const Details: React.FC<Props> = ({
<nav className="navbar" role="navigation"> <nav className="navbar" role="navigation">
<NavLink <NavLink
exact exact
to={clusterTopicPath(clusterId, topicName)} to={clusterTopicPath(clusterName, topicName)}
className="navbar-item is-tab" className="navbar-item is-tab"
activeClassName="is-active is-primary" activeClassName="is-active is-primary"
> >
@ -40,7 +40,7 @@ const Details: React.FC<Props> = ({
</NavLink> </NavLink>
<NavLink <NavLink
exact exact
to={clusterTopicMessagesPath(clusterId, topicName)} to={clusterTopicMessagesPath(clusterName, topicName)}
className="navbar-item is-tab" className="navbar-item is-tab"
activeClassName="is-active" activeClassName="is-active"
> >
@ -48,7 +48,7 @@ const Details: React.FC<Props> = ({
</NavLink> </NavLink>
<NavLink <NavLink
exact exact
to={clusterTopicSettingsPath(clusterId, topicName)} to={clusterTopicSettingsPath(clusterName, topicName)}
className="navbar-item is-tab" className="navbar-item is-tab"
activeClassName="is-active" activeClassName="is-active"
> >
@ -57,13 +57,13 @@ const Details: React.FC<Props> = ({
</nav> </nav>
<br /> <br />
<Switch> <Switch>
<Route exact path="/clusters/:clusterId/topics/:topicName/messages" component={MessagesContainer} /> <Route exact path="/clusters/:clusterName/topics/:topicName/messages" component={MessagesContainer} />
<Route exact path="/clusters/:clusterId/topics/:topicName/settings" component={SettingsContainer} /> <Route exact path="/clusters/:clusterName/topics/:topicName/settings" component={SettingsContainer} />
<Route exact path="/clusters/:clusterId/topics/:topicName" component={OverviewContainer} /> <Route exact path="/clusters/:clusterName/topics/:topicName" component={OverviewContainer} />
</Switch> </Switch>
</div> </div>
</div> </div>
); );
} };
export default Details; export default Details;

View file

@ -1,17 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Details from './Details'; import Details from './Details';
import { RootState } from 'redux/interfaces'; import {ClusterName, RootState} from 'redux/interfaces';
import { withRouter, RouteComponentProps } from 'react-router-dom'; import { withRouter, RouteComponentProps } from 'react-router-dom';
interface RouteProps { interface RouteProps {
clusterId: string; clusterName: ClusterName;
topicName: string; topicName: string;
} }
interface OwnProps extends RouteComponentProps<RouteProps> { } interface OwnProps extends RouteComponentProps<RouteProps> { }
const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterId } } }: OwnProps) => ({ const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterName } } }: OwnProps) => ({
clusterId, clusterName,
topicName, topicName,
}); });

View file

@ -1,20 +1,20 @@
import React from 'react'; import React from 'react';
import { ClusterId, TopicName } from 'redux/interfaces'; import { ClusterName, TopicName } from 'redux/interfaces';
interface Props { interface Props {
clusterId: ClusterId; clusterName: ClusterName;
topicName: TopicName; topicName: TopicName;
} }
const Messages: React.FC<Props> = ({ const Messages: React.FC<Props> = ({
clusterId, clusterName,
topicName, topicName,
}) => { }) => {
return ( return (
<h1> <h1>
Messages from {clusterId}{topicName} Messages from {clusterName}{topicName}
</h1> </h1>
); );
} };
export default Messages; export default Messages;

View file

@ -1,17 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Messages from './Messages'; import Messages from './Messages';
import { RootState } from 'redux/interfaces'; import {ClusterName, RootState, TopicName} from 'redux/interfaces';
import { withRouter, RouteComponentProps } from 'react-router-dom'; import { withRouter, RouteComponentProps } from 'react-router-dom';
interface RouteProps { interface RouteProps {
clusterId: string; clusterName: ClusterName;
topicName: string; topicName: TopicName;
} }
interface OwnProps extends RouteComponentProps<RouteProps> { } interface OwnProps extends RouteComponentProps<RouteProps> { }
const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterId } } }: OwnProps) => ({ const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterName } } }: OwnProps) => ({
clusterId, clusterName,
topicName, topicName,
}); });

View file

@ -1,18 +1,18 @@
import React from 'react'; import React from 'react';
import { ClusterId, Topic, TopicDetails, TopicName } from 'redux/interfaces'; import { ClusterName, Topic, TopicDetails, TopicName } from 'redux/interfaces';
import MetricsWrapper from 'components/common/Dashboard/MetricsWrapper'; import MetricsWrapper from 'components/common/Dashboard/MetricsWrapper';
import Indicator from 'components/common/Dashboard/Indicator'; import Indicator from 'components/common/Dashboard/Indicator';
interface Props extends Topic, TopicDetails { interface Props extends Topic, TopicDetails {
isFetched: boolean; isFetched: boolean;
clusterId: ClusterId; clusterName: ClusterName;
topicName: TopicName; topicName: TopicName;
fetchTopicDetails: (clusterId: ClusterId, topicName: TopicName) => void; fetchTopicDetails: (clusterName: ClusterName, topicName: TopicName) => void;
} }
const Overview: React.FC<Props> = ({ const Overview: React.FC<Props> = ({
isFetched, isFetched,
clusterId, clusterName,
topicName, topicName,
partitions, partitions,
underReplicatedPartitions, underReplicatedPartitions,
@ -24,8 +24,8 @@ const Overview: React.FC<Props> = ({
fetchTopicDetails, fetchTopicDetails,
}) => { }) => {
React.useEffect( React.useEffect(
() => { fetchTopicDetails(clusterId, topicName); }, () => { fetchTopicDetails(clusterName, topicName); },
[fetchTopicDetails, clusterId, topicName], [fetchTopicDetails, clusterName, topicName],
); );
if (!isFetched) { if (!isFetched) {
@ -74,6 +74,6 @@ const Overview: React.FC<Props> = ({
</div> </div>
</> </>
); );
} };
export default Overview; export default Overview;

View file

@ -3,27 +3,27 @@ import {
fetchTopicDetails, fetchTopicDetails,
} from 'redux/actions'; } from 'redux/actions';
import Overview from './Overview'; import Overview from './Overview';
import { RootState, TopicName, ClusterId } from 'redux/interfaces'; 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 { withRouter, RouteComponentProps } from 'react-router-dom';
interface RouteProps { interface RouteProps {
clusterId: string; clusterName: ClusterName;
topicName: string; topicName: TopicName;
} }
interface OwnProps extends RouteComponentProps<RouteProps> { } interface OwnProps extends RouteComponentProps<RouteProps> { }
const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterId } } }: OwnProps) => ({ const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterName } } }: OwnProps) => ({
clusterId, clusterName,
topicName, topicName,
isFetched: getIsTopicDetailsFetched(state), isFetched: getIsTopicDetailsFetched(state),
...getTopicByName(state, topicName), ...getTopicByName(state, topicName),
}); });
const mapDispatchToProps = { const mapDispatchToProps = {
fetchTopicDetails: (clusterId: ClusterId, topicName: TopicName) => fetchTopicDetails(clusterId, topicName), fetchTopicDetails: (clusterName: ClusterName, topicName: TopicName) => fetchTopicDetails(clusterName, topicName),
} };
export default withRouter( export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(Overview) connect(mapStateToProps, mapDispatchToProps)(Overview)

View file

@ -1,12 +1,12 @@
import React from 'react'; import React from 'react';
import { ClusterId, TopicName, TopicConfig } from 'redux/interfaces'; import { ClusterName, TopicName, TopicConfig } from 'redux/interfaces';
interface Props { interface Props {
clusterId: ClusterId; clusterName: ClusterName;
topicName: TopicName; topicName: TopicName;
config?: TopicConfig[]; config?: TopicConfig[];
isFetched: boolean; isFetched: boolean;
fetchTopicConfig: (clusterId: ClusterId, topicName: TopicName) => void; fetchTopicConfig: (clusterName: ClusterName, topicName: TopicName) => void;
} }
const ConfigListItem: React.FC<TopicConfig> = ({ const ConfigListItem: React.FC<TopicConfig> = ({
@ -32,22 +32,22 @@ const ConfigListItem: React.FC<TopicConfig> = ({
</td> </td>
</tr> </tr>
) )
} };
const Sertings: React.FC<Props> = ({ const Sertings: React.FC<Props> = ({
clusterId, clusterName,
topicName, topicName,
isFetched, isFetched,
fetchTopicConfig, fetchTopicConfig,
config, config,
}) => { }) => {
React.useEffect( React.useEffect(
() => { fetchTopicConfig(clusterId, topicName); }, () => { fetchTopicConfig(clusterName, topicName); },
[fetchTopicConfig, clusterId, topicName], [fetchTopicConfig, clusterName, topicName],
); );
if (!isFetched || !config) { if (!isFetched || !config) {
return (null); return null;
} }
return ( return (
@ -66,6 +66,6 @@ const Sertings: React.FC<Props> = ({
</table> </table>
</div> </div>
); );
} };
export default Sertings; export default Sertings;

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { RootState, ClusterId, TopicName } from 'redux/interfaces'; import { RootState, ClusterName, TopicName } from 'redux/interfaces';
import { withRouter, RouteComponentProps } from 'react-router-dom'; import { withRouter, RouteComponentProps } from 'react-router-dom';
import { import {
fetchTopicConfig, fetchTopicConfig,
@ -12,22 +12,22 @@ import {
interface RouteProps { interface RouteProps {
clusterId: string; clusterName: ClusterName;
topicName: string; topicName: TopicName;
} }
interface OwnProps extends RouteComponentProps<RouteProps> { } interface OwnProps extends RouteComponentProps<RouteProps> { }
const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterId } } }: OwnProps) => ({ const mapStateToProps = (state: RootState, { match: { params: { topicName, clusterName } } }: OwnProps) => ({
clusterId, clusterName,
topicName, topicName,
config: getTopicConfig(state, topicName), config: getTopicConfig(state, topicName),
isFetched: getTopicConfigFetched(state), isFetched: getTopicConfigFetched(state),
}); });
const mapDispatchToProps = { const mapDispatchToProps = {
fetchTopicConfig: (clusterId: ClusterId, topicName: TopicName) => fetchTopicConfig(clusterId, topicName), fetchTopicConfig: (clusterName: ClusterName, topicName: TopicName) => fetchTopicConfig(clusterName, topicName),
} };
export default withRouter( export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(Settings) connect(mapStateToProps, mapDispatchToProps)(Settings)

View file

@ -1,18 +1,18 @@
import React from 'react'; import React from 'react';
import { TopicWithDetailedInfo, ClusterId } from 'redux/interfaces'; import { TopicWithDetailedInfo, ClusterName } from 'redux/interfaces';
import ListItem from './ListItem'; import ListItem from './ListItem';
import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb'; import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { clusterTopicNewPath } from 'lib/paths'; import { clusterTopicNewPath } from 'lib/paths';
interface Props { interface Props {
clusterId: ClusterId; clusterName: ClusterName;
topics: (TopicWithDetailedInfo)[]; topics: (TopicWithDetailedInfo)[];
externalTopics: (TopicWithDetailedInfo)[]; externalTopics: (TopicWithDetailedInfo)[];
} }
const List: React.FC<Props> = ({ const List: React.FC<Props> = ({
clusterId, clusterName,
topics, topics,
externalTopics, externalTopics,
}) => { }) => {
@ -46,7 +46,7 @@ const List: React.FC<Props> = ({
<div className="level-item level-right"> <div className="level-item level-right">
<NavLink <NavLink
className="button is-primary" className="button is-primary"
to={clusterTopicNewPath(clusterId)} to={clusterTopicNewPath(clusterName)}
> >
Add a Topic Add a Topic
</NavLink> </NavLink>
@ -75,6 +75,6 @@ const List: React.FC<Props> = ({
</div> </div>
</div> </div>
); );
} };
export default List; export default List;

View file

@ -1,17 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { RootState } from 'redux/interfaces'; import {ClusterName, RootState} from 'redux/interfaces';
import { getTopicList, getExternalTopicList } from 'redux/reducers/topics/selectors'; import { getTopicList, getExternalTopicList } from 'redux/reducers/topics/selectors';
import List from './List'; import List from './List';
import { withRouter, RouteComponentProps } from 'react-router-dom'; import { withRouter, RouteComponentProps } from 'react-router-dom';
interface RouteProps { interface RouteProps {
clusterId: string; clusterName: ClusterName;
} }
interface OwnProps extends RouteComponentProps<RouteProps> { } interface OwnProps extends RouteComponentProps<RouteProps> { }
const mapStateToProps = (state: RootState, { match: { params: { clusterId } } }: OwnProps) => ({ const mapStateToProps = (state: RootState, { match: { params: { clusterName } } }: OwnProps) => ({
clusterId, clusterName,
topics: getTopicList(state), topics: getTopicList(state),
externalTopics: getExternalTopicList(state), externalTopics: getExternalTopicList(state),
}); });

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { ClusterId, CleanupPolicy, TopicFormData, TopicName } from 'redux/interfaces'; import { ClusterName, CleanupPolicy, TopicFormData, TopicName } from 'redux/interfaces';
import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb'; import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb';
import { clusterTopicsPath } from 'lib/paths'; import { clusterTopicsPath } from 'lib/paths';
import { useForm, ErrorMessage } from 'react-hook-form'; import { useForm, ErrorMessage } from 'react-hook-form';
@ -10,15 +10,15 @@ import {
} from 'lib/constants'; } from 'lib/constants';
interface Props { interface Props {
clusterId: ClusterId; clusterName: ClusterName;
isTopicCreated: boolean; isTopicCreated: boolean;
createTopic: (clusterId: ClusterId, form: TopicFormData) => void; createTopic: (clusterName: ClusterName, form: TopicFormData) => void;
redirectToTopicPath: (clusterId: ClusterId, topicName: TopicName) => void; redirectToTopicPath: (clusterName: ClusterName, topicName: TopicName) => void;
resetUploadedState: () => void; resetUploadedState: () => void;
} }
const New: React.FC<Props> = ({ const New: React.FC<Props> = ({
clusterId, clusterName,
isTopicCreated, isTopicCreated,
createTopic, createTopic,
redirectToTopicPath, redirectToTopicPath,
@ -31,10 +31,10 @@ const New: React.FC<Props> = ({
() => { () => {
if (isSubmitting && isTopicCreated) { if (isSubmitting && isTopicCreated) {
const {name} = getValues(); const {name} = getValues();
redirectToTopicPath(clusterId, name); redirectToTopicPath(clusterName, name);
} }
}, },
[isSubmitting, isTopicCreated, redirectToTopicPath, clusterId, getValues], [isSubmitting, isTopicCreated, redirectToTopicPath, clusterName, getValues],
); );
const onSubmit = async (data: TopicFormData) => { const onSubmit = async (data: TopicFormData) => {
@ -43,7 +43,7 @@ const New: React.FC<Props> = ({
//going to object page on the second creation. Resetting loaded state is workaround, need to tweak loader logic //going to object page on the second creation. Resetting loaded state is workaround, need to tweak loader logic
resetUploadedState(); resetUploadedState();
setIsSubmitting(true); setIsSubmitting(true);
createTopic(clusterId, data); createTopic(clusterName, data);
}; };
return ( return (
@ -51,7 +51,7 @@ const New: React.FC<Props> = ({
<div className="level"> <div className="level">
<div className="level-item level-left"> <div className="level-item level-left">
<Breadcrumb links={[ <Breadcrumb links={[
{href: clusterTopicsPath(clusterId), label: 'All Topics'}, {href: clusterTopicsPath(clusterName), label: 'All Topics'},
]}> ]}>
New Topic New Topic
</Breadcrumb> </Breadcrumb>

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { RootState, ClusterId, TopicFormData, TopicName, Action } from 'redux/interfaces'; import { RootState, ClusterName, TopicFormData, TopicName, Action } from 'redux/interfaces';
import New from './New'; import New from './New';
import { withRouter, RouteComponentProps } from 'react-router-dom'; import { withRouter, RouteComponentProps } from 'react-router-dom';
import { createTopic } from 'redux/actions'; import { createTopic } from 'redux/actions';
@ -9,22 +9,22 @@ import { ThunkDispatch } from 'redux-thunk';
import * as actions from "../../../redux/actions/actions"; import * as actions from "../../../redux/actions/actions";
interface RouteProps { interface RouteProps {
clusterId: string; clusterName: ClusterName;
} }
interface OwnProps extends RouteComponentProps<RouteProps> { } interface OwnProps extends RouteComponentProps<RouteProps> { }
const mapStateToProps = (state: RootState, { match: { params: { clusterId } } }: OwnProps) => ({ const mapStateToProps = (state: RootState, { match: { params: { clusterName } } }: OwnProps) => ({
clusterId, clusterName,
isTopicCreated: getTopicCreated(state), isTopicCreated: getTopicCreated(state),
}); });
const mapDispatchToProps = (dispatch: ThunkDispatch<RootState, undefined, Action>, { history }: OwnProps) => ({ const mapDispatchToProps = (dispatch: ThunkDispatch<RootState, undefined, Action>, { history }: OwnProps) => ({
createTopic: (clusterId: ClusterId, form: TopicFormData) => { createTopic: (clusterName: ClusterName, form: TopicFormData) => {
dispatch(createTopic(clusterId, form)); dispatch(createTopic(clusterName, form));
}, },
redirectToTopicPath: (clusterId: ClusterId, topicName: TopicName) => { redirectToTopicPath: (clusterName: ClusterName, topicName: TopicName) => {
history.push(clusterTopicPath(clusterId, topicName)); history.push(clusterTopicPath(clusterName, topicName));
}, },
resetUploadedState: (() => dispatch(actions.createTopicAction.failure())) resetUploadedState: (() => dispatch(actions.createTopicAction.failure()))
}); });

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { ClusterId } from 'redux/interfaces'; import { ClusterName } from 'redux/interfaces';
import { import {
Switch, Switch,
Route, Route,
@ -10,30 +10,30 @@ import PageLoader from 'components/common/PageLoader/PageLoader';
import NewContainer from './New/NewContainer'; import NewContainer from './New/NewContainer';
interface Props { interface Props {
clusterId: string; clusterName: ClusterName;
isFetched: boolean; isFetched: boolean;
fetchBrokers: (clusterId: ClusterId) => void; fetchBrokers: (clusterName: ClusterName) => void;
fetchTopicList: (clusterId: ClusterId) => void; fetchTopicList: (clusterName: ClusterName) => void;
} }
const Topics: React.FC<Props> = ({ const Topics: React.FC<Props> = ({
clusterId, clusterName,
isFetched, isFetched,
fetchTopicList, fetchTopicList,
}) => { }) => {
React.useEffect(() => { fetchTopicList(clusterId); }, [fetchTopicList, clusterId]); React.useEffect(() => { fetchTopicList(clusterName); }, [fetchTopicList, clusterName]);
if (isFetched) { if (isFetched) {
return ( return (
<Switch> <Switch>
<Route exact path="/clusters/:clusterId/topics" component={ListContainer} /> <Route exact path="/clusters/:clusterName/topics" component={ListContainer} />
<Route exact path="/clusters/:clusterId/topics/new" component={NewContainer} /> <Route exact path="/clusters/:clusterName/topics/new" component={NewContainer} />
<Route path="/clusters/:clusterId/topics/:topicName" component={DetailsContainer} /> <Route path="/clusters/:clusterName/topics/:topicName" component={DetailsContainer} />
</Switch> </Switch>
); );
} }
return (<PageLoader />); return (<PageLoader />);
} };
export default Topics; export default Topics;

View file

@ -2,22 +2,22 @@ import { connect } from 'react-redux';
import { fetchTopicList } from 'redux/actions'; import { fetchTopicList } from 'redux/actions';
import Topics from './Topics'; import Topics from './Topics';
import { getIsTopicListFetched } from 'redux/reducers/topics/selectors'; import { getIsTopicListFetched } from 'redux/reducers/topics/selectors';
import { RootState, ClusterId } from 'redux/interfaces'; import { RootState, ClusterName } from 'redux/interfaces';
import { RouteComponentProps } from 'react-router-dom'; import { RouteComponentProps } from 'react-router-dom';
interface RouteProps { interface RouteProps {
clusterId: string; clusterName: ClusterName;
} }
interface OwnProps extends RouteComponentProps<RouteProps> { } interface OwnProps extends RouteComponentProps<RouteProps> { }
const mapStateToProps = (state: RootState, { match: { params: { clusterId } }}: OwnProps) => ({ const mapStateToProps = (state: RootState, { match: { params: { clusterName } }}: OwnProps) => ({
isFetched: getIsTopicListFetched(state), isFetched: getIsTopicListFetched(state),
clusterId, clusterName,
}); });
const mapDispatchToProps = { const mapDispatchToProps = {
fetchTopicList: (clusterId: ClusterId) => fetchTopicList(clusterId), fetchTopicList: (clusterName: ClusterName) => fetchTopicList(clusterName),
} };
export default connect(mapStateToProps, mapDispatchToProps)(Topics); export default connect(mapStateToProps, mapDispatchToProps)(Topics);

View file

@ -1,15 +1,15 @@
import { import {
ClusterId, ClusterName,
TopicName, TopicName,
} from 'redux/interfaces'; } from 'redux/interfaces';
const clusterPath = (clusterId: ClusterId) => `/clusters/${clusterId}`; const clusterPath = (clusterName: ClusterName) => `/clusters/${clusterName}`;
export const clusterBrokersPath = (clusterId: ClusterId) => `${clusterPath(clusterId)}/brokers`; export const clusterBrokersPath = (clusterName: ClusterName) => `${clusterPath(clusterName)}/brokers`;
export const clusterTopicsPath = (clusterId: ClusterId) => `${clusterPath(clusterId)}/topics`; export const clusterTopicsPath = (clusterName: ClusterName) => `${clusterPath(clusterName)}/topics`;
export const clusterTopicNewPath = (clusterId: ClusterId) => `${clusterPath(clusterId)}/topics/new`; export const clusterTopicNewPath = (clusterName: ClusterName) => `${clusterPath(clusterName)}/topics/new`;
export const clusterTopicPath = (clusterId: ClusterId, topicName: TopicName) => `${clusterTopicsPath(clusterId)}/${topicName}`; export const clusterTopicPath = (clusterName: ClusterName, topicName: TopicName) => `${clusterTopicsPath(clusterName)}/${topicName}`;
export const clusterTopicSettingsPath = (clusterId: ClusterId, topicName: TopicName) => `${clusterTopicsPath(clusterId)}/${topicName}/settings`; export const clusterTopicSettingsPath = (clusterName: ClusterName, topicName: TopicName) => `${clusterTopicsPath(clusterName)}/${topicName}/settings`;
export const clusterTopicMessagesPath = (clusterId: ClusterId, topicName: TopicName) => `${clusterTopicsPath(clusterId)}/${topicName}/messages`; export const clusterTopicMessagesPath = (clusterName: ClusterName, topicName: TopicName) => `${clusterTopicsPath(clusterName)}/${topicName}/messages`;

View file

@ -3,30 +3,30 @@ import * as actions from './actions';
import { import {
PromiseThunk, PromiseThunk,
Cluster, Cluster,
ClusterId, ClusterName,
TopicFormData, TopicFormData,
TopicName, Topic, TopicName, Topic,
} from 'redux/interfaces'; } from 'redux/interfaces';
export const fetchBrokers = (clusterId: ClusterId): PromiseThunk<void> => async (dispatch) => { export const fetchBrokers = (clusterName: ClusterName): PromiseThunk<void> => async (dispatch) => {
dispatch(actions.fetchBrokersAction.request()); dispatch(actions.fetchBrokersAction.request());
try { try {
const payload = await api.getBrokers(clusterId); const payload = await api.getBrokers(clusterName);
dispatch(actions.fetchBrokersAction.success(payload)); dispatch(actions.fetchBrokersAction.success(payload));
} catch (e) { } catch (e) {
dispatch(actions.fetchBrokersAction.failure()); dispatch(actions.fetchBrokersAction.failure());
} }
} };
export const fetchBrokerMetrics = (clusterId: ClusterId): PromiseThunk<void> => async (dispatch) => { export const fetchBrokerMetrics = (clusterName: ClusterName): PromiseThunk<void> => async (dispatch) => {
dispatch(actions.fetchBrokerMetricsAction.request()); dispatch(actions.fetchBrokerMetricsAction.request());
try { try {
const payload = await api.getBrokerMetrics(clusterId); const payload = await api.getBrokerMetrics(clusterName);
dispatch(actions.fetchBrokerMetricsAction.success(payload)); dispatch(actions.fetchBrokerMetricsAction.success(payload));
} catch (e) { } catch (e) {
dispatch(actions.fetchBrokerMetricsAction.failure()); dispatch(actions.fetchBrokerMetricsAction.failure());
} }
} };
export const fetchClustersList = (): PromiseThunk<void> => async (dispatch) => { export const fetchClustersList = (): PromiseThunk<void> => async (dispatch) => {
dispatch(actions.fetchClusterListAction.request()); dispatch(actions.fetchClusterListAction.request());
@ -36,44 +36,44 @@ export const fetchClustersList = (): PromiseThunk<void> => async (dispatch) => {
} catch (e) { } catch (e) {
dispatch(actions.fetchClusterListAction.failure()); dispatch(actions.fetchClusterListAction.failure());
} }
} };
export const fetchTopicList = (clusterId: ClusterId): PromiseThunk<void> => async (dispatch) => { export const fetchTopicList = (clusterName: ClusterName): PromiseThunk<void> => async (dispatch) => {
dispatch(actions.fetchTopicListAction.request()); dispatch(actions.fetchTopicListAction.request());
try { try {
const topics = await api.getTopics(clusterId); const topics = await api.getTopics(clusterName);
dispatch(actions.fetchTopicListAction.success(topics)); dispatch(actions.fetchTopicListAction.success(topics));
} catch (e) { } catch (e) {
dispatch(actions.fetchTopicListAction.failure()); dispatch(actions.fetchTopicListAction.failure());
} }
} };
export const fetchTopicDetails = (clusterId: ClusterId, topicName: TopicName): PromiseThunk<void> => async (dispatch) => { export const fetchTopicDetails = (clusterName: ClusterName, topicName: TopicName): PromiseThunk<void> => async (dispatch) => {
dispatch(actions.fetchTopicDetailsAction.request()); dispatch(actions.fetchTopicDetailsAction.request());
try { try {
const topicDetails = await api.getTopicDetails(clusterId, topicName); const topicDetails = await api.getTopicDetails(clusterName, topicName);
dispatch(actions.fetchTopicDetailsAction.success({ topicName, details: topicDetails })); dispatch(actions.fetchTopicDetailsAction.success({ topicName, details: topicDetails }));
} catch (e) { } catch (e) {
dispatch(actions.fetchTopicDetailsAction.failure()); dispatch(actions.fetchTopicDetailsAction.failure());
} }
} };
export const fetchTopicConfig = (clusterId: ClusterId, topicName: TopicName): PromiseThunk<void> => async (dispatch) => { export const fetchTopicConfig = (clusterName: ClusterName, topicName: TopicName): PromiseThunk<void> => async (dispatch) => {
dispatch(actions.fetchTopicConfigAction.request()); dispatch(actions.fetchTopicConfigAction.request());
try { try {
const config = await api.getTopicConfig(clusterId, topicName); const config = await api.getTopicConfig(clusterName, topicName);
dispatch(actions.fetchTopicConfigAction.success({ topicName, config })); dispatch(actions.fetchTopicConfigAction.success({ topicName, config }));
} catch (e) { } catch (e) {
dispatch(actions.fetchTopicConfigAction.failure()); dispatch(actions.fetchTopicConfigAction.failure());
} }
} };
export const createTopic = (clusterId: ClusterId, form: TopicFormData): PromiseThunk<void> => async (dispatch) => { export const createTopic = (clusterName: ClusterName, form: TopicFormData): PromiseThunk<void> => async (dispatch) => {
dispatch(actions.createTopicAction.request()); dispatch(actions.createTopicAction.request());
try { try {
const topic: Topic = await api.postTopic(clusterId, form); const topic: Topic = await api.postTopic(clusterName, form);
dispatch(actions.createTopicAction.success(topic)); dispatch(actions.createTopicAction.success(topic));
} catch (e) { } catch (e) {
dispatch(actions.createTopicAction.failure()); dispatch(actions.createTopicAction.failure());
} }
} };

View file

@ -1,6 +1,6 @@
import { import {
Broker, Broker,
ClusterId, ClusterName,
BrokerMetrics, BrokerMetrics,
} from 'redux/interfaces'; } from 'redux/interfaces';
import { import {
@ -8,10 +8,10 @@ import {
BASE_PARAMS, BASE_PARAMS,
} from 'lib/constants'; } from 'lib/constants';
export const getBrokers = (clusterId: ClusterId): Promise<Broker[]> => export const getBrokers = (clusterName: ClusterName): Promise<Broker[]> =>
fetch(`${BASE_URL}/clusters/${clusterId}/brokers`, { ...BASE_PARAMS }) fetch(`${BASE_URL}/clusters/${clusterName}/brokers`, { ...BASE_PARAMS })
.then(res => res.json()); .then(res => res.json());
export const getBrokerMetrics = (clusterId: ClusterId): Promise<BrokerMetrics> => export const getBrokerMetrics = (clusterName: ClusterName): Promise<BrokerMetrics> =>
fetch(`${BASE_URL}/clusters/${clusterId}/metrics/broker`, { ...BASE_PARAMS }) fetch(`${BASE_URL}/clusters/${clusterName}/metrics/broker`, { ...BASE_PARAMS })
.then(res => res.json()); .then(res => res.json());

View file

@ -1,7 +1,7 @@
import { import {
TopicName, TopicName,
Topic, Topic,
ClusterId, ClusterName,
TopicDetails, TopicDetails,
TopicConfig, TopicConfig,
TopicFormData, TopicFormData,
@ -11,19 +11,19 @@ import {
BASE_PARAMS, BASE_PARAMS,
} from 'lib/constants'; } from 'lib/constants';
export const getTopicConfig = (clusterId: ClusterId, topicName: TopicName): Promise<TopicConfig[]> => export const getTopicConfig = (clusterName: ClusterName, topicName: TopicName): Promise<TopicConfig[]> =>
fetch(`${BASE_URL}/clusters/${clusterId}/topics/${topicName}/config`, { ...BASE_PARAMS }) fetch(`${BASE_URL}/clusters/${clusterName}/topics/${topicName}/config`, { ...BASE_PARAMS })
.then(res => res.json()); .then(res => res.json());
export const getTopicDetails = (clusterId: ClusterId, topicName: TopicName): Promise<TopicDetails> => export const getTopicDetails = (clusterName: ClusterName, topicName: TopicName): Promise<TopicDetails> =>
fetch(`${BASE_URL}/clusters/${clusterId}/topics/${topicName}`, { ...BASE_PARAMS }) fetch(`${BASE_URL}/clusters/${clusterName}/topics/${topicName}`, { ...BASE_PARAMS })
.then(res => res.json()); .then(res => res.json());
export const getTopics = (clusterId: ClusterId): Promise<Topic[]> => export const getTopics = (clusterName: ClusterName): Promise<Topic[]> =>
fetch(`${BASE_URL}/clusters/${clusterId}/topics`, { ...BASE_PARAMS }) fetch(`${BASE_URL}/clusters/${clusterName}/topics`, { ...BASE_PARAMS })
.then(res => res.json()); .then(res => res.json());
export const postTopic = (clusterId: ClusterId, form: TopicFormData): Promise<Topic> => { export const postTopic = (clusterName: ClusterName, form: TopicFormData): Promise<Topic> => {
const { const {
name, name,
partitions, partitions,
@ -46,9 +46,9 @@ export const postTopic = (clusterId: ClusterId, form: TopicFormData): Promise<To
'min.insync.replicas': minInSyncReplicas, 'min.insync.replicas': minInSyncReplicas,
} }
}); });
return fetch(`${BASE_URL}/clusters/${clusterId}/topics`, { return fetch(`${BASE_URL}/clusters/${clusterName}/topics`, {
...BASE_PARAMS, ...BASE_PARAMS,
method: 'POST', method: 'POST',
body, body,
}).then(res => res.json()); }).then(res => res.json());
} };

View file

@ -3,11 +3,11 @@ export enum ClusterStatus {
Offline = 'offline', Offline = 'offline',
} }
export type ClusterId = string; export type ClusterName = string;
export interface Cluster { export interface Cluster {
id: ClusterId; id: string;
name: string; name: ClusterName;
defaultCluster: boolean; defaultCluster: boolean;
status: ClusterStatus; status: ClusterStatus;
brokerCount: number; brokerCount: number;