浏览代码

Remove messages v2 (#2917)

Oleg Shur 2 年之前
父节点
当前提交
8b7c8e3216
共有 21 个文件被更改,包括 8 次插入1221 次删除
  1. 6 0
      kafka-ui-react-app/src/components/Topics/Topic/Messages/Messages.styled.ts
  2. 1 1
      kafka-ui-react-app/src/components/Topics/Topic/Messages/Messages.tsx
  3. 0 0
      kafka-ui-react-app/src/components/Topics/Topic/Messages/getDefaultSerdeName.ts
  4. 0 53
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/Advanced Filter/AdvancedFilter.tsx
  5. 0 118
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/Advanced Filter/Form.tsx
  6. 0 75
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/FiltersBar/FiltersBar.styled.ts
  7. 0 193
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/FiltersBar/Form.tsx
  8. 0 46
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/FiltersBar/Meta.tsx
  9. 0 112
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/FiltersBar/utils.ts
  10. 0 64
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/Messages.styled.ts
  11. 0 112
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/Messages.tsx
  12. 0 62
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesContainer.tsx
  13. 0 25
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesTable/ActionsCell.tsx
  14. 0 55
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesTable/MessageContent/MessageContent.styled.ts
  15. 0 106
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesTable/MessageContent/MessageContent.tsx
  16. 0 41
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesTable/MessagesTable.tsx
  17. 0 39
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/StatusBar.tsx
  18. 0 50
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/utils/consumingModes.ts
  19. 0 65
      kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/utils/handleNextPageClick.ts
  20. 0 3
      kafka-ui-react-app/src/components/Topics/Topic/Topic.tsx
  21. 1 1
      kafka-ui-react-app/src/lib/hooks/api/topicMessages.tsx

+ 6 - 0
kafka-ui-react-app/src/components/Topics/Topic/Messages/Messages.styled.ts

@@ -0,0 +1,6 @@
+import styled from 'styled-components';
+
+export const StopLoading = styled.div`
+  color: ${({ theme }) => theme.pageLoader.borderColor};
+  cursor: pointer;
+`;

+ 1 - 1
kafka-ui-react-app/src/components/Topics/Topic/Messages/Messages.tsx

@@ -5,7 +5,7 @@ import { useSearchParams } from 'react-router-dom';
 import { useSerdes } from 'lib/hooks/api/topicMessages';
 import useAppParams from 'lib/hooks/useAppParams';
 import { RouteParamsClusterTopic } from 'lib/paths';
-import { getDefaultSerdeName } from 'components/Topics/Topic/MessagesV2/utils/getDefaultSerdeName';
+import { getDefaultSerdeName } from 'components/Topics/Topic/Messages/getDefaultSerdeName';
 
 import MessagesTable from './MessagesTable';
 import FiltersContainer from './Filters/FiltersContainer';

+ 0 - 0
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/utils/getDefaultSerdeName.ts → kafka-ui-react-app/src/components/Topics/Topic/Messages/getDefaultSerdeName.ts


+ 0 - 53
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/Advanced Filter/AdvancedFilter.tsx

@@ -1,53 +0,0 @@
-import React from 'react';
-import { useMessageFiltersStore } from 'lib/hooks/useMessageFiltersStore';
-import * as StyledTable from 'components/common/NewTable/Table.styled';
-import Heading from 'components/common/heading/Heading.styled';
-import { Dropdown, DropdownItem } from 'components/common/Dropdown';
-
-import Form from './Form';
-
-const AdvancedFilter = () => {
-  const { save, apply, filters, remove } = useMessageFiltersStore();
-  return (
-    <div>
-      <Heading level={4}>Add new filter</Heading>
-      <Form save={save} apply={apply} />
-      {filters.length > 0 && (
-        <>
-          <Heading level={4}>Saved Filters</Heading>
-          <StyledTable.Table>
-            <thead>
-              <tr>
-                <StyledTable.Th>Name</StyledTable.Th>
-                <StyledTable.Th>Value</StyledTable.Th>
-                <StyledTable.Th> </StyledTable.Th>
-              </tr>
-            </thead>
-            <tbody>
-              {filters.map((filter) => (
-                <tr key={filter.name}>
-                  <td>{filter.name}</td>
-                  <td>
-                    <pre>{filter.value}</pre>
-                  </td>
-                  <td>
-                    <Dropdown>
-                      <DropdownItem onClick={() => apply(filter)}>
-                        Apply Filter
-                      </DropdownItem>
-                      <DropdownItem onClick={() => remove(filter.name)}>
-                        Delete filter
-                      </DropdownItem>
-                    </Dropdown>
-                  </td>
-                </tr>
-              ))}
-            </tbody>
-          </StyledTable.Table>
-        </>
-      )}
-    </div>
-  );
-};
-
-export default AdvancedFilter;

+ 0 - 118
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/Advanced Filter/Form.tsx

@@ -1,118 +0,0 @@
-import React from 'react';
-import * as S from 'components/Topics/Topic/Messages/Filters/Filters.styled';
-import { InputLabel } from 'components/common/Input/InputLabel.styled';
-import Input from 'components/common/Input/Input';
-import { FormProvider, Controller, useForm } from 'react-hook-form';
-import { ErrorMessage } from '@hookform/error-message';
-import { Button } from 'components/common/Button/Button';
-import { FormError } from 'components/common/Input/Input.styled';
-import Editor from 'components/common/Editor/Editor';
-import { yupResolver } from '@hookform/resolvers/yup';
-import yup from 'lib/yupExtended';
-import { AdvancedFilter } from 'lib/hooks/useMessageFiltersStore';
-
-const validationSchema = yup.object().shape({
-  value: yup.string().required(),
-  name: yup.string().required(),
-});
-
-export interface FormProps {
-  name?: string;
-  value?: string;
-  save(filter: AdvancedFilter): void;
-  apply(filter: AdvancedFilter): void;
-}
-
-const Form: React.FC<FormProps> = ({ name, value, save, apply }) => {
-  const methods = useForm<AdvancedFilter>({
-    mode: 'onChange',
-    resolver: yupResolver(validationSchema),
-  });
-  const {
-    handleSubmit,
-    control,
-    formState: { isDirty, isSubmitting, isValid, errors },
-    reset,
-    getValues,
-  } = methods;
-
-  const onSubmit = React.useCallback(
-    (values: AdvancedFilter) => {
-      apply(values);
-      reset({ name: '', value: '' });
-    },
-    [reset, save]
-  );
-
-  const onSave = React.useCallback(() => {
-    save(getValues());
-    handleSubmit(onSubmit);
-  }, []);
-
-  return (
-    <FormProvider {...methods}>
-      <form onSubmit={handleSubmit(onSubmit)} aria-label="Filters submit Form">
-        <div>
-          <InputLabel>Filter code</InputLabel>
-          <Controller
-            control={control}
-            name="value"
-            defaultValue={value}
-            render={({ field }) => (
-              <Editor
-                value={field.value}
-                minLines={5}
-                maxLines={28}
-                onChange={field.onChange}
-                setOptions={{
-                  showLineNumbers: false,
-                }}
-              />
-            )}
-          />
-        </div>
-        <div>
-          <FormError>
-            <ErrorMessage errors={errors} name="value" />
-          </FormError>
-        </div>
-        <div>
-          <InputLabel>Display name</InputLabel>
-          <Input
-            inputSize="M"
-            placeholder="Enter Name"
-            autoComplete="off"
-            name="name"
-            defaultValue={name}
-          />
-        </div>
-        <div>
-          <FormError>
-            <ErrorMessage errors={errors} name="name" />
-          </FormError>
-        </div>
-        <S.FilterButtonWrapper>
-          <Button
-            buttonSize="M"
-            buttonType="secondary"
-            type="submit"
-            disabled={!isValid || isSubmitting || !isDirty}
-            onClick={onSave}
-          >
-            Save & Apply
-          </Button>
-          <Button
-            buttonSize="M"
-            buttonType="primary"
-            type="submit"
-            disabled={isSubmitting || !isDirty}
-          >
-            Apply Filter
-          </Button>
-        </S.FilterButtonWrapper>
-      </form>
-    </FormProvider>
-  );
-};
-
-export default Form;

+ 0 - 75
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/FiltersBar/FiltersBar.styled.ts

@@ -1,75 +0,0 @@
-import styled from 'styled-components';
-import DatePicker from 'react-datepicker';
-
-export const Meta = styled.div`
-  display: flex;
-  flex-direction: column;
-  gap: 4px;
-  padding: 6px 16px;
-  border-bottom: 1px solid ${({ theme }) => theme.layout.stuffBorderColor};
-`;
-
-export const MetaRow = styled.div`
-  display: flex;
-  align-items: center;
-  gap: 20px;
-`;
-
-export const Metric = styled.div`
-  color: ${({ theme }) => theme.metrics.filters.color.normal};
-  font-size: 12px;
-  display: flex;
-`;
-
-export const MetricIcon = styled.div`
-  color: ${({ theme }) => theme.metrics.filters.color.icon};
-  padding-right: 6px;
-  height: 12px;
-`;
-
-export const MetaMessage = styled.div.attrs({
-  role: 'contentLoader',
-})`
-  color: ${({ theme }) => theme.heading.h3.color};
-  font-size: 12px;
-  display: flex;
-  gap: 8px;
-`;
-
-export const StopLoading = styled.div`
-  color: ${({ theme }) => theme.pageLoader.borderColor};
-  cursor: pointer;
-`;
-
-export const FilterRow = styled.div`
-  margin: 8px 0 8px;
-`;
-export const FilterFooter = styled.div`
-  display: flex;
-  gap: 8px;
-  justify-content: end;
-  margin: 16px 0;
-`;
-
-export const DatePickerInput = styled(DatePicker)`
-  height: 32px;
-  border: 1px ${(props) => props.theme.select.borderColor.normal} solid;
-  border-radius: 4px;
-  font-size: 14px;
-  width: 100%;
-  padding-left: 12px;
-  color: ${(props) => props.theme.select.color.normal};
-
-  background-image: url('data:image/svg+xml,%3Csvg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M1 1L5 5L9 1" stroke="%23454F54"/%3E%3C/svg%3E%0A') !important;
-  background-repeat: no-repeat !important;
-  background-position-x: 96% !important;
-  background-position-y: 55% !important;
-  appearance: none !important;
-
-  &:hover {
-    cursor: pointer;
-  }
-  &:focus {
-    outline: none;
-  }
-`;

+ 0 - 193
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/FiltersBar/Form.tsx

@@ -1,193 +0,0 @@
-import React from 'react';
-import { useForm } from 'react-hook-form';
-import { useSearchParams } from 'react-router-dom';
-import Input from 'components/common/Input/Input';
-import { ConsumingMode, useSerdes } from 'lib/hooks/api/topicMessages';
-import Select from 'components/common/Select/Select';
-import { InputLabel } from 'components/common/Input/InputLabel.styled';
-import { Option } from 'react-multi-select-component';
-import { Button } from 'components/common/Button/Button';
-import { Partition, SerdeUsage } from 'generated-sources';
-import { getModeOptions } from 'components/Topics/Topic/MessagesV2/utils/consumingModes';
-import { getSerdeOptions } from 'components/Topics/Topic/SendMessage/utils';
-import useAppParams from 'lib/hooks/useAppParams';
-import { RouteParamsClusterTopic } from 'lib/paths';
-
-import * as S from './FiltersBar.styled';
-import { setSeekTo } from './utils';
-
-type FormValues = {
-  mode: ConsumingMode;
-  offset: string;
-  time: Date;
-  partitions: Option[];
-  keySerde: string;
-  valueSerde: string;
-};
-
-const Form: React.FC<{ isFetching: boolean; partitions: Partition[] }> = ({
-  isFetching,
-  partitions,
-}) => {
-  const [searchParams, setSearchParams] = useSearchParams();
-  const routerProps = useAppParams<RouteParamsClusterTopic>();
-  const { data: serdes = {} } = useSerdes({
-    ...routerProps,
-    use: SerdeUsage.DESERIALIZE,
-  });
-
-  const {
-    handleSubmit,
-    setValue,
-    watch,
-    formState: { isDirty },
-    reset,
-  } = useForm<FormValues>({
-    defaultValues: {
-      mode: searchParams.get('m') || 'newest',
-      offset: searchParams.get('o') || '0',
-      time: searchParams.get('t')
-        ? new Date(Number(searchParams.get('t')))
-        : Date.now(),
-      keySerde: searchParams.get('keySerde') as string,
-      valueSerde: searchParams.get('valueSerde') as string,
-    } as FormValues,
-  });
-  const mode = watch('mode');
-  const offset = watch('offset');
-  const time = watch('time');
-  const keySerde = watch('keySerde');
-  const valueSerde = watch('valueSerde');
-
-  const onSubmit = (values: FormValues) => {
-    searchParams.set('m', values.mode);
-    if (values.keySerde) {
-      searchParams.set('keySerde', values.keySerde);
-    }
-    if (values.valueSerde) {
-      searchParams.set('valueSerde', values.valueSerde);
-    }
-    searchParams.delete('o');
-    searchParams.delete('t');
-    searchParams.delete('a');
-    searchParams.delete('page');
-    if (['fromOffset', 'toOffset'].includes(mode)) {
-      searchParams.set('o', values.offset);
-    } else if (['sinceTime', 'untilTime'].includes(mode)) {
-      searchParams.set('t', `${values.time.getTime()}`);
-    }
-
-    setSeekTo(searchParams, partitions);
-    setSearchParams(searchParams);
-    reset(values);
-  };
-
-  const handleTimestampChange = (value: Date | null) => {
-    if (value) {
-      setValue('time', value, { shouldDirty: true });
-    }
-  };
-  const handleOffsetChange = (e: React.ChangeEvent<HTMLInputElement>) => {
-    setValue('offset', e.target.value, { shouldDirty: true });
-  };
-  const handleSerdeChange =
-    (type: 'keySerde' | 'valueSerde') => (option: string | number) => {
-      setValue(type, String(option), { shouldDirty: true });
-    };
-  const handleRefresh: React.MouseEventHandler<HTMLButtonElement> = (e) => {
-    e.stopPropagation();
-    e.preventDefault();
-    searchParams.set('a', `${Number(searchParams.get('a') || 0) + 1}`);
-    setSearchParams(searchParams);
-  };
-
-  return (
-    <form onSubmit={handleSubmit(onSubmit)}>
-      <S.FilterRow>
-        <InputLabel>Mode</InputLabel>
-        <Select
-          selectSize="M"
-          minWidth="100%"
-          value={mode}
-          options={getModeOptions()}
-          isLive={mode === 'live' && isFetching}
-          onChange={(option: string | number) =>
-            setValue('mode', option as ConsumingMode, { shouldDirty: true })
-          }
-        />
-      </S.FilterRow>
-      {['sinceTime', 'untilTime'].includes(mode) && (
-        <S.FilterRow>
-          <InputLabel>Time</InputLabel>
-          <S.DatePickerInput
-            selected={time}
-            onChange={handleTimestampChange}
-            showTimeInput
-            timeInputLabel="Time:"
-            dateFormat="MMMM d, yyyy HH:mm"
-            placeholderText="Select timestamp"
-          />
-        </S.FilterRow>
-      )}
-      {['fromOffset', 'toOffset'].includes(mode) && (
-        <S.FilterRow>
-          <InputLabel>Offset</InputLabel>
-          <Input
-            type="text"
-            inputSize="M"
-            value={offset}
-            placeholder="Offset"
-            onChange={handleOffsetChange}
-          />
-        </S.FilterRow>
-      )}
-      <S.FilterRow>
-        <InputLabel>Key Serde</InputLabel>
-        <Select
-          id="selectKeySerdeOptions"
-          aria-labelledby="selectKeySerdeOptions"
-          onChange={handleSerdeChange('keySerde')}
-          options={getSerdeOptions(serdes.key || [])}
-          value={keySerde}
-          selectSize="M"
-          minWidth="100%"
-        />
-      </S.FilterRow>
-      <S.FilterRow>
-        <InputLabel>Content Serde</InputLabel>
-        <Select
-          id="selectValueSerdeOptions"
-          aria-labelledby="selectValueSerdeOptions"
-          onChange={handleSerdeChange('valueSerde')}
-          options={getSerdeOptions(serdes.value || [])}
-          value={valueSerde}
-          selectSize="M"
-          minWidth="100%"
-        />
-      </S.FilterRow>
-      <S.FilterFooter>
-        <Button
-          buttonType="secondary"
-          disabled={!isDirty}
-          buttonSize="S"
-          onClick={() => reset()}
-        >
-          Clear All
-        </Button>
-        <Button
-          buttonType="secondary"
-          buttonSize="S"
-          disabled={isDirty || isFetching}
-          onClick={handleRefresh}
-        >
-          Refresh
-        </Button>
-        <Button buttonType="primary" disabled={!isDirty} buttonSize="S">
-          Apply Mode
-        </Button>
-      </S.FilterFooter>
-    </form>
-  );
-};
-
-export default Form;

+ 0 - 46
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/FiltersBar/Meta.tsx

@@ -1,46 +0,0 @@
-import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
-import ArrowDownIcon from 'components/common/Icons/ArrowDownIcon';
-import ClockIcon from 'components/common/Icons/ClockIcon';
-import FileIcon from 'components/common/Icons/FileIcon';
-import { TopicMessageConsuming } from 'generated-sources';
-import { formatMilliseconds } from 'lib/dateTimeHelpers';
-import React from 'react';
-
-import * as S from './FiltersBar.styled';
-
-interface MetaProps {
-  meta?: TopicMessageConsuming;
-  phase?: string;
-  isFetching: boolean;
-}
-
-const Meta: React.FC<MetaProps> = ({ meta = {} }) => {
-  const { bytesConsumed, messagesConsumed, elapsedMs } = meta;
-
-  return (
-    <S.Meta>
-      <S.MetaRow>
-        <S.Metric title="Messages Consumed">
-          <S.MetricIcon>
-            <FileIcon />
-          </S.MetricIcon>
-          <span>{messagesConsumed || 0} msg.</span>
-        </S.Metric>
-        <S.Metric title="Bytes Consumed">
-          <S.MetricIcon>
-            <ArrowDownIcon />
-          </S.MetricIcon>
-          <BytesFormatted value={bytesConsumed || 0} />
-        </S.Metric>
-        <S.Metric title="Elapsed Time">
-          <S.MetricIcon>
-            <ClockIcon />
-          </S.MetricIcon>
-          <span>{formatMilliseconds(elapsedMs)}</span>
-        </S.Metric>
-      </S.MetaRow>
-    </S.Meta>
-  );
-};
-
-export default Meta;

+ 0 - 112
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/FiltersBar/utils.ts

@@ -1,112 +0,0 @@
-import { Partition } from 'generated-sources';
-import { ConsumingMode } from 'lib/hooks/api/topicMessages';
-import { Option } from 'react-multi-select-component';
-
-export const filterOptions = (options: Option[], filter: string) => {
-  if (!filter) {
-    return options;
-  }
-  return options.filter(({ value }) => value && value.toString() === filter);
-};
-
-export const convertPartitionsToOptions = (ids: Array<string>): Option[] =>
-  ids.map((id) => ({
-    label: `Partition #${id}`,
-    value: `${id}`,
-  }));
-
-export const getSelectedPartitions = (
-  allIds: string[],
-  query: string | null
-) => {
-  let selectedIds: string[] = [];
-  switch (query) {
-    case null: // Empty array of partitions in searchParams - means all
-    case 'all':
-      selectedIds = allIds;
-      break;
-    case 'none':
-      selectedIds = [];
-      break;
-    default:
-      selectedIds = query.split('.');
-      break;
-  }
-  return convertPartitionsToOptions(selectedIds);
-};
-
-type PartionOffsetKey = 'offsetMax' | 'offsetMin';
-
-const generateSeekTo = (
-  partitions: Partition[],
-  type: 'property' | 'value',
-  value: PartionOffsetKey | string
-) => {
-  // we iterating over existing partitions to avoid sending wrong partition ids to the backend
-  const seekTo = partitions.map((partition) => {
-    const { partition: id } = partition;
-    switch (type) {
-      case 'property':
-        return `${id}-${partition[value as PartionOffsetKey]}`;
-      case 'value':
-        return `${id}-${value}`;
-      default:
-        return null;
-    }
-  });
-
-  return seekTo.join('.');
-};
-
-export const generateSeekToForSelectedPartitions = (
-  mode: ConsumingMode,
-  partitions: Partition[],
-  offset: string,
-  time: string
-) => {
-  switch (mode) {
-    case 'live':
-    case 'newest':
-      return generateSeekTo(partitions, 'property', 'offsetMax');
-    case 'fromOffset':
-    case 'toOffset':
-      return generateSeekTo(partitions, 'value', offset);
-    case 'sinceTime':
-    case 'untilTime':
-      return generateSeekTo(partitions, 'value', time);
-    default:
-      // case 'oldest';
-      return generateSeekTo(partitions, 'value', '0');
-  }
-};
-
-export const setSeekTo = (
-  searchParams: URLSearchParams,
-  partitions: Partition[]
-) => {
-  const currentSeekTo = searchParams.get('seekTo');
-  const mode = searchParams.get('m') as ConsumingMode;
-  const offset = (searchParams.get('o') as string) || '0';
-  const time =
-    (searchParams.get('t') as string) || new Date().getTime().toString();
-
-  let selectedPartitions: Partition[] = [];
-  // if not `seekTo` property in search params, we set it to all partition
-  if (!currentSeekTo) {
-    selectedPartitions = partitions;
-  } else {
-    const partitionIds = currentSeekTo
-      .split('.')
-      .map((prop) => prop.split('-')[0]);
-
-    selectedPartitions = partitions.filter(({ partition }) =>
-      partitionIds.includes(String(partition))
-    );
-  }
-  searchParams.set(
-    'seekTo',
-    generateSeekToForSelectedPartitions(mode, selectedPartitions, offset, time)
-  );
-
-  return searchParams;
-};

+ 0 - 64
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/Messages.styled.ts

@@ -1,64 +0,0 @@
-import styled, { css } from 'styled-components';
-
-export const Wrapper = styled.div(
-  ({ theme }) => css`
-    display: grid;
-    grid-template-columns: 300px 1fr;
-    justify-items: center;
-    min-height: calc(
-      100vh - ${theme.layout.navBarHeight} - ${theme.pageHeading.height} -
-        ${theme.primaryTab.height}
-    );
-  `
-);
-
-export const Sidebar = styled.div(
-  ({ theme }) => css`
-    width: ${theme.layout.filtersSidebarWidth};
-    position: sticky;
-    top: ${theme.layout.navBarHeight};
-    align-self: start;
-  `
-);
-
-export const SidebarContent = styled.div`
-  padding: 8px 16px 16px;
-`;
-
-export const TableWrapper = styled.div(
-  ({ theme }) => css`
-    width: calc(
-      100vw - ${theme.layout.navBarWidth} - ${theme.layout.filtersSidebarWidth}
-    );
-    border-left: 1px solid ${theme.layout.stuffBorderColor};
-  `
-);
-
-export const Pagination = styled.div`
-  display: grid;
-  grid-template-columns: 1fr 1fr;
-  gap: 8px;
-  position: fixed;
-  bottom: 0;
-  padding: 16px;
-  width: 300px;
-`;
-
-export const StatusBarWrapper = styled.div(
-  ({ theme }) => css`
-    padding: 4px 8px;
-    position: sticky;
-    top: ${theme.layout.navBarHeight};
-    background-color: ${theme.layout.backgroundColor};
-    border-bottom: 1px solid ${theme.layout.stuffBorderColor};
-    white-space: nowrap;
-    display: flex;
-    justify-content: space-between;
-    z-index: 10;
-  `
-);
-
-export const StatusTags = styled.div`
-  display: flex;
-  gap: 4px;
-`;

+ 0 - 112
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/Messages.tsx

@@ -1,112 +0,0 @@
-import React from 'react';
-import { ConsumingMode, useTopicMessages } from 'lib/hooks/api/topicMessages';
-import useAppParams from 'lib/hooks/useAppParams';
-import { RouteParamsClusterTopic } from 'lib/paths';
-import { useNavigate, useSearchParams } from 'react-router-dom';
-import { useTopicDetails } from 'lib/hooks/api/topics';
-import { MESSAGES_PER_PAGE } from 'lib/constants';
-import Search from 'components/common/Search/Search';
-import { Button } from 'components/common/Button/Button';
-import PlusIcon from 'components/common/Icons/PlusIcon';
-import SlidingSidebar from 'components/common/SlidingSidebar';
-import useBoolean from 'lib/hooks/useBoolean';
-
-import MessagesTable from './MessagesTable/MessagesTable';
-import * as S from './Messages.styled';
-import Meta from './FiltersBar/Meta';
-import Form from './FiltersBar/Form';
-import handleNextPageClick from './utils/handleNextPageClick';
-import StatusBar from './StatusBar';
-import AdvancedFilter from './Advanced Filter/AdvancedFilter';
-
-const Messages = () => {
-  const routerProps = useAppParams<RouteParamsClusterTopic>();
-  const [searchParams, setSearchParams] = useSearchParams();
-  const navigate = useNavigate();
-  const {
-    value: isAdvancedFiltersSidebarVisible,
-    setFalse: closeAdvancedFiltersSidebar,
-    setTrue: openAdvancedFiltersSidebar,
-  } = useBoolean();
-  const { messages, meta, phase, isFetching } = useTopicMessages({
-    ...routerProps,
-    searchParams,
-  });
-  const mode = searchParams.get('m') as ConsumingMode;
-  const isTailing = mode === 'live' && isFetching;
-  const { data: topic = { partitions: [] } } = useTopicDetails(routerProps);
-
-  const partitions = topic.partitions || [];
-
-  // Pagination is disabled in live mode, also we don't want to show the button
-  // if we are fetching the messages or if we are at the end of the topic
-  const isPaginationDisabled =
-    isTailing ||
-    ['newest', 'oldest'].includes(mode) || // TODO: remove after BE is fixed
-    isFetching ||
-    !searchParams.get('seekTo');
-
-  const isNextPageButtonDisabled =
-    isPaginationDisabled ||
-    messages.length < Number(searchParams.get('perPage') || MESSAGES_PER_PAGE);
-  const isPrevPageButtonDisabled =
-    isPaginationDisabled || !searchParams.get('page');
-
-  const handleNextPage = () =>
-    handleNextPageClick(messages, searchParams, setSearchParams);
-
-  return (
-    <>
-      <S.Wrapper>
-        <S.Sidebar>
-          <Meta meta={meta} phase={phase} isFetching={isFetching} />
-          <S.SidebarContent>
-            <Search placeholder="Search" />
-            <Form isFetching={isFetching} partitions={partitions} />
-          </S.SidebarContent>
-          <S.Pagination>
-            <Button
-              buttonType="secondary"
-              buttonSize="L"
-              disabled={isPrevPageButtonDisabled}
-              onClick={() => navigate(-1)}
-            >
-              ← Back
-            </Button>
-            <Button
-              buttonType="secondary"
-              buttonSize="L"
-              disabled={isNextPageButtonDisabled}
-              onClick={handleNextPage}
-            >
-              Next →
-            </Button>
-          </S.Pagination>
-        </S.Sidebar>
-        <S.TableWrapper>
-          <S.StatusBarWrapper>
-            <StatusBar />
-            <Button
-              buttonType="primary"
-              buttonSize="S"
-              onClick={openAdvancedFiltersSidebar}
-            >
-              <PlusIcon />
-              Advanced Filter
-            </Button>
-          </S.StatusBarWrapper>
-          <MessagesTable messages={messages} isLive={isTailing} />
-        </S.TableWrapper>
-      </S.Wrapper>
-      <SlidingSidebar
-        title="Advanced filtering"
-        open={isAdvancedFiltersSidebarVisible}
-        onClose={closeAdvancedFiltersSidebar}
-      >
-        <AdvancedFilter />
-      </SlidingSidebar>
-    </>
-  );
-};
-
-export default Messages;

+ 0 - 62
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesContainer.tsx

@@ -1,62 +0,0 @@
-import React, { Suspense } from 'react';
-import { ConsumingMode, useSerdes } from 'lib/hooks/api/topicMessages';
-import useAppParams from 'lib/hooks/useAppParams';
-import { RouteParamsClusterTopic } from 'lib/paths';
-import { useSearchParams } from 'react-router-dom';
-import { useTopicDetails } from 'lib/hooks/api/topics';
-import { MESSAGES_PER_PAGE } from 'lib/constants';
-import { SerdeUsage } from 'generated-sources';
-
-import { setSeekTo } from './FiltersBar/utils';
-import { getDefaultSerdeName } from './utils/getDefaultSerdeName';
-import Messages from './Messages';
-
-const MessagesContainer = () => {
-  const routerProps = useAppParams<RouteParamsClusterTopic>();
-  const [searchParams, setSearchParams] = useSearchParams();
-  const { data: serdes = {} } = useSerdes({
-    ...routerProps,
-    use: SerdeUsage.DESERIALIZE,
-  });
-  const mode = searchParams.get('m') as ConsumingMode;
-  const { data: topic = { partitions: [] } } = useTopicDetails(routerProps);
-  const partitions = topic.partitions || [];
-
-  /**
-   * Search params:
-   * - `q` - search query
-   * - `m` - way the consumer is going to consume the messages..
-   * - `o` - offset
-   * - `t` - timestamp
-   * - `perPage` - number of messages per page
-   * - `seekTo` - offset or timestamp to seek to.
-   *    Format: `0-101.1-987` - [partition 0, offset 101], [partition 1, offset 987]
-   * - `page` - page number
-   */
-  React.useEffect(() => {
-    if (!mode) {
-      searchParams.set('m', 'newest');
-    }
-    if (!searchParams.get('perPage')) {
-      searchParams.set('perPage', MESSAGES_PER_PAGE);
-    }
-    if (!searchParams.get('seekTo')) {
-      setSeekTo(searchParams, partitions);
-    }
-    if (!searchParams.get('keySerde')) {
-      searchParams.set('keySerde', getDefaultSerdeName(serdes.key || []));
-    }
-    if (!searchParams.get('valueSerde')) {
-      searchParams.set('valueSerde', getDefaultSerdeName(serdes.value || []));
-    }
-    setSearchParams(searchParams);
-  }, [topic, serdes]);
-
-  return (
-    <Suspense>
-      <Messages />
-    </Suspense>
-  );
-};
-
-export default MessagesContainer;

+ 0 - 25
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesTable/ActionsCell.tsx

@@ -1,25 +0,0 @@
-import React from 'react';
-import { TopicMessage } from 'generated-sources';
-import { CellContext } from '@tanstack/react-table';
-import { Dropdown, DropdownItem } from 'components/common/Dropdown';
-import useDataSaver from 'lib/hooks/useDataSaver';
-
-const ActionsCell: React.FC<CellContext<TopicMessage, unknown>> = ({ row }) => {
-  const { content } = row.original;
-
-  const { copyToClipboard, saveFile } = useDataSaver(
-    'topic-message',
-    content || ''
-  );
-
-  return (
-    <Dropdown>
-      <DropdownItem onClick={copyToClipboard}>
-        Copy content to clipboard
-      </DropdownItem>
-      <DropdownItem onClick={saveFile}>Save content as a file</DropdownItem>
-    </Dropdown>
-  );
-};
-
-export default ActionsCell;

+ 0 - 55
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesTable/MessageContent/MessageContent.styled.ts

@@ -1,55 +0,0 @@
-import styled, { css } from 'styled-components';
-import * as SEditorViewer from 'components/common/EditorViewer/EditorViewer.styled';
-
-export const Section = styled.div`
-  display: grid;
-  grid-template-columns: 1fr 400px;
-  align-items: stretch;
-`;
-
-export const ContentBox = styled.div`
-  background-color: white;
-  border-right: 1px solid ${({ theme }) => theme.layout.stuffBorderColor};
-  display: flex;
-  flex-direction: column;
-  padding-right: 16px;
-  & nav {
-    padding-bottom: 16px;
-  }
-
-  ${SEditorViewer.Wrapper} {
-    flex-grow: 1;
-  }
-`;
-
-export const MetadataWrapper = styled.div`
-  padding-left: 16px;
-`;
-
-export const Tab = styled.button<{ $active?: boolean }>(
-  ({ theme, $active }) => css`
-    background-color: ${theme.secondaryTab.backgroundColor[
-      $active ? 'active' : 'normal'
-    ]};
-    color: ${theme.secondaryTab.color[$active ? 'active' : 'normal']};
-    padding: 6px 16px;
-    height: 32px;
-    border: 1px solid ${theme.layout.stuffBorderColor};
-    cursor: pointer;
-    &:hover {
-      background-color: ${theme.secondaryTab.backgroundColor.hover};
-      color: ${theme.secondaryTab.color.hover};
-    }
-    &:first-child {
-      border-radius: 4px 0 0 4px;
-    }
-    &:last-child {
-      border-radius: 0 4px 4px 0;
-    }
-    &:not(:last-child) {
-      border-right: 0px;
-    }
-  `
-);
-
-export const Tabs = styled.nav``;

+ 0 - 106
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesTable/MessageContent/MessageContent.tsx

@@ -1,106 +0,0 @@
-import { SchemaType, TopicMessage } from 'generated-sources';
-import React from 'react';
-import EditorViewer from 'components/common/EditorViewer/EditorViewer';
-import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
-import { formatTimestamp } from 'lib/dateTimeHelpers';
-import { Row } from '@tanstack/react-table';
-import {
-  Label,
-  List,
-  SubText,
-} from 'components/common/PropertiesList/PropertiesList.styled';
-
-import * as S from './MessageContent.styled';
-
-type Tab = 'key' | 'content' | 'headers';
-
-const MessageContent: React.FC<{ row: Row<TopicMessage> }> = ({ row }) => {
-  const {
-    content,
-    valueFormat,
-    key,
-    keyFormat,
-    headers,
-    timestamp,
-    timestampType,
-  } = row.original;
-
-  const [activeTab, setActiveTab] = React.useState<Tab>('content');
-  const activeTabContent = () => {
-    switch (activeTab) {
-      case 'content':
-        return content;
-      case 'key':
-        return key;
-      default:
-        return JSON.stringify(headers || {});
-    }
-  };
-
-  const encoder = new TextEncoder();
-  const keySize = encoder.encode(key).length;
-  const contentSize = encoder.encode(content).length;
-  const contentType =
-    content && content.trim().startsWith('{')
-      ? SchemaType.JSON
-      : SchemaType.PROTOBUF;
-  return (
-    <S.Section>
-      <S.ContentBox>
-        <S.Tabs>
-          <S.Tab
-            type="button"
-            $active={activeTab === 'key'}
-            onClick={() => setActiveTab('key')}
-          >
-            Key
-          </S.Tab>
-          <S.Tab
-            $active={activeTab === 'content'}
-            type="button"
-            onClick={() => setActiveTab('content')}
-          >
-            Content
-          </S.Tab>
-          <S.Tab
-            $active={activeTab === 'headers'}
-            type="button"
-            onClick={() => setActiveTab('headers')}
-          >
-            Headers
-          </S.Tab>
-        </S.Tabs>
-        <EditorViewer
-          data={activeTabContent() || ''}
-          maxLines={28}
-          schemaType={contentType}
-        />
-      </S.ContentBox>
-      <S.MetadataWrapper>
-        <List>
-          <Label>Timestamp</Label>
-          <span>
-            {formatTimestamp(timestamp)}
-            <SubText>Timestamp type: {timestampType}</SubText>
-          </span>
-          <Label>Content</Label>
-          <span>
-            {valueFormat}
-            <SubText>
-              Size: <BytesFormatted value={contentSize} />
-            </SubText>
-          </span>
-          <Label>Key</Label>
-          <span>
-            {keyFormat}
-            <SubText>
-              Size: <BytesFormatted value={keySize} />
-            </SubText>
-          </span>
-        </List>
-      </S.MetadataWrapper>
-    </S.Section>
-  );
-};
-
-export default MessageContent;

+ 0 - 41
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/MessagesTable/MessagesTable.tsx

@@ -1,41 +0,0 @@
-import React from 'react';
-import { ColumnDef } from '@tanstack/react-table';
-import Table, { TimestampCell } from 'components/common/NewTable';
-import { TopicMessage } from 'generated-sources';
-import TruncatedTextCell from 'components/common/NewTable/TimestampCell copy';
-
-import MessageContent from './MessageContent/MessageContent';
-import ActionsCell from './ActionsCell';
-
-const MessagesTable: React.FC<{
-  messages: TopicMessage[];
-  isLive: boolean;
-}> = ({ messages, isLive }) => {
-  const columns = React.useMemo<ColumnDef<TopicMessage>[]>(
-    () => [
-      { header: 'Offset', accessorKey: 'offset' },
-      { header: 'Partition', accessorKey: 'partition' },
-      { header: 'Timestamp', accessorKey: 'timestamp', cell: TimestampCell },
-      { header: 'Key', accessorKey: 'key', cell: TruncatedTextCell },
-      { header: 'Content', accessorKey: 'content', cell: TruncatedTextCell },
-      { header: '', id: 'action', cell: ActionsCell },
-    ],
-    []
-  );
-
-  return (
-    <Table
-      columns={columns}
-      data={messages}
-      serverSideProcessing
-      pageCount={1}
-      emptyMessage={isLive ? 'Consuming messages...' : 'No messages to display'}
-      getRowCanExpand={() => true}
-      enableRowSelection={false}
-      enableSorting={false}
-      renderSubComponent={MessageContent}
-    />
-  );
-};
-
-export default MessagesTable;

+ 0 - 39
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/StatusBar.tsx

@@ -1,39 +0,0 @@
-import React from 'react';
-import { useSearchParams } from 'react-router-dom';
-import { Tag } from 'components/common/Tag/Tag.styled';
-import { ConsumingMode } from 'lib/hooks/api/topicMessages';
-
-import { StatusTags } from './Messages.styled';
-import { getModeTitle } from './utils/consumingModes';
-
-const StatusBar = () => {
-  const [searchParams] = useSearchParams();
-
-  const mode = getModeTitle(
-    (searchParams.get('m') as ConsumingMode) || undefined
-  );
-  const offset = searchParams.get('o');
-  const timestamp = searchParams.get('t');
-  const query = searchParams.get('q');
-
-  return (
-    <StatusTags>
-      <Tag color="green">
-        {offset || timestamp ? (
-          <>
-            {mode}: <b>{offset || timestamp}</b>
-          </>
-        ) : (
-          mode
-        )}
-      </Tag>
-      {query && (
-        <Tag color="blue">
-          Search: <b>{query}</b>
-        </Tag>
-      )}
-    </StatusTags>
-  );
-};
-
-export default StatusBar;

+ 0 - 50
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/utils/consumingModes.ts

@@ -1,50 +0,0 @@
-import { ConsumingMode } from 'lib/hooks/api/topicMessages';
-import { SelectOption } from 'components/common/Select/Select';
-
-interface Mode {
-  key: ConsumingMode;
-  title: string;
-}
-
-interface ModeOption extends SelectOption {
-  value: ConsumingMode;
-}
-
-const config: Mode[] = [
-  {
-    key: 'live',
-    title: 'Live mode',
-  },
-  {
-    key: 'newest',
-    title: 'Newest first',
-  },
-  {
-    key: 'oldest',
-    title: 'Oldest first',
-  },
-  {
-    key: 'fromOffset',
-    title: 'From offset',
-  },
-  {
-    key: 'toOffset',
-    title: 'To offset',
-  },
-  {
-    key: 'sinceTime',
-    title: 'Since time',
-  },
-  {
-    key: 'untilTime',
-    title: 'Until time',
-  },
-];
-
-export const getModeOptions = (): ModeOption[] =>
-  config.map(({ key, title }) => ({ value: key, label: title }));
-
-export const getModeTitle = (mode: ConsumingMode = 'newest') => {
-  const modeConfig = config.find((item) => item.key === mode) as Mode;
-  return modeConfig.title;
-};

+ 0 - 65
kafka-ui-react-app/src/components/Topics/Topic/MessagesV2/utils/handleNextPageClick.ts

@@ -1,65 +0,0 @@
-import { TopicMessage } from 'generated-sources';
-import { ConsumingMode } from 'lib/hooks/api/topicMessages';
-
-export default (
-  messages: TopicMessage[],
-  searchParams: URLSearchParams,
-  setSearchParams: (params: URLSearchParams) => void
-) => {
-  const seekTo = searchParams.get('seekTo');
-  const mode = searchParams.get('m') as ConsumingMode;
-  const page = searchParams.get('page');
-  if (!seekTo || !mode) return;
-
-  // parse current seekTo query param to array of [partition, offset] tuples
-  const configTuple = seekTo?.split('.').map((item) => {
-    const [partition, offset] = item.split('-');
-    return { partition: Number(partition), offset: Number(offset) };
-  });
-
-  // Reverse messages array for faster last displayed message search.
-  const reversedMessages = [...messages].reverse();
-
-  if (!configTuple) return;
-
-  const newConfigTuple = configTuple.map(({ partition, offset }) => {
-    const message = reversedMessages.find((m) => partition === m.partition);
-    if (!message) {
-      return { partition, offset };
-    }
-
-    switch (mode) {
-      case 'fromOffset':
-      case 'oldest':
-        // First message in the reversed array is the message with max offset.
-        // Replace offset in seekTo query param with the max offset for
-        // each partition from displayed messages array.
-        return { partition, offset: Math.max(message.offset, offset) };
-      case 'toOffset':
-      case 'newest':
-        // First message in the reversed array is the message with min offset.
-        return { partition, offset: Math.min(message.offset, offset) };
-      case 'sinceTime':
-        // First message in the reversed array is the message with max timestamp.
-        return {
-          partition,
-          offset: Math.max(new Date(message.timestamp).getTime(), offset),
-        };
-      case 'untilTime':
-        // First message in the reversed array is the message with min timestamp.
-        return {
-          partition,
-          offset: Math.min(new Date(message.timestamp).getTime(), offset),
-        };
-      default:
-        return { partition, offset };
-    }
-  });
-  searchParams.set('page', String(Number(page || 0) + 1));
-  searchParams.set(
-    'seekTo',
-    newConfigTuple.map((t) => `${t.partition}-${t.offset}`).join('.')
-  );
-
-  setSearchParams(searchParams);
-};

+ 0 - 3
kafka-ui-react-app/src/components/Topics/Topic/Topic.tsx

@@ -35,8 +35,6 @@ import SlidingSidebar from 'components/common/SlidingSidebar';
 import useBoolean from 'lib/hooks/useBoolean';
 
 import Messages from './Messages/Messages';
-// Messages v2
-import MessagesContainer from './MessagesV2/MessagesContainer';
 import Overview from './Overview/Overview';
 import Settings from './Settings/Settings';
 import TopicConsumerGroups from './ConsumerGroups/TopicConsumerGroups';
@@ -186,7 +184,6 @@ const Topic: React.FC = () => {
             path={clusterTopicMessagesRelativePath}
             element={<Messages />}
           />
-          <Route path="v2" element={<MessagesContainer />} />
           <Route
             path={clusterTopicSettingsRelativePath}
             element={<Settings />}

+ 1 - 1
kafka-ui-react-app/src/lib/hooks/api/topicMessages.tsx

@@ -13,9 +13,9 @@ import {
 } from 'generated-sources';
 import { showServerError } from 'lib/errorHandling';
 import toast from 'react-hot-toast';
-import { StopLoading } from 'components/Topics/Topic/MessagesV2/FiltersBar/FiltersBar.styled';
 import { useQuery } from '@tanstack/react-query';
 import { messagesApiClient } from 'lib/api';
+import { StopLoading } from 'components/Topics/Topic/Messages/Messages.styled';
 
 interface UseTopicMessagesProps {
   clusterName: ClusterName;