Merge branch 'master' of github.com:provectus/kafka-ui into feature/schema_registry_views
This commit is contained in:
commit
a167482c74
24 changed files with 401 additions and 53 deletions
|
@ -1,4 +1,4 @@
|
|||
name: Java CI with Maven
|
||||
name: backend
|
||||
on:
|
||||
push:
|
||||
branches: [ '*' ]
|
31
.github/workflows/charts.yaml
vendored
Normal file
31
.github/workflows/charts.yaml
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
name: charts
|
||||
on:
|
||||
create:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
- uses: azure/setup-helm@v1
|
||||
- name: update appVersion
|
||||
run: |
|
||||
export version=${GITHUB_REF##*/}
|
||||
sed -i "s/appVersion:.*/appVersion: ${version}/" charts/kafka-ui/Chart.yaml
|
||||
- name:
|
||||
run: |
|
||||
export VERSION=${GITHUB_REF##*/}
|
||||
MSG=$(helm package --app-version ${VERSION} charts/kafka-ui)
|
||||
git fetch origin
|
||||
git stash
|
||||
git checkout -b gh-pages origin/gh-pages
|
||||
helm repo index .
|
||||
git add -f ${MSG##*/} index.yaml
|
||||
git commit -m "release ${VERSION}"
|
||||
git push
|
77
.github/workflows/release.yaml
vendored
Normal file
77
.github/workflows/release.yaml
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
name: release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 1.13
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.13
|
||||
- name: Update development version
|
||||
run: |
|
||||
mvn -q versions:set -DnextSnapshot
|
||||
git add pom.xml **/pom.xml
|
||||
git commit -m "Increased version in pom.xml"
|
||||
git push -f
|
||||
git reset --hard HEAD~1
|
||||
- name: Prepare release
|
||||
id: prep
|
||||
run: |
|
||||
mvn -q versions:set -DremoveSnapshot
|
||||
export VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
|
||||
git add .
|
||||
git commit -m "release ${VERSION}"
|
||||
git tag -f v${VERSION}
|
||||
git push --tags
|
||||
echo ::set-output name=version::${VERSION}
|
||||
- name: Build with Maven
|
||||
run: mvn clean package -Pprod
|
||||
#################
|
||||
# #
|
||||
# Docker images #
|
||||
# #
|
||||
#################
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
- name: Login to DockerHub
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: kafka-ui-api
|
||||
push: github.ref == 'refs/heads/master'
|
||||
tags: provectuslabs/kafka-ui:${{ steps.prep.outputs.version }}
|
||||
build-args: |
|
||||
JAR_FILE=kafka-ui-api-${{ steps.prep.outputs.version }}.jar
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
|
@ -3,4 +3,5 @@ name: kafka-ui
|
|||
description: A Helm chart for kafka-UI
|
||||
type: application
|
||||
version: 0.0.1
|
||||
appVersion: 0.0.9
|
||||
appVersion: latest
|
||||
icon: https://github.com/provectus/kafka-ui/raw/master/images/kafka-ui-logo.png
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import formatBytes from 'lib/utils/formatBytes';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { clusterBrokersPath } from 'lib/paths';
|
||||
import { clusterBrokersPath, clusterTopicsPath } from 'lib/paths';
|
||||
import { Cluster, ServerStatus } from 'generated-sources';
|
||||
import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
|
||||
|
||||
interface ClusterWidgetProps {
|
||||
cluster: Cluster;
|
||||
|
@ -19,9 +19,9 @@ const ClusterWidget: React.FC<ClusterWidgetProps> = ({
|
|||
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="column is-full-modile is-6">
|
||||
<div className="box">
|
||||
<div className="title is-6 has-text-overflow-ellipsis">
|
||||
<div
|
||||
className={`tag has-margin-right ${
|
||||
status === ServerStatus.Online ? 'is-primary' : 'is-danger'
|
||||
|
@ -36,7 +36,9 @@ const ClusterWidget: React.FC<ClusterWidgetProps> = ({
|
|||
<tbody>
|
||||
<tr>
|
||||
<th>Brokers</th>
|
||||
<td>{brokerCount}</td>
|
||||
<td>
|
||||
<NavLink to={clusterBrokersPath(name)}>{brokerCount}</NavLink>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Partitions</th>
|
||||
|
@ -44,20 +46,26 @@ const ClusterWidget: React.FC<ClusterWidgetProps> = ({
|
|||
</tr>
|
||||
<tr>
|
||||
<th>Topics</th>
|
||||
<td>{topicCount}</td>
|
||||
<td>
|
||||
<NavLink to={clusterTopicsPath(name)}>{topicCount}</NavLink>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Production</th>
|
||||
<td>{formatBytes(bytesInPerSec || 0)}</td>
|
||||
<td>
|
||||
<BytesFormatted value={bytesInPerSec} />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Consumption</th>
|
||||
<td>{formatBytes(bytesOutPerSec || 0)}</td>
|
||||
<td>
|
||||
<BytesFormatted value={bytesOutPerSec} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</NavLink>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ClusterWidget;
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { ServerStatus } from 'generated-sources';
|
||||
import { clusterBrokersPath, clusterTopicsPath } from 'lib/paths';
|
||||
import ClusterWidget from '../ClusterWidget';
|
||||
import { offlineCluster, onlineCluster } from './fixtures';
|
||||
|
||||
describe('ClusterWidget', () => {
|
||||
describe('when cluster is online', () => {
|
||||
it('renders with correct tag', () => {
|
||||
const tag = shallow(<ClusterWidget cluster={onlineCluster} />).find(
|
||||
'.tag'
|
||||
);
|
||||
expect(tag.hasClass('is-primary')).toBeTruthy();
|
||||
expect(tag.text()).toEqual(ServerStatus.Online);
|
||||
});
|
||||
|
||||
it('renders table', () => {
|
||||
const table = shallow(<ClusterWidget cluster={onlineCluster} />).find(
|
||||
'table'
|
||||
);
|
||||
expect(table.hasClass('is-fullwidth')).toBeTruthy();
|
||||
|
||||
expect(
|
||||
table.find(`NavLink[to="${clusterBrokersPath(onlineCluster.name)}"]`)
|
||||
.exists
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
table.find(`NavLink[to="${clusterTopicsPath(onlineCluster.name)}"]`)
|
||||
.exists
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('matches snapshot', () => {
|
||||
expect(
|
||||
shallow(<ClusterWidget cluster={onlineCluster} />)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when cluster is offline', () => {
|
||||
it('renders with correct tag', () => {
|
||||
const tag = shallow(<ClusterWidget cluster={offlineCluster} />).find(
|
||||
'.tag'
|
||||
);
|
||||
|
||||
expect(tag.hasClass('is-danger')).toBeTruthy();
|
||||
expect(tag.text()).toEqual(ServerStatus.Offline);
|
||||
});
|
||||
|
||||
it('renders table', () => {
|
||||
const table = shallow(<ClusterWidget cluster={offlineCluster} />).find(
|
||||
'table'
|
||||
);
|
||||
expect(table.hasClass('is-fullwidth')).toBeTruthy();
|
||||
|
||||
expect(
|
||||
table.find(`NavLink[to="${clusterBrokersPath(onlineCluster.name)}"]`)
|
||||
.exists
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
table.find(`NavLink[to="${clusterTopicsPath(onlineCluster.name)}"]`)
|
||||
.exists
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('matches snapshot', () => {
|
||||
expect(
|
||||
shallow(<ClusterWidget cluster={offlineCluster} />)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,159 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ClusterWidget when cluster is offline matches snapshot 1`] = `
|
||||
<div
|
||||
className="column is-full-modile is-6"
|
||||
>
|
||||
<div
|
||||
className="box"
|
||||
>
|
||||
<div
|
||||
className="title is-6 has-text-overflow-ellipsis"
|
||||
>
|
||||
<div
|
||||
className="tag has-margin-right is-danger"
|
||||
>
|
||||
offline
|
||||
</div>
|
||||
local
|
||||
</div>
|
||||
<table
|
||||
className="table is-fullwidth"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
Brokers
|
||||
</th>
|
||||
<td>
|
||||
<NavLink
|
||||
to="/ui/clusters/local/brokers"
|
||||
>
|
||||
1
|
||||
</NavLink>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Partitions
|
||||
</th>
|
||||
<td>
|
||||
2
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Topics
|
||||
</th>
|
||||
<td>
|
||||
<NavLink
|
||||
to="/ui/clusters/local/topics"
|
||||
>
|
||||
2
|
||||
</NavLink>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Production
|
||||
</th>
|
||||
<td>
|
||||
<BytesFormatted
|
||||
value={8000.00000673768}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Consumption
|
||||
</th>
|
||||
<td>
|
||||
<BytesFormatted
|
||||
value={0.815306356729712}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ClusterWidget when cluster is online matches snapshot 1`] = `
|
||||
<div
|
||||
className="column is-full-modile is-6"
|
||||
>
|
||||
<div
|
||||
className="box"
|
||||
>
|
||||
<div
|
||||
className="title is-6 has-text-overflow-ellipsis"
|
||||
>
|
||||
<div
|
||||
className="tag has-margin-right is-primary"
|
||||
>
|
||||
online
|
||||
</div>
|
||||
secondLocal
|
||||
</div>
|
||||
<table
|
||||
className="table is-fullwidth"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
Brokers
|
||||
</th>
|
||||
<td>
|
||||
<NavLink
|
||||
to="/ui/clusters/secondLocal/brokers"
|
||||
>
|
||||
1
|
||||
</NavLink>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Partitions
|
||||
</th>
|
||||
<td>
|
||||
6
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Topics
|
||||
</th>
|
||||
<td>
|
||||
<NavLink
|
||||
to="/ui/clusters/secondLocal/topics"
|
||||
>
|
||||
3
|
||||
</NavLink>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Production
|
||||
</th>
|
||||
<td>
|
||||
<BytesFormatted
|
||||
value={0.00003061819685376472}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Consumption
|
||||
</th>
|
||||
<td>
|
||||
<BytesFormatted
|
||||
value={5.737800890036267}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,25 @@
|
|||
import { Cluster, ServerStatus } from 'generated-sources';
|
||||
|
||||
export const onlineCluster: Cluster = {
|
||||
name: 'secondLocal',
|
||||
defaultCluster: false,
|
||||
status: ServerStatus.Online,
|
||||
brokerCount: 1,
|
||||
onlinePartitionCount: 6,
|
||||
topicCount: 3,
|
||||
bytesInPerSec: 0.000030618196853764715,
|
||||
bytesOutPerSec: 5.737800890036267075817,
|
||||
};
|
||||
|
||||
export const offlineCluster: Cluster = {
|
||||
name: 'local',
|
||||
defaultCluster: true,
|
||||
status: ServerStatus.Offline,
|
||||
brokerCount: 1,
|
||||
onlinePartitionCount: 2,
|
||||
topicCount: 2,
|
||||
bytesInPerSec: 8000.0000067376808542600021,
|
||||
bytesOutPerSec: 0.8153063567297119490871,
|
||||
};
|
||||
|
||||
export const clusters: Cluster[] = [onlineCluster, offlineCluster];
|
|
@ -5,18 +5,23 @@ interface Props {
|
|||
precision?: number;
|
||||
}
|
||||
|
||||
const BytesFormatted: React.FC<Props> = ({ value, precision }) => {
|
||||
const formatBytes = React.useCallback(() => {
|
||||
const numVal = typeof value === 'string' ? parseInt(value, 10) : value;
|
||||
if (!numVal) return 0;
|
||||
const pow = Math.floor(Math.log2(numVal) / 10);
|
||||
const BytesFormatted: React.FC<Props> = ({ value, precision = 0 }) => {
|
||||
const formatedValue = React.useMemo(() => {
|
||||
const bytes = typeof value === 'string' ? parseInt(value, 10) : value;
|
||||
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
if (!bytes || bytes === 0) return [0, sizes[0]];
|
||||
|
||||
if (bytes < 1024) return [Math.ceil(bytes), sizes[0]];
|
||||
|
||||
const pow = Math.floor(Math.log2(bytes) / 10);
|
||||
const multiplier = 10 ** (precision || 2);
|
||||
return (
|
||||
Math.round((numVal * multiplier) / 1024 ** pow) / multiplier +
|
||||
['Bytes', 'KB', 'MB', 'GB', 'TB'][pow]
|
||||
Math.round((bytes * multiplier) / 1024 ** pow) / multiplier + sizes[pow]
|
||||
);
|
||||
}, [value]);
|
||||
return <span>{formatBytes()}</span>;
|
||||
|
||||
return <span>{formatedValue}</span>;
|
||||
};
|
||||
|
||||
export default BytesFormatted;
|
||||
|
|
|
@ -1,13 +0,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]];
|
||||
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return [parseFloat((bytes / k ** i).toFixed(dm)), sizes[i]];
|
||||
}
|
||||
|
||||
export default formatBytes;
|
|
@ -1,13 +1,3 @@
|
|||
@import "../../node_modules/bulma/sass/utilities/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/base/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/elements/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/form/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/helpers/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/components/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/grid/_all.sass";
|
||||
@import "../../node_modules/bulma/sass/layout/_all.sass";
|
||||
@import "../../node_modules/bulma-switch/src/sass/index.sass";
|
||||
|
||||
.has {
|
||||
&-text-overflow-ellipsis {
|
||||
flex: 1;
|
||||
|
@ -55,16 +45,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
&.is-hoverable {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.2), 0 0px 0 1px rgba(10, 10, 10, 0.02);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@import 'bulma';
|
||||
@import '~bulma-switch';
|
||||
@import 'src/theme/bulma_overrides';
|
||||
|
||||
#root, body, html {
|
||||
|
|
Loading…
Add table
Reference in a new issue