diff --git a/.github/workflows/aws_publisher.yml b/.github/workflows/aws_publisher.yml
index 9d74a2804..6aa70fa91 100644
--- a/.github/workflows/aws_publisher.yml
+++ b/.github/workflows/aws_publisher.yml
@@ -19,7 +19,7 @@ on:
jobs:
build-ami:
name: Build AMI
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- name: Clone infra repo
run: |
diff --git a/.github/workflows/backend_tests.yml b/.github/workflows/backend_tests.yml
index 06b9a6d1c..8a3ffe2d3 100644
--- a/.github/workflows/backend_tests.yml
+++ b/.github/workflows/backend_tests.yml
@@ -15,7 +15,7 @@ permissions:
jobs:
build-and-test:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- name: Checkout
diff --git a/.github/workflows/block_merge.yml b/.github/workflows/block_merge.yml
index db26a946d..c689d45b0 100644
--- a/.github/workflows/block_merge.yml
+++ b/.github/workflows/block_merge.yml
@@ -4,7 +4,7 @@ on:
types: [opened, labeled, unlabeled, synchronize]
jobs:
block_merge:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: mheap/github-action-required-labels@v5
with:
diff --git a/.github/workflows/branch-deploy.yml b/.github/workflows/branch-deploy.yml
index f073dff71..107a93116 100644
--- a/.github/workflows/branch-deploy.yml
+++ b/.github/workflows/branch-deploy.yml
@@ -12,7 +12,7 @@ permissions:
jobs:
build:
if: ${{ github.event.label.name == 'status/feature_testing' || github.event.label.name == 'status/feature_testing_public' }}
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
@@ -75,7 +75,7 @@ jobs:
tag: ${{ steps.extract_branch.outputs.tag }}
make-branch-env:
needs: build
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- name: clone
run: |
diff --git a/.github/workflows/branch-remove.yml b/.github/workflows/branch-remove.yml
index a3177011b..d700ea976 100644
--- a/.github/workflows/branch-remove.yml
+++ b/.github/workflows/branch-remove.yml
@@ -10,7 +10,7 @@ permissions:
jobs:
remove:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
if: ${{ (github.event.label.name == 'status/feature_testing' || github.event.label.name == 'status/feature_testing_public') || (github.event.action == 'closed' && (contains(github.event.pull_request.labels.*.name, 'status/feature_testing') || contains(github.event.pull_request.labels.*.name, 'status/feature_testing_public'))) }}
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/build-public-image.yml b/.github/workflows/build-public-image.yml
index de5e33b51..86f90ad9c 100644
--- a/.github/workflows/build-public-image.yml
+++ b/.github/workflows/build-public-image.yml
@@ -11,7 +11,7 @@ permissions:
jobs:
build:
if: ${{ github.event.label.name == 'status/image_testing' }}
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index a29477928..57f5a0251 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -23,7 +23,7 @@ permissions:
jobs:
analyze:
name: Analyze
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
diff --git a/.github/workflows/cve.yml b/.github/workflows/cve.yml
index 13535c65c..d53913521 100644
--- a/.github/workflows/cve.yml
+++ b/.github/workflows/cve.yml
@@ -10,7 +10,7 @@ permissions:
jobs:
build-and-test:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/delete-public-image.yml b/.github/workflows/delete-public-image.yml
index 5294307d8..8e3f2dd7c 100644
--- a/.github/workflows/delete-public-image.yml
+++ b/.github/workflows/delete-public-image.yml
@@ -6,7 +6,7 @@ on:
jobs:
remove:
if: ${{ github.event.label.name == 'status/image_testing' || ( github.event.action == 'closed' && (contains(github.event.pull_request.labels, 'status/image_testing'))) }}
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- name: get branch name
id: extract_branch
diff --git a/.github/workflows/e2e-automation.yml b/.github/workflows/e2e-automation.yml
index 0313784b7..6303001a3 100644
--- a/.github/workflows/e2e-automation.yml
+++ b/.github/workflows/e2e-automation.yml
@@ -21,7 +21,7 @@ permissions:
jobs:
build-and-test:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/e2e-manual.yml b/.github/workflows/e2e-manual.yml
index 2668897ae..d554bdaa2 100644
--- a/.github/workflows/e2e-manual.yml
+++ b/.github/workflows/e2e-manual.yml
@@ -20,7 +20,7 @@ permissions:
jobs:
build-and-test:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
index f7509c1df..72e7c92e1 100644
--- a/.github/workflows/e2e-tests.yml
+++ b/.github/workflows/e2e-tests.yml
@@ -16,7 +16,7 @@ permissions:
jobs:
build-and-test:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/e2e-weekly.yml b/.github/workflows/e2e-weekly.yml
index 4e238ead9..d8275e473 100644
--- a/.github/workflows/e2e-weekly.yml
+++ b/.github/workflows/e2e-weekly.yml
@@ -8,7 +8,7 @@ permissions:
jobs:
build-and-test:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/frontend_tests.yml b/.github/workflows/frontend_tests.yml
index 9aa4a6110..4be3239d4 100644
--- a/.github/workflows/frontend_tests.yml
+++ b/.github/workflows/frontend_tests.yml
@@ -11,7 +11,7 @@ jobs:
env:
CI: true
NODE_ENV: dev
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 472dadbca..503656b2d 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -10,7 +10,7 @@ permissions:
jobs:
build:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
permissions:
contents: read
packages: write
diff --git a/.github/workflows/md-links.yml b/.github/workflows/md-links.yml
index ee3379558..b885e014d 100644
--- a/.github/workflows/md-links.yml
+++ b/.github/workflows/md-links.yml
@@ -14,7 +14,7 @@ permissions:
jobs:
build-and-test:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/pr_linter.yml b/.github/workflows/pr_linter.yml
index ef5bd8b25..f4562345f 100644
--- a/.github/workflows/pr_linter.yml
+++ b/.github/workflows/pr_linter.yml
@@ -6,7 +6,7 @@ permissions:
checks: write
jobs:
task-check:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: kentaro-m/task-completed-checker-action@v0.1.2
with:
diff --git a/.github/workflows/release-serde-api.yml b/.github/workflows/release-serde-api.yml
index 86aa61a75..af5b1db0d 100644
--- a/.github/workflows/release-serde-api.yml
+++ b/.github/workflows/release-serde-api.yml
@@ -7,7 +7,7 @@ permissions:
jobs:
release-serde-api:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index efa859a79..2ae221180 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -8,7 +8,7 @@ permissions:
jobs:
release:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
permissions:
contents: write
packages: write
@@ -95,7 +95,7 @@ jobs:
cache-to: type=local,dest=/tmp/.buildx-cache
charts:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
needs: release
steps:
- name: Repository Dispatch
diff --git a/.github/workflows/release_drafter.yml b/.github/workflows/release_drafter.yml
index dc8f689ea..6614c88aa 100644
--- a/.github/workflows/release_drafter.yml
+++ b/.github/workflows/release_drafter.yml
@@ -18,7 +18,7 @@ permissions:
jobs:
update_release_draft:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
diff --git a/.github/workflows/separate_env_public_create.yml b/.github/workflows/separate_env_public_create.yml
index 5449482db..b7bb630e1 100644
--- a/.github/workflows/separate_env_public_create.yml
+++ b/.github/workflows/separate_env_public_create.yml
@@ -12,7 +12,7 @@ permissions:
jobs:
build:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -76,7 +76,7 @@ jobs:
tag: ${{ steps.extract_branch.outputs.tag }}
separate-env-create:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
needs: build
steps:
- name: clone
diff --git a/.github/workflows/separate_env_public_remove.yml b/.github/workflows/separate_env_public_remove.yml
index 2ada624e2..0eb48cd4a 100644
--- a/.github/workflows/separate_env_public_remove.yml
+++ b/.github/workflows/separate_env_public_remove.yml
@@ -9,7 +9,7 @@ on:
jobs:
separate-env-remove:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- name: clone
run: |
diff --git a/.github/workflows/welcome-first-time-contributors.yml b/.github/workflows/welcome-first-time-contributors.yml
index 3ec8e8a34..1ac861055 100644
--- a/.github/workflows/welcome-first-time-contributors.yml
+++ b/.github/workflows/welcome-first-time-contributors.yml
@@ -12,7 +12,7 @@ permissions:
pull-requests: write
jobs:
welcome:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
diff --git a/.github/workflows/workflow_linter.yml b/.github/workflows/workflow_linter.yml
index 47925a9cf..728aaa251 100644
--- a/.github/workflows/workflow_linter.yml
+++ b/.github/workflows/workflow_linter.yml
@@ -10,7 +10,7 @@ permissions:
jobs:
build-and-test:
- runs-on: gha-private-runner
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
diff --git a/frontend/index.html b/frontend/index.html
index 693664306..0041f6efa 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -5,8 +5,7 @@
-
-
+
diff --git a/frontend/public/favicon/favicon.ico b/frontend/public/favicon/favicon.ico
deleted file mode 100644
index 2774ebccf..000000000
Binary files a/frontend/public/favicon/favicon.ico and /dev/null differ
diff --git a/frontend/public/favicon/icon.svg b/frontend/public/favicon/favicon.svg
similarity index 77%
rename from frontend/public/favicon/icon.svg
rename to frontend/public/favicon/favicon.svg
index d31960515..fc31bcf4a 100644
--- a/frontend/public/favicon/icon.svg
+++ b/frontend/public/favicon/favicon.svg
@@ -2,14 +2,16 @@
-
-
+
+
diff --git a/frontend/src/components/App.tsx b/frontend/src/components/App.tsx
index 43abc60bd..f3d6d88cd 100644
--- a/frontend/src/components/App.tsx
+++ b/frontend/src/components/App.tsx
@@ -50,7 +50,7 @@ const App: React.FC = () => {
- }>
+ }>
diff --git a/frontend/src/components/Brokers/BrokersList/BrokersList.tsx b/frontend/src/components/Brokers/BrokersList/BrokersList.tsx
index f869269fa..bdc1f9c00 100644
--- a/frontend/src/components/Brokers/BrokersList/BrokersList.tsx
+++ b/frontend/src/components/Brokers/BrokersList/BrokersList.tsx
@@ -1,27 +1,15 @@
-import React from 'react';
+import React, { useMemo } from 'react';
import { ClusterName } from 'redux/interfaces';
import { useNavigate } from 'react-router-dom';
import PageHeading from 'components/common/PageHeading/PageHeading';
-import * as Metrics from 'components/common/Metrics';
import useAppParams from 'lib/hooks/useAppParams';
+import Table from 'components/common/NewTable';
+import { clusterBrokerPath } from 'lib/paths';
import { useBrokers } from 'lib/hooks/api/brokers';
import { useClusterStats } from 'lib/hooks/api/clusters';
-import Table, { LinkCell, SizeCell } from 'components/common/NewTable';
-import CheckMarkRoundIcon from 'components/common/Icons/CheckMarkRoundIcon';
-import { ColumnDef } from '@tanstack/react-table';
-import { clusterBrokerPath } from 'lib/paths';
-import { keyBy } from 'lib/functions/keyBy';
-import Tooltip from 'components/common/Tooltip/Tooltip';
-import ColoredCell from 'components/common/NewTable/ColoredCell';
-
-import SkewHeader from './SkewHeader/SkewHeader';
-import * as S from './BrokersList.styled';
-const NA = 'N/A';
-const NA_DISK_USAGE = {
- segmentCount: NA,
- segmentSize: NA,
-};
+import { BrokersMetrics } from './BrokersMetrics/BrokersMetrics';
+import { getBrokersTableColumns, getBrokersTableRows } from './lib';
const BrokersList: React.FC = () => {
const navigate = useNavigate();
@@ -41,202 +29,35 @@ const BrokersList: React.FC = () => {
version,
} = clusterStats;
- const rows = React.useMemo(() => {
- if (!brokers || brokers.length === 0) {
- return [];
- }
-
- const diskUsageByBroker = keyBy(diskUsage, 'brokerId');
-
- return brokers.map((broker) => {
- const diskUse = diskUsageByBroker[broker.id] || NA_DISK_USAGE;
-
- return {
- brokerId: broker.id,
- size: diskUse.segmentSize,
- count: diskUse.segmentCount,
- port: broker.port,
- host: broker.host,
- partitionsLeader: broker.partitionsLeader,
- partitionsSkew: broker.partitionsSkew,
- leadersSkew: broker.leadersSkew,
- inSyncPartitions: broker.inSyncPartitions,
- };
- });
- }, [diskUsage, brokers]);
-
- const columns = React.useMemo[]>(
- () => [
- {
- header: 'Broker ID',
- accessorKey: 'brokerId',
- // eslint-disable-next-line react/no-unstable-nested-components
- cell: ({ getValue }) => (
-
- ()}`}
- to={encodeURIComponent(`${getValue()}`)}
- />
- {getValue() === activeControllers && (
- }
- content="Active Controller"
- placement="right"
- />
- )}
-
- ),
- },
- {
- header: 'Disk usage',
- accessorKey: 'size',
- // eslint-disable-next-line react/no-unstable-nested-components
- cell: ({ getValue, table, cell, column, renderValue, row }) =>
- getValue() === NA ? (
- NA
- ) : (
-
- ),
- },
- {
- // eslint-disable-next-line react/no-unstable-nested-components
- header: () => ,
- accessorKey: 'partitionsSkew',
- // eslint-disable-next-line react/no-unstable-nested-components
- cell: ({ getValue }) => {
- const value = getValue();
- return (
- = 10 && value < 20}
- attention={value >= 20}
- />
- );
- },
- },
- { header: 'Leaders', accessorKey: 'partitionsLeader' },
- {
- header: 'Leader skew',
- accessorKey: 'leadersSkew',
- // eslint-disable-next-line react/no-unstable-nested-components
- cell: ({ getValue }) => {
- const value = getValue();
- return (
- = 10 && value < 20}
- attention={value >= 20}
- />
- );
- },
- },
- {
- header: 'Online partitions',
- accessorKey: 'inSyncPartitions',
- // eslint-disable-next-line react/no-unstable-nested-components
- cell: ({ getValue, row }) => {
- const value = getValue();
- return (
-
- );
- },
- },
- { header: 'Port', accessorKey: 'port' },
- {
- header: 'Host',
- accessorKey: 'host',
- },
- ],
- []
+ const rows = useMemo(
+ () =>
+ getBrokersTableRows({
+ brokers,
+ diskUsage,
+ activeControllers,
+ onlinePartitionCount,
+ offlinePartitionCount,
+ }),
+ [diskUsage, activeControllers, brokers]
);
- const replicas = (inSyncReplicasCount ?? 0) + (outOfSyncReplicasCount ?? 0);
- const areAllInSync = inSyncReplicasCount && replicas === inSyncReplicasCount;
- const partitionIsOffline = offlinePartitionCount && offlinePartitionCount > 0;
-
- const isActiveControllerUnKnown = typeof activeControllers === 'undefined';
+ const columns = useMemo(() => getBrokersTableColumns(), []);
return (
<>
-
-
-
- {brokerCount}
-
-
- {isActiveControllerUnKnown ? (
- No Active Controller
- ) : (
- activeControllers
- )}
-
- {version}
-
-
-
- {partitionIsOffline ? (
- {onlinePartitionCount}
- ) : (
- onlinePartitionCount
- )}
-
- {` of ${
- (onlinePartitionCount || 0) + (offlinePartitionCount || 0)
- }
- `}
-
-
-
- {!underReplicatedPartitionCount ? (
-
- {underReplicatedPartitionCount}
-
- ) : (
- {underReplicatedPartitionCount}
- )}
-
-
- {areAllInSync ? (
- replicas
- ) : (
- {inSyncReplicasCount}
- )}
- of {replicas}
-
-
- {outOfSyncReplicasCount}
-
-
-
+
+
+
theme.circularAlert.color.error};
+`;
diff --git a/frontend/src/components/Brokers/BrokersList/BrokersMetrics/BrokersMetrics.tsx b/frontend/src/components/Brokers/BrokersList/BrokersMetrics/BrokersMetrics.tsx
new file mode 100644
index 000000000..5c1600806
--- /dev/null
+++ b/frontend/src/components/Brokers/BrokersList/BrokersMetrics/BrokersMetrics.tsx
@@ -0,0 +1,105 @@
+import React from 'react';
+import * as Metrics from 'components/common/Metrics';
+
+import * as S from './BrokersMetrics.styled';
+
+type BrokersMetricsProps = {
+ brokerCount: number | undefined;
+ inSyncReplicasCount: number | undefined;
+ outOfSyncReplicasCount: number | undefined;
+ offlinePartitionCount: number | undefined;
+ activeControllers: number | undefined;
+ onlinePartitionCount: number | undefined;
+ underReplicatedPartitionCount: number | undefined;
+ version: string | undefined;
+};
+
+export const BrokersMetrics = ({
+ brokerCount,
+ version,
+ activeControllers,
+ outOfSyncReplicasCount,
+ inSyncReplicasCount,
+ offlinePartitionCount,
+ underReplicatedPartitionCount,
+ onlinePartitionCount,
+}: BrokersMetricsProps) => {
+ const replicas = (inSyncReplicasCount ?? 0) + (outOfSyncReplicasCount ?? 0);
+ const areAllInSync = inSyncReplicasCount && replicas === inSyncReplicasCount;
+ const partitionIsOffline = offlinePartitionCount && offlinePartitionCount > 0;
+
+ const isActiveControllerUnKnown = typeof activeControllers === 'undefined';
+
+ return (
+
+
+
+ {brokerCount}
+
+
+
+ {isActiveControllerUnKnown ? (
+ No Active Controller
+ ) : (
+ activeControllers
+ )}
+
+
+ {version}
+
+
+
+
+ {partitionIsOffline ? (
+ {onlinePartitionCount}
+ ) : (
+ onlinePartitionCount
+ )}
+
+ {` of ${(onlinePartitionCount || 0) + (offlinePartitionCount || 0)}
+ `}
+
+
+
+
+ {!underReplicatedPartitionCount ? (
+
+ {underReplicatedPartitionCount}
+
+ ) : (
+ {underReplicatedPartitionCount}
+ )}
+
+
+
+ {areAllInSync ? (
+ replicas
+ ) : (
+ {inSyncReplicasCount}
+ )}
+ of {replicas}
+
+
+
+ {outOfSyncReplicasCount}
+
+
+
+ );
+};
diff --git a/frontend/src/components/Brokers/BrokersList/BrokersList.styled.ts b/frontend/src/components/Brokers/BrokersList/TableCells/TableCells.styled.ts
similarity index 64%
rename from frontend/src/components/Brokers/BrokersList/BrokersList.styled.ts
rename to frontend/src/components/Brokers/BrokersList/TableCells/TableCells.styled.ts
index 964e64368..718f952eb 100644
--- a/frontend/src/components/Brokers/BrokersList/BrokersList.styled.ts
+++ b/frontend/src/components/Brokers/BrokersList/TableCells/TableCells.styled.ts
@@ -10,7 +10,3 @@ export const RowCell = styled.div`
padding-left: 6px;
}
`;
-
-export const DangerText = styled.span`
- color: ${({ theme }) => theme.circularAlert.color.error};
-`;
diff --git a/frontend/src/components/Brokers/BrokersList/TableCells/TableCells.tsx b/frontend/src/components/Brokers/BrokersList/TableCells/TableCells.tsx
new file mode 100644
index 000000000..5d6039fbf
--- /dev/null
+++ b/frontend/src/components/Brokers/BrokersList/TableCells/TableCells.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import { BrokersTableRow } from 'components/Brokers/BrokersList/lib/types';
+import { CellContext } from '@tanstack/react-table';
+import { LinkCell } from 'components/common/NewTable';
+import Tooltip from 'components/common/Tooltip/Tooltip';
+import CheckMarkRoundIcon from 'components/common/Icons/CheckMarkRoundIcon';
+import { NA } from 'components/Brokers/BrokersList/lib';
+import ColoredCell from 'components/common/NewTable/ColoredCell';
+import SizeCellCount from 'components/common/NewTable/SizeCellCount';
+
+import * as S from './TableCells.styled';
+
+type BrokerIdProps = CellContext;
+
+export const BrokerId = ({ getValue, row }: BrokerIdProps) => {
+ const { activeControllers } = row.original;
+ const brokerId = getValue();
+
+ return (
+
+
+ {brokerId === activeControllers && (
+ }
+ content="Active Controller"
+ placement="right"
+ />
+ )}
+
+ );
+};
+
+type DiscUsageProps = CellContext;
+
+export const DiscUsage = ({
+ getValue,
+ table,
+ cell,
+ column,
+ renderValue,
+ row,
+}: DiscUsageProps) => {
+ if (getValue() === undefined) return NA;
+
+ return (
+
+ );
+};
+
+type ScewProps = CellContext<
+ BrokersTableRow,
+ BrokersTableRow['partitionsSkew'] | BrokersTableRow['leadersSkew']
+>;
+
+export const Skew = ({ getValue }: ScewProps) => {
+ const skew = getValue();
+ const value = skew ? `${skew.toFixed(2)}%` : '-';
+
+ return (
+ = 10 && skew < 20}
+ attention={skew !== undefined && skew >= 20}
+ />
+ );
+};
+
+type OnlinePartitionsProps = CellContext<
+ BrokersTableRow,
+ BrokersTableRow['onlinePartitionCount']
+>;
+
+export const OnlinePartitions = ({ row }: OnlinePartitionsProps) => {
+ const { onlinePartitionCount, offlinePartitionCount } = row.original;
+
+ if (
+ onlinePartitionCount === undefined ||
+ offlinePartitionCount === undefined
+ ) {
+ return null;
+ }
+
+ return (
+ 0}
+ />
+ );
+};
diff --git a/frontend/src/components/Brokers/BrokersList/__test__/BrokersList.spec.tsx b/frontend/src/components/Brokers/BrokersList/__test__/BrokersList.spec.tsx
index e98f28e52..9dc40591e 100644
--- a/frontend/src/components/Brokers/BrokersList/__test__/BrokersList.spec.tsx
+++ b/frontend/src/components/Brokers/BrokersList/__test__/BrokersList.spec.tsx
@@ -72,11 +72,13 @@ describe('BrokersList Component', () => {
},
}));
renderComponent();
- const onlineWidget = screen.getByText(
+ const onlineWidgets = screen.getAllByText(
clusterStatsPayload.onlinePartitionCount
);
- expect(onlineWidget).toBeInTheDocument();
- expect(onlineWidget).toHaveStyle({ color: '#E51A1A' });
+ onlineWidgets.forEach((widget) => {
+ expect(widget).toBeInTheDocument();
+ expect(widget).toHaveStyle({ color: '#E51A1A' });
+ });
});
it('shows right count when offlinePartitionCount > 0', async () => {
(useClusterStats as jest.Mock).mockImplementation(() => ({
@@ -154,49 +156,24 @@ describe('BrokersList Component', () => {
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()
);
});
+ });
+ });
- describe('when diskUsage', () => {
- describe('is empty', () => {
- beforeEach(() => {
- (useClusterStats as jest.Mock).mockImplementation(() => ({
- data: { ...clusterStatsPayload, diskUsage: undefined },
- }));
- });
-
- it('renders list of all brokers', async () => {
- renderComponent();
- expect(screen.getByRole('table')).toBeInTheDocument();
- expect(screen.getAllByRole('row').length).toEqual(3);
- });
- });
-
- describe('was NOT set for second broker', () => {
- beforeEach(() => {
- (useClusterStats as jest.Mock).mockImplementation(() => ({
- data: {
- ...clusterStatsPayload,
- diskUsage: [clusterStatsPayload.diskUsage[0]],
- },
- }));
- });
-
- it('renders list of all brokers', async () => {
- renderComponent();
- expect(screen.getByRole('table')).toBeInTheDocument();
- expect(screen.getAllByRole('row').length).toEqual(3);
- });
- });
- });
+ describe('when diskUsage is empty', () => {
+ beforeEach(() => {
+ (useBrokers as jest.Mock).mockImplementation(() => ({
+ data: brokersPayload,
+ }));
+ (useClusterStats as jest.Mock).mockImplementation(() => ({
+ data: { ...clusterStatsPayload, diskUsage: undefined },
+ }));
});
- describe('when the brokers list is empty', () => {
+ describe('when it has no brokers', () => {
beforeEach(() => {
(useBrokers as jest.Mock).mockImplementation(() => ({
data: [],
}));
- (useClusterStats as jest.Mock).mockImplementation(() => ({
- data: clusterStatsPayload,
- }));
});
it('renders empty table', async () => {
@@ -207,6 +184,22 @@ describe('BrokersList Component', () => {
).toBeInTheDocument();
});
});
+
+ it('renders list of all brokers', async () => {
+ renderComponent();
+ expect(screen.getByRole('table')).toBeInTheDocument();
+ expect(screen.getAllByRole('row').length).toEqual(3);
+ });
+ it('opens broker when row clicked', async () => {
+ renderComponent();
+ await userEvent.click(screen.getByRole('cell', { name: '100' }));
+
+ await waitFor(() =>
+ expect(mockedUsedNavigate).toBeCalledWith(
+ clusterBrokerPath(clusterName, '100')
+ )
+ );
+ });
});
});
});
diff --git a/frontend/src/components/Brokers/BrokersList/lib/constants.ts b/frontend/src/components/Brokers/BrokersList/lib/constants.ts
new file mode 100644
index 000000000..48e4e0cb4
--- /dev/null
+++ b/frontend/src/components/Brokers/BrokersList/lib/constants.ts
@@ -0,0 +1,5 @@
+export const NA = 'N/A';
+export const NA_DISK_USAGE = {
+ segmentCount: NA,
+ segmentSize: NA,
+};
diff --git a/frontend/src/components/Brokers/BrokersList/lib/index.ts b/frontend/src/components/Brokers/BrokersList/lib/index.ts
new file mode 100644
index 000000000..7a616f8d2
--- /dev/null
+++ b/frontend/src/components/Brokers/BrokersList/lib/index.ts
@@ -0,0 +1,3 @@
+export * from './utils';
+export * from './constants';
+export * from './types';
diff --git a/frontend/src/components/Brokers/BrokersList/lib/types.ts b/frontend/src/components/Brokers/BrokersList/lib/types.ts
new file mode 100644
index 000000000..7928862a1
--- /dev/null
+++ b/frontend/src/components/Brokers/BrokersList/lib/types.ts
@@ -0,0 +1,13 @@
+export type BrokersTableRow = {
+ brokerId: number;
+ size: number | undefined;
+ count: number | undefined;
+ port: number | undefined;
+ host: string | undefined;
+ partitionsLeader: number | undefined;
+ partitionsSkew: number | undefined;
+ leadersSkew: number | undefined;
+ onlinePartitionCount: number | undefined;
+ offlinePartitionCount: number | undefined;
+ activeControllers: number | undefined;
+};
diff --git a/frontend/src/components/Brokers/BrokersList/lib/utils.ts b/frontend/src/components/Brokers/BrokersList/lib/utils.ts
new file mode 100644
index 000000000..1eb6b2886
--- /dev/null
+++ b/frontend/src/components/Brokers/BrokersList/lib/utils.ts
@@ -0,0 +1,78 @@
+import { Broker, BrokerDiskUsage } from 'generated-sources';
+import * as Cell from 'components/Brokers/BrokersList/TableCells/TableCells';
+import { createColumnHelper } from '@tanstack/react-table';
+import { keyBy } from 'lib/functions/keyBy';
+import SkewHeader from 'components/Brokers/BrokersList/SkewHeader/SkewHeader';
+
+import { BrokersTableRow } from './types';
+import { NA_DISK_USAGE } from './constants';
+
+type GetBrokersTableRowsParams = {
+ brokers: Broker[] | undefined;
+ diskUsage: BrokerDiskUsage[] | undefined;
+ activeControllers: number | undefined;
+ onlinePartitionCount: number | undefined;
+ offlinePartitionCount: number | undefined;
+};
+
+export const getBrokersTableRows = ({
+ brokers = [],
+ diskUsage = [],
+ activeControllers,
+ onlinePartitionCount,
+ offlinePartitionCount,
+}: GetBrokersTableRowsParams): BrokersTableRow[] => {
+ if (!brokers || brokers.length === 0) {
+ return [];
+ }
+
+ const diskUsageByBroker = keyBy(diskUsage, 'brokerId');
+
+ return brokers.map((broker) => {
+ const diskUse = diskUsageByBroker[broker.id] || NA_DISK_USAGE;
+
+ return {
+ brokerId: broker.id,
+ size: diskUse.segmentSize,
+ count: diskUse.segmentCount,
+ port: broker.port,
+ host: broker.host,
+ partitionsLeader: broker.partitionsLeader,
+ partitionsSkew: broker.partitionsSkew,
+ leadersSkew: broker.leadersSkew,
+ onlinePartitionCount,
+ offlinePartitionCount,
+ activeControllers,
+ };
+ });
+};
+
+export const getBrokersTableColumns = () => {
+ const columnHelper = createColumnHelper();
+
+ return [
+ columnHelper.accessor('brokerId', {
+ header: 'Broker ID',
+ cell: Cell.BrokerId,
+ }),
+ columnHelper.accessor('size', {
+ header: 'Disk usage',
+ cell: Cell.DiscUsage,
+ }),
+ columnHelper.accessor('partitionsSkew', {
+ header: SkewHeader,
+ cell: Cell.Skew,
+ }),
+ columnHelper.accessor('partitionsLeader', { header: 'Leaders' }),
+ columnHelper.accessor('leadersSkew', {
+ header: 'Leader skew',
+ cell: Cell.Skew,
+ }),
+ columnHelper.accessor('onlinePartitionCount', {
+ header: 'Online partitions',
+ cell: Cell.OnlinePartitions,
+ }),
+ columnHelper.accessor('port', { header: 'Port' }),
+ columnHelper.accessor('host', { header: 'Host' }),
+ ];
+};
diff --git a/frontend/src/components/NavBar/NavBar.styled.ts b/frontend/src/components/NavBar/NavBar.styled.ts
index 8c4dd6f5b..d9013dcdd 100644
--- a/frontend/src/components/NavBar/NavBar.styled.ts
+++ b/frontend/src/components/NavBar/NavBar.styled.ts
@@ -130,18 +130,20 @@ export const Hyperlink = styled(Link)(
align-items: center;
gap: 8px;
- margin: 0;
+ margin: 0 0 0 8px;
padding: 0.5rem 0.75rem;
font-family: Inter, sans-serif;
font-style: normal;
font-weight: bold;
- font-size: 12px;
+ font-size: 22px;
line-height: 16px;
color: ${theme.default.color.normal};
+
&:hover {
color: ${theme.default.color.normal};
}
+
text-decoration: none;
word-break: break-word;
cursor: pointer;
diff --git a/frontend/src/components/NavBar/NavBar.tsx b/frontend/src/components/NavBar/NavBar.tsx
index e025c892c..1a58c7e7b 100644
--- a/frontend/src/components/NavBar/NavBar.tsx
+++ b/frontend/src/components/NavBar/NavBar.tsx
@@ -69,7 +69,7 @@ const NavBar: React.FC = ({ onBurgerClick }) => {
- Kafbat UI
+ kafbat UI
diff --git a/frontend/src/components/NavBar/__tests__/NavBar.spec.tsx b/frontend/src/components/NavBar/__tests__/NavBar.spec.tsx
index 9b3e4528f..a94d941e5 100644
--- a/frontend/src/components/NavBar/__tests__/NavBar.spec.tsx
+++ b/frontend/src/components/NavBar/__tests__/NavBar.spec.tsx
@@ -26,7 +26,7 @@ describe('NavBar', () => {
it('correctly renders header', () => {
const header = screen.getByLabelText('Page Header');
expect(header).toBeInTheDocument();
- expect(within(header).getByText('Kafbat UI')).toBeInTheDocument();
+ expect(within(header).getByText('kafbat UI')).toBeInTheDocument();
expect(within(header).getAllByRole('separator').length).toEqual(3);
expect(
within(header).getByRole('button', burgerButtonOptions)
diff --git a/frontend/src/components/PageContainer/__tests__/PageContainer.spec.tsx b/frontend/src/components/PageContainer/__tests__/PageContainer.spec.tsx
index de270a0a3..b6d654ea5 100644
--- a/frontend/src/components/PageContainer/__tests__/PageContainer.spec.tsx
+++ b/frontend/src/components/PageContainer/__tests__/PageContainer.spec.tsx
@@ -9,9 +9,11 @@ import { Cluster, ServerStatus } from 'generated-sources';
const burgerButtonOptions = { name: 'burger' };
jest.mock('components/Version/Version', () => () => Version
);
+
interface DataType {
data: Cluster[] | undefined;
}
+
jest.mock('lib/hooks/api/clusters');
const mockedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
diff --git a/frontend/src/components/Topics/Topic/Messages/Filters/Filters.tsx b/frontend/src/components/Topics/Topic/Messages/Filters/Filters.tsx
index 22f017088..99eb6bac4 100644
--- a/frontend/src/components/Topics/Topic/Messages/Filters/Filters.tsx
+++ b/frontend/src/components/Topics/Topic/Messages/Filters/Filters.tsx
@@ -13,7 +13,7 @@ import {
} from 'generated-sources';
import React, { useContext } from 'react';
import omitBy from 'lodash/omitBy';
-import { useNavigate, useLocation, useSearchParams } from 'react-router-dom';
+import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
import MultiSelect from 'components/common/MultiSelect/MultiSelect.styled';
import { Option } from 'react-multi-select-component';
import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
@@ -55,11 +55,17 @@ export interface FiltersProps {
meta: TopicMessageConsuming;
isFetching: boolean;
messageEventType?: string;
+
addMessage(content: { message: TopicMessage; prepend: boolean }): void;
+
resetMessages(): void;
+
updatePhase(phase: string): void;
+
updateMeta(meta: TopicMessageConsuming): void;
+
setIsFetching(status: boolean): void;
+
setMessageType(messageType: string): void;
}
@@ -205,10 +211,7 @@ const Filters: React.FC = ({
const handleFiltersSubmit = (currentOffset: string) => {
const nextAttempt = Number(searchParams.get('attempt') || 0) + 1;
const props: Query = {
- q:
- queryType === MessageFilterType.CEL_SCRIPT
- ? activeFilter.code
- : query,
+ q: queryType === MessageFilterType.CEL_SCRIPT ? activeFilter.code : query,
filterQueryType: queryType,
attempt: nextAttempt,
limit: PER_PAGE,
diff --git a/frontend/src/components/common/Logo/Logo.styled.ts b/frontend/src/components/common/Logo/Logo.styled.ts
new file mode 100644
index 000000000..51d649c62
--- /dev/null
+++ b/frontend/src/components/common/Logo/Logo.styled.ts
@@ -0,0 +1,5 @@
+import styled from 'styled-components';
+
+export const Logo = styled.svg`
+ fill: ${({ theme }) => theme.logo.color};
+`;
diff --git a/frontend/src/components/common/Logo/Logo.tsx b/frontend/src/components/common/Logo/Logo.tsx
index b209f32b2..d149d6511 100644
--- a/frontend/src/components/common/Logo/Logo.tsx
+++ b/frontend/src/components/common/Logo/Logo.tsx
@@ -1,19 +1,18 @@
import React from 'react';
+import * as S from './Logo.styled';
+
const Logo: React.FC = () => {
return (
-
+
+
);
};
diff --git a/frontend/src/components/common/NewTable/SizeCell.tsx b/frontend/src/components/common/NewTable/SizeCell.tsx
index 7a230be81..4b472b5bd 100644
--- a/frontend/src/components/common/NewTable/SizeCell.tsx
+++ b/frontend/src/components/common/NewTable/SizeCell.tsx
@@ -2,16 +2,15 @@ import React from 'react';
import { CellContext } from '@tanstack/react-table';
import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-type AsAny = any;
-
-const SizeCell: React.FC<
- CellContext & { renderSegments?: boolean; precision?: number }
-> = ({ getValue, row, renderSegments = false, precision = 0 }) => (
- <>
+const SizeCell = ({
+ getValue,
+ precision = 0,
+}: CellContext & {
+ precision?: number;
+}) => {
+ return (
()} precision={precision} />
- {renderSegments ? `, ${row?.original.count} segment(s)` : null}
- >
-);
+ );
+};
export default SizeCell;
diff --git a/frontend/src/components/common/NewTable/SizeCellCount.tsx b/frontend/src/components/common/NewTable/SizeCellCount.tsx
new file mode 100644
index 000000000..80df59b9f
--- /dev/null
+++ b/frontend/src/components/common/NewTable/SizeCellCount.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { CellContext } from '@tanstack/react-table';
+import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
+
+const SizeCellCount = ({
+ getValue,
+ row,
+ precision = 0,
+}: CellContext & {
+ precision?: number;
+}) => {
+ return (
+ <>
+ ()}
+ precision={precision}
+ />
+ {`, ${row.original.count} segment(s)`}
+ >
+ );
+};
+
+export default SizeCellCount;
diff --git a/frontend/src/components/common/NewTable/Table.tsx b/frontend/src/components/common/NewTable/Table.tsx
index 42d406b4f..df4421c98 100644
--- a/frontend/src/components/common/NewTable/Table.tsx
+++ b/frontend/src/components/common/NewTable/Table.tsx
@@ -1,20 +1,20 @@
import React from 'react';
+import type {
+ ColumnDef,
+ OnChangeFn,
+ PaginationState,
+ Row,
+ SortingState,
+} from '@tanstack/react-table';
import {
flexRender,
getCoreRowModel,
getExpandedRowModel,
+ getPaginationRowModel,
getSortedRowModel,
useReactTable,
- getPaginationRowModel,
} from '@tanstack/react-table';
-import type {
- Row,
- SortingState,
- OnChangeFn,
- PaginationState,
- ColumnDef,
-} from '@tanstack/react-table';
-import { useSearchParams, useLocation } from 'react-router-dom';
+import { useLocation, useSearchParams } from 'react-router-dom';
import { PER_PAGE } from 'lib/constants';
import { Button } from 'components/common/Button/Button';
import Input from 'components/common/Input/Input';
@@ -26,10 +26,13 @@ import ExpanderCell from './ExpanderCell';
import SelectRowCell from './SelectRowCell';
import SelectRowHeader from './SelectRowHeader';
-export interface TableProps {
+export interface TableProps {
data: TData[];
pageCount?: number;
- columns: ColumnDef[];
+
+ // https://github.com/TanStack/table/issues/4382
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ columns: ColumnDef[];
// Server-side processing: sorting, pagination
serverSideProcessing?: boolean;
@@ -118,7 +121,7 @@ const getSortingFromSearchParams = (searchParams: URLSearchParams) => {
* - use URLSearchParams to get the pagination and sorting state from the url for your server side processing.
*/
-function Table({
+function Table({
data,
pageCount,
columns,
@@ -134,7 +137,7 @@ function Table({
onRowHover,
onMouseLeave,
setRowId,
-}: TableProps) {
+}: TableProps) {
const [searchParams, setSearchParams] = useSearchParams();
const location = useLocation();
const [rowSelection, setRowSelection] = React.useState({});
diff --git a/frontend/src/components/common/PageLoader/PageLoader.styled.ts b/frontend/src/components/common/PageLoader/PageLoader.styled.ts
index f38f21c0b..36c5848e0 100644
--- a/frontend/src/components/common/PageLoader/PageLoader.styled.ts
+++ b/frontend/src/components/common/PageLoader/PageLoader.styled.ts
@@ -1,10 +1,15 @@
import styled from 'styled-components';
-export const Wrapper = styled.div`
+export interface PageLoaderProps {
+ fullSize?: boolean;
+}
+
+export const Wrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
- padding-top: 15%;
height: 100%;
width: 100%;
+ background-color: ${({ theme }) => theme.default.backgroundColor};
+ ${({ fullSize }) => (fullSize ? `min-height: 100vh;` : 'padding-top: 15%;')}
`;
diff --git a/frontend/src/components/common/PageLoader/PageLoader.tsx b/frontend/src/components/common/PageLoader/PageLoader.tsx
index 674ab0f0c..b568357dd 100644
--- a/frontend/src/components/common/PageLoader/PageLoader.tsx
+++ b/frontend/src/components/common/PageLoader/PageLoader.tsx
@@ -2,9 +2,10 @@ import React from 'react';
import Spinner from 'components/common/Spinner/Spinner';
import * as S from './PageLoader.styled';
+import { PageLoaderProps } from './PageLoader.styled';
-const PageLoader: React.FC = () => (
-
+const PageLoader: React.FC = ({ fullSize }) => (
+
);
diff --git a/frontend/src/theme/theme.ts b/frontend/src/theme/theme.ts
index 8426d3c2f..44e19eb5b 100644
--- a/frontend/src/theme/theme.ts
+++ b/frontend/src/theme/theme.ts
@@ -35,15 +35,15 @@ const Colors = {
'60': '#29A352',
},
brand: {
- '5': '#E8E8FC',
- '10': '#D1D1FA',
- '15': '#B8BEF9',
- '20': '#A3A3F5',
- '30': '#7E7EF1',
- '40': '#6666FF',
- '50': '#4C4CFF',
- '60': '#1717CF',
- '70': '#1414B8',
+ '5': '#F1F2F3',
+ '10': '#E3E6E8',
+ '15': '#D5DADD',
+ '20': '#C7CED1',
+ '30': '#ABB5BA',
+ '40': '#8F9CA3',
+ '50': '#2F3639',
+ '60': '#22282A',
+ '70': '#171A1C',
},
red: {
'10': '#FAD1D1',
@@ -313,6 +313,9 @@ const baseTheme = {
export const theme = {
...baseTheme,
+ logo: {
+ color: Colors.brand[70],
+ },
version: {
currentVersion: {
color: Colors.neutral[30],
@@ -389,8 +392,8 @@ export const theme = {
primary: {
backgroundColor: {
normal: Colors.brand[50],
- hover: Colors.brand[60],
- active: Colors.brand[70],
+ hover: Colors.brand[70],
+ active: Colors.brand[60],
disabled: Colors.neutral[5],
},
color: {
@@ -756,6 +759,9 @@ export type ThemeType = typeof theme;
export const darkTheme: ThemeType = {
...baseTheme,
+ logo: {
+ color: '#FDFDFD',
+ },
version: {
currentVersion: {
color: Colors.neutral[50],
@@ -831,13 +837,13 @@ export const darkTheme: ThemeType = {
button: {
primary: {
backgroundColor: {
- normal: Colors.brand[30],
- hover: Colors.brand[20],
- active: Colors.brand[10],
- disabled: Colors.neutral[75],
+ normal: Colors.brand[10],
+ hover: Colors.brand[5],
+ active: Colors.brand[20],
+ disabled: Colors.brand[60],
},
color: {
- normal: Colors.neutral[0],
+ normal: Colors.neutral[70],
disabled: Colors.neutral[60],
},
invertedColors: {
@@ -848,9 +854,9 @@ export const darkTheme: ThemeType = {
},
secondary: {
backgroundColor: {
- normal: Colors.blue[80],
- hover: Colors.blue[70],
- active: Colors.blue[60],
+ normal: Colors.brand[50],
+ hover: Colors.brand[70],
+ active: Colors.brand[60],
disabled: Colors.neutral[75],
},
color: {