Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FE: Brokers: Configs: Improvements #179

Merged
merged 15 commits into from
Mar 12, 2024
Merged
Original file line number Diff line number Diff line change
@@ -1,36 +1,6 @@
import styled from 'styled-components';

export const ValueWrapper = styled.div`
display: flex;
justify-content: space-between;
button {
margin: 0 10px;
}
`;

export const Value = styled.span`
line-height: 24px;
margin-right: 10px;
text-overflow: ellipsis;
max-width: 400px;
overflow: hidden;
white-space: nowrap;
`;

export const ButtonsWrapper = styled.div`
display: flex;
`;
export const SearchWrapper = styled.div`
margin: 10px;
width: 21%;
`;

export const Source = styled.div`
display: flex;
align-content: center;
svg {
margin-left: 10px;
vertical-align: middle;
cursor: pointer;
}
`;
103 changes: 24 additions & 79 deletions frontend/src/components/Brokers/Broker/Configs/Configs.tsx
Original file line number Diff line number Diff line change
@@ -1,110 +1,55 @@
import React from 'react';
import { CellContext, ColumnDef } from '@tanstack/react-table';
import React, { type FC, useMemo, useState } from 'react';
import { ClusterBrokerParam } from 'lib/paths';
import useAppParams from 'lib/hooks/useAppParams';
import {
useBrokerConfig,
useUpdateBrokerConfigByName,
} from 'lib/hooks/api/brokers';
import Table from 'components/common/NewTable';
import { BrokerConfig, ConfigSource } from 'generated-sources';
import type { BrokerConfig } from 'generated-sources';
import Search from 'components/common/Search/Search';
import Tooltip from 'components/common/Tooltip/Tooltip';
import InfoIcon from 'components/common/Icons/InfoIcon';
import {
getBrokerConfigsTableColumns,
getConfigTableData,
} from 'components/Brokers/Broker/Configs/lib/utils';

import InputCell from './InputCell';
import * as S from './Configs.styled';

const tooltipContent = `DYNAMIC_TOPIC_CONFIG = dynamic topic config that is configured for a specific topic
DYNAMIC_BROKER_LOGGER_CONFIG = dynamic broker logger config that is configured for a specific broker
DYNAMIC_BROKER_CONFIG = dynamic broker config that is configured for a specific broker
DYNAMIC_DEFAULT_BROKER_CONFIG = dynamic broker config that is configured as default for all brokers in the cluster
STATIC_BROKER_CONFIG = static broker config provided as broker properties at start up (e.g. server.properties file)
DEFAULT_CONFIG = built-in default configuration for configs that have a default value
UNKNOWN = source unknown e.g. in the ConfigEntry used for alter requests where source is not set`;

const Configs: React.FC = () => {
const [keyword, setKeyword] = React.useState('');
const Configs: FC = () => {
const [searchQuery, setSearchQuery] = useState('');
const { clusterName, brokerId } = useAppParams<ClusterBrokerParam>();
Leshe4ka marked this conversation as resolved.
Show resolved Hide resolved
const { data = [] } = useBrokerConfig(clusterName, Number(brokerId));
const stateMutation = useUpdateBrokerConfigByName(
const { data: configs = [] } = useBrokerConfig(clusterName, Number(brokerId));
const updateBrokerConfigByName = useUpdateBrokerConfigByName(
clusterName,
Number(brokerId)
);

const getData = () => {
return data
.filter((item) => {
const nameMatch = item.name
.toLocaleLowerCase()
.includes(keyword.toLocaleLowerCase());
return nameMatch
? true
: item.value &&
item.value
.toLocaleLowerCase()
.includes(keyword.toLocaleLowerCase()); // try to match the keyword on any of the item.value elements when nameMatch fails but item.value exists
})
.sort((a, b) => {
if (a.source === b.source) return 0;
return a.source === ConfigSource.DYNAMIC_BROKER_CONFIG ? -1 : 1;
});
};

const dataSource = React.useMemo(() => getData(), [data, keyword]);

const renderCell = (props: CellContext<BrokerConfig, unknown>) => (
<InputCell
{...props}
onUpdate={(name, value) => {
stateMutation.mutateAsync({
name,
brokerConfigItem: {
value,
},
});
}}
/>
const tableData = useMemo(
() => getConfigTableData(configs, searchQuery),
[configs, searchQuery]
);

const columns = React.useMemo<ColumnDef<BrokerConfig>[]>(
() => [
{ header: 'Key', accessorKey: 'name' },
{
header: 'Value',
accessorKey: 'value',
cell: renderCell,
},
{
// eslint-disable-next-line react/no-unstable-nested-components
header: () => {
return (
<S.Source>
Source
<Tooltip
value={<InfoIcon />}
content={tooltipContent}
placement="top-end"
/>
</S.Source>
);
},
accessorKey: 'source',
},
],
const onUpdateInputCell = async (
name: BrokerConfig['name'],
value: BrokerConfig['value']
) =>
updateBrokerConfigByName.mutateAsync({ name, brokerConfigItem: { value } });

const columns = useMemo(
() => getBrokerConfigsTableColumns(onUpdateInputCell),
[]
);

return (
<>
<S.SearchWrapper>
<Search
onChange={setKeyword}
onChange={setSearchQuery}
placeholder="Search by Key or Value"
value={keyword}
value={searchQuery}
/>
</S.SearchWrapper>
<Table columns={columns} data={dataSource} />
<Table columns={columns} data={tableData} />
</>
);
};
Expand Down
91 changes: 0 additions & 91 deletions frontend/src/components/Brokers/Broker/Configs/InputCell.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import styled from 'styled-components';

export const Source = styled.div`
display: flex;
align-content: center;

svg {
margin-left: 10px;
vertical-align: middle;
cursor: pointer;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import Tooltip from 'components/common/Tooltip/Tooltip';
import InfoIcon from 'components/common/Icons/InfoIcon';
import { CONFIG_SOURCE_NAME_MAP } from 'components/Brokers/Broker/Configs/lib/constants';

import * as S from './ConfigSourceHeader.styled';

const tooltipContent = `${CONFIG_SOURCE_NAME_MAP.DYNAMIC_TOPIC_CONFIG} = dynamic topic config that is configured for a specific topic
${CONFIG_SOURCE_NAME_MAP.DYNAMIC_BROKER_LOGGER_CONFIG} = dynamic broker logger config that is configured for a specific broker
${CONFIG_SOURCE_NAME_MAP.DYNAMIC_BROKER_CONFIG} = dynamic broker config that is configured for a specific broker
${CONFIG_SOURCE_NAME_MAP.DYNAMIC_DEFAULT_BROKER_CONFIG} = dynamic broker config that is configured as default for all brokers in the cluster
${CONFIG_SOURCE_NAME_MAP.STATIC_BROKER_CONFIG} = static broker config provided as broker properties at start up (e.g. server.properties file)
${CONFIG_SOURCE_NAME_MAP.DEFAULT_CONFIG} = built-in default configuration for configs that have a default value
${CONFIG_SOURCE_NAME_MAP.UNKNOWN} = source unknown e.g. in the ConfigEntry used for alter requests where source is not set`;

const ConfigSourceHeader = () => (
<S.Source>
Source
<Tooltip
value={<InfoIcon />}
content={tooltipContent}
placement="top-end"
/>
</S.Source>
);

export default ConfigSourceHeader;
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { type FC, useState } from 'react';
import Input from 'components/common/Input/Input';
import { Button } from 'components/common/Button/Button';
import CheckmarkIcon from 'components/common/Icons/CheckmarkIcon';
import CancelIcon from 'components/common/Icons/CancelIcon';

import * as S from './styled';

interface EditModeProps {
initialValue: string;
onSave: (value: string) => void;
onCancel: () => void;
}

const InputCellEditMode: FC<EditModeProps> = ({
initialValue,
onSave,
onCancel,
}) => {
const [value, setValue] = useState(initialValue);

return (
<S.ValueWrapper>
<Input
type="text"
inputSize="S"
value={value}
aria-label="inputValue"
onChange={({ target }) => setValue(target.value)}
/>
<S.ButtonsWrapper>
<Button
buttonType="primary"
buttonSize="S"
aria-label="confirmAction"
onClick={() => onSave(value)}
>
<CheckmarkIcon /> Save
</Button>
<Button
buttonType="primary"
buttonSize="S"
aria-label="cancelAction"
onClick={onCancel}
>
<CancelIcon /> Cancel
</Button>
</S.ButtonsWrapper>
</S.ValueWrapper>
);
};

export default InputCellEditMode;
Loading
Loading