From 38b573f4246f4575d73580f10ab8b92441990782 Mon Sep 17 00:00:00 2001 From: Oleg Shuralev Date: Sun, 31 Jul 2022 15:48:08 +0300 Subject: [PATCH 1/3] Add an ability to run app from subfolder --- kafka-ui-react-app/.jest/resolver.js | 4 + kafka-ui-react-app/index.html | 21 +++- kafka-ui-react-app/package.json | 4 +- kafka-ui-react-app/pnpm-lock.yaml | 22 +--- .../public/{ => favicon}/favicon.ico | Bin kafka-ui-react-app/public/manifest.json | 12 +- kafka-ui-react-app/src/components/App.tsx | 11 +- .../src/components/Cluster/Cluster.tsx | 24 ++-- .../Connect/Details/Actions/Actions.tsx | 21 ---- .../Connect/List/__tests__/ListPage.spec.tsx | 4 +- .../KsqlDb/Query/QueryForm/QueryForm.tsx | 3 +- .../src/components/Nav/ClusterMenu.tsx | 2 +- .../src/components/Nav/Nav.styled.ts | 5 - .../src/components/Schemas/List/List.tsx | 3 +- .../src/components/Topics/List/List.tsx | 3 +- .../Topics/Topic/Details/Details.styled.ts | 11 -- .../Messages/Filters/Filters.styled.ts | 16 +-- .../Details/Messages/Filters/Filters.tsx | 18 +-- .../Details/Messages/Filters/InfoModal.tsx | 14 +-- .../Details/Messages/Filters/SavedFilters.tsx | 3 +- .../Filters/__tests__/Filters.spec.tsx | 6 +- .../Filters/__tests__/SavedFilters.spec.tsx | 14 ++- .../Topic/Details/Overview/Overview.styled.ts | 16 +++ .../Topic/Details/Overview/Overview.tsx | 16 +-- .../Overview/__test__/Overview.spec.tsx | 9 +- .../shared/Form/CustomParams/CustomParams.tsx | 3 +- .../components/common/Button/Button.styled.ts | 2 +- .../components/common/Icons/ArrowDownIcon.tsx | 15 +++ .../src/components/common/Icons/ClockIcon.tsx | 15 +++ .../components/common/Icons/DeleteIcon.tsx | 20 +++ .../src/components/common/Icons/FileIcon.tsx | 15 +++ .../src/components/common/Icons/PlusIcon.tsx | 17 +++ .../components/common/Icons/SearchIcon.tsx | 10 ++ .../components/common/Icons/SpinnerIcon.tsx | 104 ++++++++++++++++ .../components/common/Input/Input.styled.ts | 30 ++--- .../src/components/common/Input/Input.tsx | 26 +--- .../components/common/Metrics/Indicator.tsx | 13 +- .../src/components/common/Search/Search.tsx | 2 +- .../TableHeaderCell/TableHeaderCell.styled.ts | 1 + .../src/components/global.css.ts | 115 ++++++++++++++++++ kafka-ui-react-app/src/index.tsx | 2 +- kafka-ui-react-app/src/theme/index.scss | 38 +----- kafka-ui-react-app/src/theme/theme.ts | 18 ++- kafka-ui-react-app/vite.config.ts | 24 ++-- 44 files changed, 487 insertions(+), 245 deletions(-) rename kafka-ui-react-app/public/{ => favicon}/favicon.ico (100%) delete mode 100644 kafka-ui-react-app/src/components/Topics/Topic/Details/Details.styled.ts create mode 100644 kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.styled.ts create mode 100644 kafka-ui-react-app/src/components/common/Icons/ArrowDownIcon.tsx create mode 100644 kafka-ui-react-app/src/components/common/Icons/ClockIcon.tsx create mode 100644 kafka-ui-react-app/src/components/common/Icons/DeleteIcon.tsx create mode 100644 kafka-ui-react-app/src/components/common/Icons/FileIcon.tsx create mode 100644 kafka-ui-react-app/src/components/common/Icons/PlusIcon.tsx create mode 100644 kafka-ui-react-app/src/components/common/Icons/SearchIcon.tsx create mode 100644 kafka-ui-react-app/src/components/common/Icons/SpinnerIcon.tsx create mode 100644 kafka-ui-react-app/src/components/global.css.ts diff --git a/kafka-ui-react-app/.jest/resolver.js b/kafka-ui-react-app/.jest/resolver.js index a1165c6e27d..24504e48883 100644 --- a/kafka-ui-react-app/.jest/resolver.js +++ b/kafka-ui-react-app/.jest/resolver.js @@ -16,6 +16,10 @@ module.exports = (path, options) => { delete pkg['exports']; delete pkg['module']; } + if (pkg.name === 'jsonpath-plus') { + delete pkg['exports']; + delete pkg['module']; + } return pkg; }, }); diff --git a/kafka-ui-react-app/index.html b/kafka-ui-react-app/index.html index 4fe0d8df0a5..7b4ed2772aa 100644 --- a/kafka-ui-react-app/index.html +++ b/kafka-ui-react-app/index.html @@ -2,17 +2,28 @@ - - - + + + + + + + + + + + - UI for Apache Kafka +
diff --git a/kafka-ui-react-app/package.json b/kafka-ui-react-app/package.json index 57a10a966d4..1110162a4f0 100644 --- a/kafka-ui-react-app/package.json +++ b/kafka-ui-react-app/package.json @@ -7,7 +7,6 @@ "@babel/core": "^7.16.0", "@babel/plugin-syntax-flow": "^7.18.6", "@babel/plugin-transform-react-jsx": "^7.18.6", - "@fortawesome/fontawesome-free": "^6.1.1", "@hookform/error-message": "^2.0.0", "@hookform/resolvers": "^2.7.1", "@reduxjs/toolkit": "^1.8.3", @@ -20,13 +19,12 @@ "ace-builds": "^1.7.1", "ajv": "^8.6.3", "babel-jest": "^28.1.1", - "bulma": "^0.9.3", "classnames": "^2.2.6", "dayjs": "^1.11.2", "fetch-mock": "^9.11.0", "jest": "^28.1.1", "jest-watch-typeahead": "^2.0.0", - "json-schema-faker": "^0.5.0-rcv.39", + "json-schema-faker": "^0.5.0-rcv.44", "lodash": "^4.17.21", "pretty-ms": "7.0.1", "react": "^18.1.0", diff --git a/kafka-ui-react-app/pnpm-lock.yaml b/kafka-ui-react-app/pnpm-lock.yaml index 3e6471154db..f86fe5f75a1 100644 --- a/kafka-ui-react-app/pnpm-lock.yaml +++ b/kafka-ui-react-app/pnpm-lock.yaml @@ -7,7 +7,6 @@ specifiers: '@babel/preset-env': ^7.18.2 '@babel/preset-react': ^7.17.12 '@babel/preset-typescript': ^7.17.12 - '@fortawesome/fontawesome-free': ^6.1.1 '@hookform/error-message': ^2.0.0 '@hookform/resolvers': ^2.7.1 '@jest/types': ^28.1.1 @@ -36,7 +35,6 @@ specifiers: ace-builds: ^1.7.1 ajv: ^8.6.3 babel-jest: ^28.1.1 - bulma: ^0.9.3 classnames: ^2.2.6 dayjs: ^1.11.2 dotenv: ^16.0.1 @@ -60,7 +58,7 @@ specifiers: jest-sonar-reporter: ^2.0.0 jest-styled-components: ^7.0.8 jest-watch-typeahead: ^2.0.0 - json-schema-faker: ^0.5.0-rcv.39 + json-schema-faker: ^0.5.0-rcv.44 lint-staged: ^13.0.2 lodash: ^4.17.21 prettier: ^2.3.1 @@ -93,7 +91,6 @@ dependencies: '@babel/core': 7.18.2 '@babel/plugin-syntax-flow': 7.18.6_@babel+core@7.18.2 '@babel/plugin-transform-react-jsx': 7.18.6_@babel+core@7.18.2 - '@fortawesome/fontawesome-free': 6.1.1 '@hookform/error-message': 2.0.0_l2dcsysovzdujulgxvsen7vbsm '@hookform/resolvers': 2.8.9_react-hook-form@7.6.9 '@reduxjs/toolkit': 1.8.3_ctm756ikdwcjcvyfxxwskzbr6q @@ -106,13 +103,12 @@ dependencies: ace-builds: 1.7.1 ajv: 8.8.2 babel-jest: 28.1.1_@babel+core@7.18.2 - bulma: 0.9.3 classnames: 2.3.1 dayjs: 1.11.3 fetch-mock: 9.11.0 jest: 28.1.1_yqiaopbgmqcuvx27p5xxvum6wm jest-watch-typeahead: 2.0.0_jest@28.1.1 - json-schema-faker: 0.5.0-rcv.40 + json-schema-faker: 0.5.0-rcv.44 lodash: 4.17.21 pretty-ms: 7.0.1 react: 18.1.0 @@ -1894,12 +1890,6 @@ packages: - supports-color dev: true - /@fortawesome/fontawesome-free/6.1.1: - resolution: {integrity: sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg==} - engines: {node: '>=6'} - requiresBuild: true - dev: false - /@hookform/error-message/2.0.0_l2dcsysovzdujulgxvsen7vbsm: resolution: {integrity: sha512-Y90nHzjgL2MP7GFy75kscdvxrCTjtyxGmOLLxX14nd08OXRIh9lMH/y9Kpdo0p1IPowJBiZMHyueg7p+yrqynQ==} peerDependencies: @@ -3376,10 +3366,6 @@ packages: ieee754: 1.2.1 dev: true - /bulma/0.9.3: - resolution: {integrity: sha512-0d7GNW1PY4ud8TWxdNcP6Cc8Bu7MxcntD/RRLGWuiw/s0a9P+XlH/6QoOIrmbj6o8WWJzJYhytiu9nFjTszk1g==} - dev: false - /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -5860,8 +5846,8 @@ packages: /json-parse-even-better-errors/2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - /json-schema-faker/0.5.0-rcv.40: - resolution: {integrity: sha512-BczZvu03jKrGh3ovCWrHusiX6MwiaKK2WZeyomKBNA8Nm/n7aBYz0mub1CnONB6cgxOZTNxx4afNmLblbUmZbA==} + /json-schema-faker/0.5.0-rcv.44: + resolution: {integrity: sha512-MbDxYFsPXTVMawW1Y6zEU7QhfwsT+ZJ2d+LI8n57Y8+Xw1Cdx1hITgsFTLNOJ1lDMHZqWeXGGgMbc1hW0BGisg==} hasBin: true dependencies: json-schema-ref-parser: 6.1.0 diff --git a/kafka-ui-react-app/public/favicon.ico b/kafka-ui-react-app/public/favicon/favicon.ico similarity index 100% rename from kafka-ui-react-app/public/favicon.ico rename to kafka-ui-react-app/public/favicon/favicon.ico diff --git a/kafka-ui-react-app/public/manifest.json b/kafka-ui-react-app/public/manifest.json index 1f6e4871af1..8ee2a24c12f 100644 --- a/kafka-ui-react-app/public/manifest.json +++ b/kafka-ui-react-app/public/manifest.json @@ -2,18 +2,14 @@ "name": "UI for Apache Kafka", "icons": [ { - "src": "/favicon/icon-192.png", + "src": "/assets/favicon/icon-192.png", "type": "image/png", "sizes": "192x192" }, { - "src": "/favicon/icon-512.png", + "src": "/assets/favicon/icon-512.png", "type": "image/png", "sizes": "512x512" } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} \ No newline at end of file + ] +} diff --git a/kafka-ui-react-app/src/components/App.tsx b/kafka-ui-react-app/src/components/App.tsx index 9de19134eaa..7d28a7bcc3c 100644 --- a/kafka-ui-react-app/src/components/App.tsx +++ b/kafka-ui-react-app/src/components/App.tsx @@ -12,11 +12,11 @@ import theme from 'theme/theme'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { showServerError } from 'lib/errorHandling'; import { Toaster } from 'react-hot-toast'; - -import * as S from './App.styled'; -import Logo from './common/Logo/Logo'; -import GitIcon from './common/Icons/GitIcon'; -import DiscordIcon from './common/Icons/DiscordIcon'; +import GlobalCSS from 'components/global.css'; +import * as S from 'components/App.styled'; +import Logo from 'components/common/Logo/Logo'; +import GitIcon from 'components/common/Icons/GitIcon'; +import DiscordIcon from 'components/common/Icons/DiscordIcon'; const queryClient = new QueryClient({ defaultOptions: { @@ -44,6 +44,7 @@ const App: React.FC = () => { return ( + diff --git a/kafka-ui-react-app/src/components/Cluster/Cluster.tsx b/kafka-ui-react-app/src/components/Cluster/Cluster.tsx index 4ca9fa44cdc..e9758c96b63 100644 --- a/kafka-ui-react-app/src/components/Cluster/Cluster.tsx +++ b/kafka-ui-react-app/src/components/Cluster/Cluster.tsx @@ -19,15 +19,23 @@ import { BreadcrumbRoute } from 'components/common/Breadcrumb/Breadcrumb.route'; import { BreadcrumbProvider } from 'components/common/Breadcrumb/Breadcrumb.provider'; import PageLoader from 'components/common/PageLoader/PageLoader'; import { useClusters } from 'lib/hooks/api/clusters'; +import Brokers from 'components/Brokers/Brokers'; +import Topics from 'components/Topics/Topics'; +import Schemas from 'components/Schemas/Schemas'; +import Connect from 'components/Connect/Connect'; +import KsqlDb from 'components/KsqlDb/KsqlDb'; +import ConsumerGroups from 'components/ConsumerGroups/ConsumerGroups'; -const Brokers = React.lazy(() => import('components/Brokers/Brokers')); -const Topics = React.lazy(() => import('components/Topics/Topics')); -const Schemas = React.lazy(() => import('components/Schemas/Schemas')); -const Connect = React.lazy(() => import('components/Connect/Connect')); -const KsqlDb = React.lazy(() => import('components/KsqlDb/KsqlDb')); -const ConsumerGroups = React.lazy( - () => import('components/ConsumerGroups/ConsumerGroups') -); +// We can't use Lazy loading till we have a better way to update publicPath in runtime +// Now java app replaces paths in builded index.html file. +// const Brokers = React.lazy(() => import('components/Brokers/Brokers')); +// const Topics = React.lazy(() => import('components/Topics/Topics')); +// const Schemas = React.lazy(() => import('components/Schemas/Schemas')); +// const Connect = React.lazy(() => import('components/Connect/Connect')); +// const KsqlDb = React.lazy(() => import('components/KsqlDb/KsqlDb')); +// const ConsumerGroups = React.lazy( +// () => import('components/ConsumerGroups/ConsumerGroups') +// ); const Cluster: React.FC = () => { const { clusterName } = useAppParams(); diff --git a/kafka-ui-react-app/src/components/Connect/Details/Actions/Actions.tsx b/kafka-ui-react-app/src/components/Connect/Details/Actions/Actions.tsx index 3d0c788a905..d672f7985f5 100644 --- a/kafka-ui-react-app/src/components/Connect/Details/Actions/Actions.tsx +++ b/kafka-ui-react-app/src/components/Connect/Details/Actions/Actions.tsx @@ -71,9 +71,6 @@ const Actions: React.FC = () => { onClick={pauseConnectorHandler} disabled={isMutating} > - - - Pause )} @@ -86,9 +83,6 @@ const Actions: React.FC = () => { onClick={resumeConnectorHandler} disabled={isMutating} > - - - Resume )} @@ -100,9 +94,6 @@ const Actions: React.FC = () => { onClick={restartConnectorHandler} disabled={isMutating} > - - - Restart Connector @@ -153,9 +135,6 @@ const Actions: React.FC = () => { onClick={setDeleteConnectorConfirmationOpen} disabled={isMutating} > - - - Delete ({ useConnectors: jest.fn(), })); +jest.mock('components/common/Icons/SpinnerIcon', () => () => 'progressbar'); + const clusterName = 'local'; describe('Connectors List Page', () => { @@ -82,7 +84,7 @@ describe('Connectors List Page', () => { await renderComponent(); const metrics = screen.getByRole('group'); expect(metrics).toBeInTheDocument(); - expect(within(metrics).getAllByRole('progressbar').length).toEqual(3); + expect(within(metrics).getAllByText('progressbar').length).toEqual(3); }); it('renders indicators for empty list of connectors', async () => { diff --git a/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.tsx b/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.tsx index 6edd4b428bb..ee78877d225 100644 --- a/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.tsx +++ b/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.tsx @@ -7,6 +7,7 @@ import IconButtonWrapper from 'components/common/Icons/IconButtonWrapper'; import CloseIcon from 'components/common/Icons/CloseIcon'; import { yupResolver } from '@hookform/resolvers/yup'; import yup from 'lib/yupExtended'; +import PlusIcon from 'components/common/Icons/PlusIcon'; import * as S from './QueryForm.styled'; @@ -165,7 +166,7 @@ const QueryForm: React.FC = ({ buttonType="secondary" onClick={() => append({ key: '', value: '' })} > - + Add Stream Property diff --git a/kafka-ui-react-app/src/components/Nav/ClusterMenu.tsx b/kafka-ui-react-app/src/components/Nav/ClusterMenu.tsx index 95043b99641..dff0e7f3ae9 100644 --- a/kafka-ui-react-app/src/components/Nav/ClusterMenu.tsx +++ b/kafka-ui-react-app/src/components/Nav/ClusterMenu.tsx @@ -27,7 +27,7 @@ const ClusterMenu: React.FC = ({ const [isOpen, setIsOpen] = React.useState(!!singleMode); return ( - +
css` width: 100%; diff --git a/kafka-ui-react-app/src/components/Schemas/List/List.tsx b/kafka-ui-react-app/src/components/Schemas/List/List.tsx index fa2e601838e..f40171a1d48 100644 --- a/kafka-ui-react-app/src/components/Schemas/List/List.tsx +++ b/kafka-ui-react-app/src/components/Schemas/List/List.tsx @@ -20,6 +20,7 @@ import { resetLoaderById } from 'redux/reducers/loader/loaderSlice'; import { ControlPanelWrapper } from 'components/common/ControlPanel/ControlPanel.styled'; import Search from 'components/common/Search/Search'; import useSearch from 'lib/hooks/useSearch'; +import PlusIcon from 'components/common/Icons/PlusIcon'; import ListItem from './ListItem'; import GlobalSchemaSelector from './GlobalSchemaSelector/GlobalSchemaSelector'; @@ -54,7 +55,7 @@ const List: React.FC = () => { buttonType="primary" to={clusterSchemaNewRelativePath} > - Create Schema + Create Schema )} diff --git a/kafka-ui-react-app/src/components/Topics/List/List.tsx b/kafka-ui-react-app/src/components/Topics/List/List.tsx index b83659d4d71..9caeced9283 100644 --- a/kafka-ui-react-app/src/components/Topics/List/List.tsx +++ b/kafka-ui-react-app/src/components/Topics/List/List.tsx @@ -29,6 +29,7 @@ import Switch from 'components/common/Switch/Switch'; import { SmartTable } from 'components/common/SmartTable/SmartTable'; import { TableColumn } from 'components/common/SmartTable/TableColumn'; import { useTableState } from 'lib/hooks/useTableState'; +import PlusIcon from 'components/common/Icons/PlusIcon'; import { MessagesCell, @@ -192,7 +193,7 @@ const List: React.FC = ({ buttonSize="M" to={clusterTopicNewRelativePath} > - Add a Topic + Add a Topic )} diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Details.styled.ts b/kafka-ui-react-app/src/components/Topics/Topic/Details/Details.styled.ts deleted file mode 100644 index 5579f1c7cba..00000000000 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Details.styled.ts +++ /dev/null @@ -1,11 +0,0 @@ -import styled from 'styled-components'; - -export const ReplicaCell = styled.span.attrs({ 'aria-label': 'replica-info' })<{ - leader?: boolean; -}>` - ${this} ~ ${this}::before { - color: black; - content: ', '; - } - color: ${(props) => (props.leader ? 'orange' : null)}; -`; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.styled.ts b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.styled.ts index 296c27b4ecb..2885a32d3a2 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.styled.ts +++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.styled.ts @@ -114,7 +114,7 @@ export const ButtonContainer = styled.div` export const ListItem = styled.li` font-size: 12px; font-weight: 400; - margin-left: 20px; + margin: 4px 0; line-height: 1.5; color: ${({ theme }) => theme.table.td.color.normal}; `; @@ -127,16 +127,6 @@ export const InfoParagraph = styled.div` color: ${({ theme }) => theme.table.td.color.normal}; `; -export const InfoCodeSample = styled.pre` - background: #f5f5f5; - padding: 5px; - border: 1px solid #e1e1e1; - border-radius: 5px; - width: fit-content; - margin: 5px 20px; - color: #cc0f35; -`; - export const MessageFilterModal = styled.div` height: auto; width: 560px; @@ -240,8 +230,9 @@ export const ActiveSmartFilterWrapper = styled.div` `; export const DeleteSavedFilter = styled.div.attrs({ role: 'deleteIcon' })` - color: ${({ theme }) => theme.breadcrumb}; + margin-top: 2px; cursor: pointer; + color: ${({ theme }) => theme.icons.deleteIcon}; `; export const FilterEdit = styled.div` @@ -299,7 +290,6 @@ export const ActiveSmartFilter = styled.div` export const DeleteSavedFilterIcon = styled.div` color: ${({ theme }) => theme.icons.closeIcon}; - border-left: 1px solid ${({ theme }) => theme.savedFilterDivider.color}; display: flex; align-items: center; padding-left: 6px; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx index 5cf9b2af573..c4512078bb0 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx @@ -30,6 +30,11 @@ import { getPartitionsByTopicName } from 'redux/reducers/topics/selectors'; import { useAppSelector } from 'lib/hooks/redux'; import { RouteParamsClusterTopic } from 'lib/paths'; import useAppParams from 'lib/hooks/useAppParams'; +import PlusIcon from 'components/common/Icons/PlusIcon'; +import CloseIcon from 'components/common/Icons/CloseIcon'; +import ClockIcon from 'components/common/Icons/ClockIcon'; +import ArrowDownIcon from 'components/common/Icons/ArrowDownIcon'; +import FileIcon from 'components/common/Icons/FileIcon'; import * as S from './Filters.styled'; import { @@ -474,17 +479,14 @@ const Filters: React.FC = ({ {activeFilter.name && ( {activeFilter.name} - + )} @@ -519,19 +521,19 @@ const Filters: React.FC = ({ - + {Math.max(elapsedMs || 0, 0)} ms - + - + {messagesConsumed} messages consumed diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/InfoModal.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/InfoModal.tsx index b879e7bf0d8..6a505cab634 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/InfoModal.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/InfoModal.tsx @@ -45,19 +45,19 @@ const InfoModal: React.FC = ({ toggleIsOpen }) => { headers["sentAt"] == "2020-01-01" - multiline filters are also allowed: - - - + + multiline filters are also allowed: + +
               def name = value.name
               
def age = value.age
name == "iliax" && age == 30
-
- - +
+
+ diff --git a/kafka-ui-react-app/src/components/common/Button/Button.styled.ts b/kafka-ui-react-app/src/components/common/Button/Button.styled.ts index e21fd744c28..49c1bd303e5 100644 --- a/kafka-ui-react-app/src/components/common/Button/Button.styled.ts +++ b/kafka-ui-react-app/src/components/common/Button/Button.styled.ts @@ -58,7 +58,7 @@ const StyledButton = styled.button` color: ${(props) => props.theme.button.primary.color}; } - & i { + & svg { margin-right: 7px; } `; diff --git a/kafka-ui-react-app/src/components/common/Icons/ArrowDownIcon.tsx b/kafka-ui-react-app/src/components/common/Icons/ArrowDownIcon.tsx new file mode 100644 index 00000000000..a026dd301b8 --- /dev/null +++ b/kafka-ui-react-app/src/components/common/Icons/ArrowDownIcon.tsx @@ -0,0 +1,15 @@ +import React from 'react'; + +const ArrowDownIcon: React.FC = () => ( + + {/* Font Awesome Pro 6.1.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. */} + + +); + +export default ArrowDownIcon; diff --git a/kafka-ui-react-app/src/components/common/Icons/ClockIcon.tsx b/kafka-ui-react-app/src/components/common/Icons/ClockIcon.tsx new file mode 100644 index 00000000000..ee477e8d826 --- /dev/null +++ b/kafka-ui-react-app/src/components/common/Icons/ClockIcon.tsx @@ -0,0 +1,15 @@ +import React from 'react'; + +const ClockIcon: React.FC = () => ( + + {/* Font Awesome Pro 6.1.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. */} + + +); + +export default ClockIcon; diff --git a/kafka-ui-react-app/src/components/common/Icons/DeleteIcon.tsx b/kafka-ui-react-app/src/components/common/Icons/DeleteIcon.tsx new file mode 100644 index 00000000000..73d62b9f6b6 --- /dev/null +++ b/kafka-ui-react-app/src/components/common/Icons/DeleteIcon.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { useTheme } from 'styled-components'; + +const DeleteIcon: React.FC = () => { + const theme = useTheme(); + return ( + + {/* Font Awesome Pro 6.1.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. */} + + + ); +}; + +export default DeleteIcon; diff --git a/kafka-ui-react-app/src/components/common/Icons/FileIcon.tsx b/kafka-ui-react-app/src/components/common/Icons/FileIcon.tsx new file mode 100644 index 00000000000..c50e1002e63 --- /dev/null +++ b/kafka-ui-react-app/src/components/common/Icons/FileIcon.tsx @@ -0,0 +1,15 @@ +import React from 'react'; + +const FileIcon: React.FC = () => ( + + {/* Font Awesome Pro 6.1.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. */} + + +); + +export default FileIcon; diff --git a/kafka-ui-react-app/src/components/common/Icons/PlusIcon.tsx b/kafka-ui-react-app/src/components/common/Icons/PlusIcon.tsx new file mode 100644 index 00000000000..8c7f33a2002 --- /dev/null +++ b/kafka-ui-react-app/src/components/common/Icons/PlusIcon.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +const PlusIcon: React.FC = () => { + return ( + + {/* Font Awesome Pro 6.1.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. */} + + + ); +}; + +export default PlusIcon; diff --git a/kafka-ui-react-app/src/components/common/Icons/SearchIcon.tsx b/kafka-ui-react-app/src/components/common/Icons/SearchIcon.tsx new file mode 100644 index 00000000000..d7bc4ba2855 --- /dev/null +++ b/kafka-ui-react-app/src/components/common/Icons/SearchIcon.tsx @@ -0,0 +1,10 @@ +import React from 'react'; + +const SearchIcon: React.FC = () => ( + + {/* Font Awesome Pro 6.1.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. */} + + +); + +export default SearchIcon; diff --git a/kafka-ui-react-app/src/components/common/Icons/SpinnerIcon.tsx b/kafka-ui-react-app/src/components/common/Icons/SpinnerIcon.tsx new file mode 100644 index 00000000000..0806795ef30 --- /dev/null +++ b/kafka-ui-react-app/src/components/common/Icons/SpinnerIcon.tsx @@ -0,0 +1,104 @@ +import React from 'react'; +import { useTheme } from 'styled-components'; + +const SpinnerIcon: React.FC = () => { + const theme = useTheme(); + return ( + + {/* By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL */} + + + + + + + + + + + + + + ); +}; + +export default SpinnerIcon; + +// { +// /* +// +// */ +// } diff --git a/kafka-ui-react-app/src/components/common/Input/Input.styled.ts b/kafka-ui-react-app/src/components/common/Input/Input.styled.ts index 6d75e55a9ed..b0abef0d797 100644 --- a/kafka-ui-react-app/src/components/common/Input/Input.styled.ts +++ b/kafka-ui-react-app/src/components/common/Input/Input.styled.ts @@ -7,6 +7,18 @@ export interface InputProps { export const Wrapper = styled.div` position: relative; + + svg { + position: absolute; + top: 8px; + line-height: 0; + z-index: 1; + left: 12px; + right: unset; + height: 16px; + width: 16px; + fill: ${({ theme }) => theme.input.icon.color}; + } `; export const Input = styled.input( @@ -55,21 +67,3 @@ export const FormError = styled.p` color: ${({ theme }) => theme.input.error}; font-size: 12px; `; - -interface InputIconProps { - className: string; - position: 'left' | 'right'; - inputSize: 'M' | 'L'; -} - -export const InputIcon = styled.i` - position: absolute; - top: 50%; - line-height: 0; - z-index: 1; - left: ${({ position }) => (position === 'left' ? '12px' : 'unset')}; - right: ${({ position }) => (position === 'right' ? '15px' : 'unset')}; - height: 11px; - width: 11px; - color: ${({ theme }) => theme.input.icon.color}; -`; diff --git a/kafka-ui-react-app/src/components/common/Input/Input.tsx b/kafka-ui-react-app/src/components/common/Input/Input.tsx index fd7951332f0..58a3bb92c85 100644 --- a/kafka-ui-react-app/src/components/common/Input/Input.tsx +++ b/kafka-ui-react-app/src/components/common/Input/Input.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { RegisterOptions, useFormContext } from 'react-hook-form'; +import SearchIcon from 'components/common/Icons/SearchIcon'; import * as S from './Input.styled'; @@ -8,44 +9,29 @@ export interface InputProps Omit { name?: string; hookFormOptions?: RegisterOptions; - leftIcon?: string; - rightIcon?: string; + search?: boolean; } const Input: React.FC = ({ name, hookFormOptions, - leftIcon, - rightIcon, + search, inputSize = 'L', ...rest }) => { const methods = useFormContext(); return ( - {leftIcon && ( - - )} + {search && } {name ? ( ) : ( - - )} - {rightIcon && ( - + )} ); diff --git a/kafka-ui-react-app/src/components/common/Metrics/Indicator.tsx b/kafka-ui-react-app/src/components/common/Metrics/Indicator.tsx index 1ebdeff6c85..be691322d6c 100644 --- a/kafka-ui-react-app/src/components/common/Metrics/Indicator.tsx +++ b/kafka-ui-react-app/src/components/common/Metrics/Indicator.tsx @@ -1,4 +1,5 @@ import React, { PropsWithChildren } from 'react'; +import SpinnerIcon from 'components/common/Icons/SpinnerIcon'; import * as S from './Metrics.styled'; @@ -28,17 +29,7 @@ const Indicator: React.FC> = ({ )} - - {fetching ? ( - - ) : ( - children - )} - + {fetching ? : children} ); diff --git a/kafka-ui-react-app/src/components/common/Search/Search.tsx b/kafka-ui-react-app/src/components/common/Search/Search.tsx index 81f513950d8..78dd758f998 100644 --- a/kafka-ui-react-app/src/components/common/Search/Search.tsx +++ b/kafka-ui-react-app/src/components/common/Search/Search.tsx @@ -26,9 +26,9 @@ const Search: React.FC = ({ placeholder={placeholder} onChange={onChange} defaultValue={value} - leftIcon="fas fa-search" inputSize="M" disabled={disabled} + search /> ); }; diff --git a/kafka-ui-react-app/src/components/common/table/TableHeaderCell/TableHeaderCell.styled.ts b/kafka-ui-react-app/src/components/common/table/TableHeaderCell/TableHeaderCell.styled.ts index 1e35e7d1a57..549da1d067b 100644 --- a/kafka-ui-react-app/src/components/common/table/TableHeaderCell/TableHeaderCell.styled.ts +++ b/kafka-ui-react-app/src/components/common/table/TableHeaderCell/TableHeaderCell.styled.ts @@ -115,4 +115,5 @@ export const TableHeaderCell = styled.th` padding: 4px 0 4px 24px; border-bottom-width: 1px; vertical-align: middle; + text-align: left; `; diff --git a/kafka-ui-react-app/src/components/global.css.ts b/kafka-ui-react-app/src/components/global.css.ts new file mode 100644 index 00000000000..260f4f8a5f2 --- /dev/null +++ b/kafka-ui-react-app/src/components/global.css.ts @@ -0,0 +1,115 @@ +import { createGlobalStyle, css } from 'styled-components'; + +export default createGlobalStyle( + ({ theme }) => css` + html { + font-family: 'Inter', sans-serif; + font-size: 14px; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background-color: ${theme.layout.backgroundColor}; + overflow-x: hidden; + overflow-y: scroll; + text-rendering: optimizeLegibility; + text-size-adjust: 100%; + min-width: 300px; + } + + #root, + body { + width: 100%; + position: relative; + margin: 0; + font-family: 'Inter', sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 20px; + } + + article, + aside, + figure, + footer, + header, + hgroup, + section { + display: block; + } + + body, + button, + input, + optgroup, + select, + textarea { + font-family: inherit; + } + + code, + pre { + font-family: 'Roboto Mono', sans-serif; + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + background-color: ${theme.code.backgroundColor}; + color: ${theme.code.color}; + font-size: 12px; + font-weight: 400; + padding: 2px 8px; + border-radius: 5px; + width: fit-content; + } + + pre { + overflow-x: auto; + white-space: pre + word-wrap: normal + + code { + background-color: transparent; + color: currentColor + padding: 0 + } + } + + a { + color: ${theme.link.color}; + cursor: pointer; + text-decoration: none; + &:hover { + color: ${theme.link.hoverColor}; + } + } + + img { + height: auto; + max-width: 100%; + } + + input[type='checkbox'], + input[type='radio'] { + vertical-align: baseline; + } + + hr { + background-color: ${theme.hr.backgroundColor}; + border: none; + display: block; + height: 1px; + margin: 0; + } + + fieldset { + border: none; + } + + + @keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + ` +); diff --git a/kafka-ui-react-app/src/index.tsx b/kafka-ui-react-app/src/index.tsx index b6a20cba2fb..d15e0528ca5 100644 --- a/kafka-ui-react-app/src/index.tsx +++ b/kafka-ui-react-app/src/index.tsx @@ -4,8 +4,8 @@ import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; import App from 'components/App'; import { store } from 'redux/store'; -import 'theme/index.scss'; import 'lib/constants'; +import 'theme/index.scss'; const container = document.getElementById('root') || document.createElement('div'); diff --git a/kafka-ui-react-app/src/theme/index.scss b/kafka-ui-react-app/src/theme/index.scss index 84d54b9bdd2..d57d3a4d12e 100644 --- a/kafka-ui-react-app/src/theme/index.scss +++ b/kafka-ui-react-app/src/theme/index.scss @@ -1,37 +1 @@ -@import '@fortawesome/fontawesome-free/css/all.min.css'; - -// Base -@import "./minireset"; -@import "bulma/sass/base/generic"; - -@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap'); - -#root, -body, -html { - width: 100%; - position: relative; - margin: 0; - font-family: 'Inter', sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background-color: #fff; -} - -input, select, textarea, button { - font-family: inherit; -} - -code { - font-family: 'Roboto Mono', sans-serif; -} - -@keyframes fadein { - from { - opacity: 0; - } - to { - opacity: 1; - } -} +@import "./minireset.css"; diff --git a/kafka-ui-react-app/src/theme/theme.ts b/kafka-ui-react-app/src/theme/theme.ts index 363bafa9228..9be09d77be9 100644 --- a/kafka-ui-react-app/src/theme/theme.ts +++ b/kafka-ui-react-app/src/theme/theme.ts @@ -60,10 +60,22 @@ const Colors = { }; const theme = { + link: { + color: Colors.brand[50], + hoverColor: Colors.brand[60], + }, + hr: { + backgroundColor: Colors.neutral[5], + }, + code: { + backgroundColor: Colors.neutral[5], + color: Colors.red[55], + }, layout: { + backgroundColor: Colors.neutral[0], minWidth: '1200px', navBarWidth: '201px', - navBarHeight: '3.25rem', + navBarHeight: '53px', stuffColor: Colors.neutral[5], stuffBorderColor: Colors.neutral[10], overlay: { @@ -477,6 +489,9 @@ const theme = { value: Colors.neutral[80], meta: Colors.neutral[30], }, + liderReplica: { + color: Colors.green[60], + }, }, dangerZone: { borderColor: Colors.neutral[10], @@ -498,6 +513,7 @@ const theme = { }, icons: { closeIcon: Colors.neutral[30], + deleteIcon: Colors.red[20], warningIcon: Colors.yellow[20], messageToggleIcon: { normal: Colors.brand[50], diff --git a/kafka-ui-react-app/vite.config.ts b/kafka-ui-react-app/vite.config.ts index 6570b334a4e..e8d3ac6d4e6 100644 --- a/kafka-ui-react-app/vite.config.ts +++ b/kafka-ui-react-app/vite.config.ts @@ -1,4 +1,9 @@ -import { defineConfig, loadEnv, UserConfigExport } from 'vite'; +import { + defineConfig, + loadEnv, + UserConfigExport, + splitVendorChunkPlugin, +} from 'vite'; import react from '@vitejs/plugin-react'; import tsconfigPaths from 'vite-tsconfig-paths'; @@ -6,27 +11,12 @@ export default defineConfig(({ mode }) => { process.env = { ...process.env, ...loadEnv(mode, process.cwd()) }; const defaultConfig: UserConfigExport = { - plugins: [react(), tsconfigPaths()], + plugins: [react(), tsconfigPaths(), splitVendorChunkPlugin()], server: { port: 3000, }, build: { outDir: 'build', - rollupOptions: { - output: { - manualChunks: { - vendor: [ - 'react', - 'react-router-dom', - 'react-dom', - 'redux', - 'react-redux', - 'styled-components', - 'react-ace', - ], - }, - }, - }, }, define: { 'process.env.NODE_ENV': `"${mode}"`, From c004305e971e9ebc6e194c66c0bc76d56bc24a20 Mon Sep 17 00:00:00 2001 From: Oleg Shuralev Date: Mon, 1 Aug 2022 17:30:14 +0300 Subject: [PATCH 2/3] linting --- .../components/common/Icons/SpinnerIcon.tsx | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/kafka-ui-react-app/src/components/common/Icons/SpinnerIcon.tsx b/kafka-ui-react-app/src/components/common/Icons/SpinnerIcon.tsx index 0806795ef30..38ab1daa0c2 100644 --- a/kafka-ui-react-app/src/components/common/Icons/SpinnerIcon.tsx +++ b/kafka-ui-react-app/src/components/common/Icons/SpinnerIcon.tsx @@ -83,22 +83,3 @@ const SpinnerIcon: React.FC = () => { }; export default SpinnerIcon; - -// { -// /* -// -// */ -// } From 0bf5d4750f07d894ae96271fe248f71c7e1e97a5 Mon Sep 17 00:00:00 2001 From: Roman Zabaluev Date: Mon, 1 Aug 2022 19:07:34 +0400 Subject: [PATCH 3/3] Fix all the static resources URLs and manifest.json --- .../kafka/ui/controller/StaticController.java | 33 ++++++++++++------- kafka-ui-react-app/public/manifest.json | 4 +-- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/StaticController.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/StaticController.java index c2d6a10b366..696f47073b7 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/StaticController.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/StaticController.java @@ -20,21 +20,30 @@ public class StaticController { @Value("classpath:static/index.html") private Resource indexFile; + @Value("classpath:static/manifest.json") + private Resource manifestFile; + private final AtomicReference renderedIndexFile = new AtomicReference<>(); + private final AtomicReference renderedManifestFile = new AtomicReference<>(); @GetMapping(value = "/index.html", produces = {"text/html"}) public Mono> getIndex(ServerWebExchange exchange) { - return Mono.just(ResponseEntity.ok(getRenderedIndexFile(exchange))); + return Mono.just(ResponseEntity.ok(getRenderedFile(exchange, renderedIndexFile, indexFile))); + } + + @GetMapping(value = "/manifest.json", produces = {"application/json"}) + public Mono> getManifest(ServerWebExchange exchange) { + return Mono.just(ResponseEntity.ok(getRenderedFile(exchange, renderedManifestFile, manifestFile))); } - public String getRenderedIndexFile(ServerWebExchange exchange) { - String rendered = renderedIndexFile.get(); + public String getRenderedFile(ServerWebExchange exchange, AtomicReference renderedFile, Resource file) { + String rendered = renderedFile.get(); if (rendered == null) { - rendered = buildIndexFile(exchange.getRequest().getPath().contextPath().value()); - if (renderedIndexFile.compareAndSet(null, rendered)) { + rendered = buildFile(file, exchange.getRequest().getPath().contextPath().value()); + if (renderedFile.compareAndSet(null, rendered)) { return rendered; } else { - return renderedIndexFile.get(); + return renderedFile.get(); } } else { return rendered; @@ -42,11 +51,11 @@ public String getRenderedIndexFile(ServerWebExchange exchange) { } @SneakyThrows - private String buildIndexFile(String contextPath) { - final String staticPath = contextPath + "/static"; - return ResourceUtil.readAsString(indexFile) - .replace("href=\"./static", "href=\"" + staticPath) - .replace("src=\"./static", "src=\"" + staticPath) - .replace("window.basePath=\"\"", "window.basePath=\"" + contextPath + "\""); + private String buildFile(Resource file, String contextPath) { + return ResourceUtil.readAsString(file) + .replace("\"/assets/", "\"" + contextPath + "/assets/") + .replace("\"/favicon/", "\"" + contextPath + "/favicon/") + .replace("/manifest.json", contextPath + "/manifest.json") + .replace("window.basePath = ''", "window.basePath=\"" + contextPath + "\""); } } diff --git a/kafka-ui-react-app/public/manifest.json b/kafka-ui-react-app/public/manifest.json index 8ee2a24c12f..fd521d3d839 100644 --- a/kafka-ui-react-app/public/manifest.json +++ b/kafka-ui-react-app/public/manifest.json @@ -2,12 +2,12 @@ "name": "UI for Apache Kafka", "icons": [ { - "src": "/assets/favicon/icon-192.png", + "src": "/favicon/icon-192.png", "type": "image/png", "sizes": "192x192" }, { - "src": "/assets/favicon/icon-512.png", + "src": "/favicon/icon-512.png", "type": "image/png", "sizes": "512x512" }