From d4194dce9c7bc13d97cf860c496cfc4df2079dcf Mon Sep 17 00:00:00 2001 From: svetaStrech Date: Mon, 1 Jan 2024 09:56:26 +0200 Subject: [PATCH] RND-367-ui-minor-changes --- ui_src/src/components/cloneModal/index.js | 7 +- ui_src/src/components/cloneModal/style.scss | 5 + .../src/components/produceMessages/index.js | 22 ++-- .../src/components/runBenchmarkModal/index.js | 120 ++++++++++++++++++ .../components/runBenchmarkModal/style.scss | 85 +++++++++++++ .../components/gitHubIntegration/index.js | 2 +- .../gitHubIntegration/integratedItem.js | 2 + .../integrationItem/integrationLogs.js | 1 - .../components/integrationItem/style.scss | 2 +- .../schema/components/schemaDetails/index.js | 2 +- .../ProduceConsumList/index.js | 48 +++++-- .../components/functionCard/index.js | 18 ++- .../components/functionCard/style.scss | 20 ++- ui_src/src/domain/users/index.js | 21 +-- ui_src/src/domain/users/style.scss | 3 + 15 files changed, 313 insertions(+), 45 deletions(-) create mode 100644 ui_src/src/components/runBenchmarkModal/index.js create mode 100644 ui_src/src/components/runBenchmarkModal/style.scss diff --git a/ui_src/src/components/cloneModal/index.js b/ui_src/src/components/cloneModal/index.js index 6b30b41c4..b3fc018f5 100644 --- a/ui_src/src/components/cloneModal/index.js +++ b/ui_src/src/components/cloneModal/index.js @@ -66,13 +66,18 @@ const CloneModal = ({ type }) => { )} {type === 'cli' && ( <> +

+ Install Memphis CLI +

{githubUrls[type][tabValue]}

-

Create a basic Memphis function template

+

+ Create a basic Memphis function template +

{githubUrls[type]?.code}

diff --git a/ui_src/src/components/cloneModal/style.scss b/ui_src/src/components/cloneModal/style.scss index f11b7f3c8..873f8699a 100644 --- a/ui_src/src/components/cloneModal/style.scss +++ b/ui_src/src/components/cloneModal/style.scss @@ -61,6 +61,11 @@ font-size: 14px; font-family: 'InterMedium'; margin: 15px 0px 5px 0px; + label { + color: var(--purple); + font-weight: 600; + margin-right: 5px; + } } .footer { border-top: 1px solid #e4e4e4; diff --git a/ui_src/src/components/produceMessages/index.js b/ui_src/src/components/produceMessages/index.js index a1dc93130..48fa294bc 100644 --- a/ui_src/src/components/produceMessages/index.js +++ b/ui_src/src/components/produceMessages/index.js @@ -136,7 +136,7 @@ const ProduceMessages = ({ stationName, cancel, produceMessagesRef, setLoading }

JSON-based value

generateMessage()}> - Generate example + Re-generate
@@ -179,8 +179,8 @@ const ProduceMessages = ({ stationName, cancel, produceMessagesRef, setLoading } backgroundColorType="none" borderColorType="gray" height="40px" - onBlur={(e) => creationForm.setFieldsValue({[name]: e.target.value})} - onChange={(e) => creationForm.setFieldsValue({[name]: e.target.value})} + onBlur={(e) => creationForm.setFieldsValue({ [name]: e.target.value })} + onChange={(e) => creationForm.setFieldsValue({ [name]: e.target.value })} value={formFields.key} /> @@ -202,8 +202,8 @@ const ProduceMessages = ({ stationName, cancel, produceMessagesRef, setLoading } backgroundColorType="none" borderColorType="gray" height="40px" - onBlur={(e) => creationForm.setFieldsValue({[name]: e.target.value})} - onChange={(e) => creationForm.setFieldsValue({[name]: e.target.value})} + onBlur={(e) => creationForm.setFieldsValue({ [name]: e.target.value })} + onChange={(e) => creationForm.setFieldsValue({ [name]: e.target.value })} value={formFields.header} /> @@ -223,13 +223,17 @@ const ProduceMessages = ({ stationName, cancel, produceMessagesRef, setLoading }
- creationForm.setFieldsValue({'bypass_schema': e})} checked={isCloud() ? formFields.bypass_schema : true} /> + creationForm.setFieldsValue({ bypass_schema: e })} + checked={isCloud() ? formFields.bypass_schema : true} + />
@@ -248,7 +252,7 @@ const ProduceMessages = ({ stationName, cancel, produceMessagesRef, setLoading } height="45px" width="100%" options={partitons} - onChange={(e) => creationForm.setFieldsValue({'partition_number': e.target.value})} + onChange={(e) => creationForm.setFieldsValue({ partition_number: e.target.value })} popupClassName="select-options" disabled={!isCloud()} /> @@ -262,7 +266,7 @@ const ProduceMessages = ({ stationName, cancel, produceMessagesRef, setLoading } creationForm.setFieldsValue({'amount': e})} + onChange={(e) => creationForm.setFieldsValue({ amount: e })} value={formFields.amount} placeholder={formFields.amount || 1} disabled={!isCloud()} diff --git a/ui_src/src/components/runBenchmarkModal/index.js b/ui_src/src/components/runBenchmarkModal/index.js new file mode 100644 index 000000000..dfb23ac9c --- /dev/null +++ b/ui_src/src/components/runBenchmarkModal/index.js @@ -0,0 +1,120 @@ +// Copyright 2022-2023 The Memphis.dev Authors +// Licensed under the Memphis Business Source License 1.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// Changed License: [Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0), as published by the Apache Foundation. +// +// https://github.com/memphisdev/memphis/blob/master/LICENSE +// +// Additional Use Grant: You may make use of the Licensed Work (i) only as part of your own product or service, provided it is not a message broker or a message queue product or service; and (ii) provided that you do not use, provide, distribute, or make available the Licensed Work as a Service. +// A "Service" is a commercial offering, product, hosted, or managed service, that allows third parties (other than your own employees and contractors acting on your behalf) to access and/or use the Licensed Work or a substantial set of the features or functionality of the Licensed Work to third parties as a software-as-a-service, platform-as-a-service, infrastructure-as-a-service or other similar services that compete with Licensor products or services. + +import './style.scss'; + +import React, { useEffect, useState } from 'react'; +import Modal from '../modal'; +import { IoRocket } from 'react-icons/io5'; +import Copy from '../copy'; +import CustomTabs from '../Tabs'; +import { githubUrls } from '../../const/globalConst'; +import { SiLinux, SiApple, SiWindows11 } from 'react-icons/si'; +import { LOCAL_STORAGE_BROKER_HOST, LOCAL_STORAGE_ENV, LOCAL_STORAGE_ACCOUNT_ID } from '../../const/localStorageConsts'; + +let write = + 'mem bench producer --message-size 128 --count 1000 --concurrency 1 --host --account-id --user --password '; +let read = + 'mem bench consumer --message-size 128 --count 1000 --concurrency 1 --batch-size 50 --host --account-id --user --password '; + +const RunBenchmarkModal = ({ open, clickOutside }) => { + const [tabValue, setTabValue] = useState('Windows'); + const [writeLink, setWriteLink] = useState(null); + const [readLink, setReadLink] = useState(null); + + useEffect(() => { + let host = + localStorage.getItem(LOCAL_STORAGE_ENV) === 'docker' + ? 'localhost' + : localStorage.getItem(LOCAL_STORAGE_BROKER_HOST) + ? localStorage.getItem(LOCAL_STORAGE_BROKER_HOST) + : 'memphis.memphis.svc.cluster.local'; + write = write.replace('', host); + write = write.replace('', parseInt(localStorage.getItem(LOCAL_STORAGE_ACCOUNT_ID))); + read = write.replace('', host); + read = write.replace('', parseInt(localStorage.getItem(LOCAL_STORAGE_ACCOUNT_ID))); + setWriteLink(write); + setReadLink(read); + }, []); + + return ( + +
+ +
+
+
Run a benchmark
+
+
+ } + className={'modal-wrapper'} + width="550px" + clickOutside={clickOutside} + open={open} + displayButtons={true} + rBtnText={'Close'} + rBtnClick={clickOutside} + > +
+ , , , ]} + size={'small'} + tabValue={tabValue} + onChange={(tabValue) => setTabValue(tabValue)} + /> + + <> +

+ Install Memphis CLI +

+
+

{githubUrls['cli'][tabValue]}

+
+ +
+
+

+ For inspecting write latency, run the following +

+
+

{writeLink}

+
+ +
+
+

+ For inspecting read latency, run the following +

+
+

{readLink || read}

+
+ +
+
+ + + +

Considerations to keep in mind:

+

1. The latency and throughput largely depend on the internet connection.

+

+ 2.These figures are preliminary and subject to improvement if necessary. Consult with an engineer for further optimization. +

+
+
+ + ); +}; + +export default RunBenchmarkModal; diff --git a/ui_src/src/components/runBenchmarkModal/style.scss b/ui_src/src/components/runBenchmarkModal/style.scss new file mode 100644 index 000000000..23fe3f77a --- /dev/null +++ b/ui_src/src/components/runBenchmarkModal/style.scss @@ -0,0 +1,85 @@ +.benchmark-wrapper { + width: 100%; + height: 100%; + .title { + color: #101828; + font-family: 'InterSemiBold'; + font-size: 18px; + line-height: 28px; + margin-bottom: 5px; + } + .subtitle { + color: #475467; + font-family: 'Inter'; + font-size: 14px; + line-height: 25px; + margin-bottom: 5px; + p { + margin: 0px; + } + } + .secondary-text { + color: #bcbcbc; + font-family: 'Inter'; + font-size: 12px; + line-height: 20px; + } + .url-wrapper { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding-left: 13px; + height: 40px; + border-radius: 4px; + border: 1px solid #e7e7e7; + margin-bottom: 15px; + .url-text { + margin: 0px; + color: #737373; + font-family: 'InterMedium'; + font-size: 14px; + line-height: 20px; + overflow-x: auto; + white-space: nowrap; + max-width: 430px; + height: 100%; + display: flex; + align-items: center; + } + + .icon { + height: 33px; + width: 37px; + display: flex; + align-items: center; + justify-content: center; + background: #fbfbfb; + border-left: 1px solid #e7e7e7; + border-top-right-radius: inherit; + border-bottom-right-radius: inherit; + cursor: pointer; + } + } + .action { + font-size: 14px; + font-family: 'InterMedium'; + margin: 5px 0px; + label { + color: var(--purple); + font-weight: 600; + margin-right: 5px; + } + } + + .ant-tabs-tab .tabs-name { + font-size: 12px; + } + .ant-tabs-tab + .ant-tabs-tab { + margin: 0 0 0 15px; + } + .ant-tabs-tab { + font-size: 12px; + padding: 8px 0px; + } +} diff --git a/ui_src/src/domain/administration/integrations/components/gitHubIntegration/index.js b/ui_src/src/domain/administration/integrations/components/gitHubIntegration/index.js index 57d2a5f03..9557f4ae3 100644 --- a/ui_src/src/domain/administration/integrations/components/gitHubIntegration/index.js +++ b/ui_src/src/domain/administration/integrations/components/gitHubIntegration/index.js @@ -270,7 +270,7 @@ const GitHubIntegration = ({ close, value }) => {
{isIntegrated && (
-

Repos

+

Repositories

diff --git a/ui_src/src/domain/administration/integrations/components/gitHubIntegration/integratedItem.js b/ui_src/src/domain/administration/integrations/components/gitHubIntegration/integratedItem.js index f5f2caf69..a9f78aa1f 100644 --- a/ui_src/src/domain/administration/integrations/components/gitHubIntegration/integratedItem.js +++ b/ui_src/src/domain/administration/integrations/components/gitHubIntegration/integratedItem.js @@ -84,6 +84,7 @@ const IntegrationItem = ({ isNew, index, disabled, repo, reposList, updateIntegr updateRepo(e); }} options={Object?.keys(reposList)} + placeholder={'Choose a repository'} /> @@ -102,6 +103,7 @@ const IntegrationItem = ({ isNew, index, disabled, repo, reposList, updateIntegr onChange={(e) => { updateBranch(e); }} + placeholder={'Branch to sync with'} /> diff --git a/ui_src/src/domain/administration/integrations/components/integrationItem/integrationLogs.js b/ui_src/src/domain/administration/integrations/components/integrationItem/integrationLogs.js index 08f398215..9de091bfc 100644 --- a/ui_src/src/domain/administration/integrations/components/integrationItem/integrationLogs.js +++ b/ui_src/src/domain/administration/integrations/components/integrationItem/integrationLogs.js @@ -40,7 +40,6 @@ const IntegrationLogs = ({ integrationName }) => { return (
-

Logs Details

diff --git a/ui_src/src/domain/administration/integrations/components/integrationItem/style.scss b/ui_src/src/domain/administration/integrations/components/integrationItem/style.scss index adc1a3756..c4e7a0ae1 100644 --- a/ui_src/src/domain/administration/integrations/components/integrationItem/style.scss +++ b/ui_src/src/domain/administration/integrations/components/integrationItem/style.scss @@ -237,7 +237,7 @@ integ-item { } .logs-header { display: flex; - justify-content: space-between; + justify-content: flex-end; align-items: center; height: 30px; } diff --git a/ui_src/src/domain/schema/components/schemaDetails/index.js b/ui_src/src/domain/schema/components/schemaDetails/index.js index 7632a383d..4f7b0ae21 100644 --- a/ui_src/src/domain/schema/components/schemaDetails/index.js +++ b/ui_src/src/domain/schema/components/schemaDetails/index.js @@ -451,7 +451,7 @@ function SchemaDetails({ schemaName, closeDrawer }) { fontFamily: 'Inter' }} language={schemaDetails?.type === 'protobuf' ? 'proto' : schemaDetails?.type === 'avro' ? 'json' : schemaDetails?.type} - height="calc(100% - 104px)" + height="calc(100% - 55px)" defaultValue={versionSelected?.schema_content} value={newVersion} onChange={(value) => { diff --git a/ui_src/src/domain/stationOverview/stationObservabilty/ProduceConsumList/index.js b/ui_src/src/domain/stationOverview/stationObservabilty/ProduceConsumList/index.js index 65b139678..c1ade54cb 100644 --- a/ui_src/src/domain/stationOverview/stationObservabilty/ProduceConsumList/index.js +++ b/ui_src/src/domain/stationOverview/stationObservabilty/ProduceConsumList/index.js @@ -50,6 +50,8 @@ import { BiLogoGoLang, BiLogoPython } from 'react-icons/bi'; import { SiDotnet } from 'react-icons/si'; import { DiJavascript1 } from 'react-icons/di'; import ConnectorInfo from '../../../../components/connectorInfo'; +import RunBenchmarkModal from '../../../../components/runBenchmarkModal'; +import { connectorTypesSource, connectorTypesSink } from '../../../../connectors'; const overlayStylesConnectors = { borderRadius: '8px', @@ -81,6 +83,7 @@ const ProduceConsumList = ({ producer }) => { const [connectorsSinkList, setConnectorsSinkList] = useState([]); const [cgsList, setCgsList] = useState([]); const [openProduceMessages, setOpenProduceMessages] = useState(false); + const [openRunBenchmark, setOpenRunBenchmark] = useState(false); const [cgDetails, setCgDetails] = useState([]); const [openCreateProducer, setOpenCreateProducer] = useState(false); const [openCreateConsumer, setOpenCreateConsumer] = useState(false); @@ -100,14 +103,14 @@ const ProduceConsumList = ({ producer }) => { const [loading, setLoader] = useState(false); const producerItemsList = [ { - action: 'Produce Synthetic Data', + action: 'Produce synthetic data', onClick: () => { setOpenProduceMessages(true); setOpenProducerPopover(false); } }, { - action: 'Develop a Producer', + action: 'Develop a producer', onClick: () => { setOpenCreateProducer(true); setOpenProducerPopover(false); @@ -121,7 +124,14 @@ const ProduceConsumList = ({ producer }) => { } }, { - action: 'Add a Source', + action: 'Run benchmark', + onClick: () => { + setOpenRunBenchmark(true); + setOpenProducerPopover(false); + } + }, + { + action: 'Add a source', onClick: () => { setOpenConnectorModal(true); setOpenProducerPopover(false); @@ -131,7 +141,7 @@ const ProduceConsumList = ({ producer }) => { const consumeItemsList = [ { - action: 'Develop a Consumer', + action: 'Develop a consumer', onClick: () => { setOpenCreateConsumer(true); setOpenProducerPopover(false); @@ -145,7 +155,14 @@ const ProduceConsumList = ({ producer }) => { } }, { - action: 'Add a Sink', + action: 'Run benchmark', + onClick: () => { + setOpenRunBenchmark(true); + setOpenProducerPopover(false); + } + }, + { + action: 'Add a sink', onClick: () => { setOpenConnectorModal(true); setOpenProducerPopover(false); @@ -384,6 +401,13 @@ const ProduceConsumList = ({ producer }) => { return
{iconComponent}
; } + const getIconByConnector = (item, connectorType) => { + let connector; + if (connectorType === 'source') connector = connectorTypesSource.find((connector) => connector?.name?.toLowerCase() === item?.type); + else connector = connectorTypesSink.find((connector) => connector?.name?.toLowerCase() === item?.type); + return {item?.type} || ; + }; + return (
@@ -393,7 +417,7 @@ const ProduceConsumList = ({ producer }) => {

<> - Sources ({(producersList?.length > 0 && countProducers(producersList).toLocaleString()) || 0} + Producers ({(producersList?.length > 0 && countProducers(producersList).toLocaleString()) || 0} {isCloud() && '/' + stationState?.stationSocketData?.max_amount_of_allowed_producers?.toLocaleString()}) @@ -470,9 +494,7 @@ const ProduceConsumList = ({ producer }) => {

onSelectedRow(index, 'producer')}> {row?.connector_connection_id ? ( - - - + {getIconByConnector(row, 'source')} ) : ( {getIconByLang(row)} )} @@ -570,9 +592,7 @@ const ProduceConsumList = ({ producer }) => {
onSelectedRow(index, 'consumer')}> {row?.connector_connection_id ? ( - - - + {getIconByConnector(row, 'sink')} ) : ( {getIconByLang(row)} )} @@ -744,8 +764,7 @@ const ProduceConsumList = ({ producer }) => {
-

Produce a message

- +

Produce synthetic data

} className={'modal-wrapper produce-modal'} @@ -832,6 +851,7 @@ const ProduceConsumList = ({ producer }) => { setOpenConnectorError(false)} connectorId={selectedConnector?.id} /> setOpenConnectorInfo(false)} connectorId={selectedConnector?.id} /> + setOpenRunBenchmark(false)} />
); }; diff --git a/ui_src/src/domain/stationOverview/stationObservabilty/components/functionCard/index.js b/ui_src/src/domain/stationOverview/stationObservabilty/components/functionCard/index.js index 6bbf82b12..5f3ee925c 100644 --- a/ui_src/src/domain/stationOverview/stationObservabilty/components/functionCard/index.js +++ b/ui_src/src/domain/stationOverview/stationObservabilty/components/functionCard/index.js @@ -42,7 +42,7 @@ export default function FunctionCard({ const [popoverFunctionContextMenu, setPopoverFunctionContextMenu] = useState(false); const [openFunctionDetails, setOpenFunctionDetails] = useState(false); const [selectedFunction, setSelectedFunction] = useState(); - + const [averageProcessingTime, setAverageProcessingTime] = useState(null); useEffect(() => { setIsActive(!isDeactive); }, [isDeactive]); @@ -53,6 +53,7 @@ export default function FunctionCard({ func.rates = Math.floor(Math.random() * (80 - 50 + 1)) + 50; func.forks = Math.floor(Math.random() * (100 - 80 + 1)) + 80; setSelectedFunction(func); + getFunctionDetails(); }, [functionItem]); const functionContextMenuStyles = { @@ -63,6 +64,15 @@ export default function FunctionCard({ width: '150px' }; + const getFunctionDetails = async () => { + try { + const response = await httpRequest('GET', `${ApiEndpoints.GET_FUNCTION_DETAILS}?function_id=${functionItem?.id}`); + setAverageProcessingTime(response?.metrics?.average_processing_time); + } catch (e) { + return; + } + }; + const getFunctionsOverview = async () => { try { const data = await httpRequest( @@ -202,8 +212,10 @@ export default function FunctionCard({
- - {selectedFunction?.name} +
+ {selectedFunction?.name} +
+ avg processing: {averageProcessingTime}/ms
diff --git a/ui_src/src/domain/stationOverview/stationObservabilty/components/functionCard/style.scss b/ui_src/src/domain/stationOverview/stationObservabilty/components/functionCard/style.scss index b8e0b96bf..46477fa1a 100644 --- a/ui_src/src/domain/stationOverview/stationObservabilty/components/functionCard/style.scss +++ b/ui_src/src/domain/stationOverview/stationObservabilty/components/functionCard/style.scss @@ -83,15 +83,27 @@ font-weight: 600; line-height: normal; display: flex; - gap: 6px; - align-items: center; - padding-left: 7px; - span { + flex-direction: column; + + .function-name { + display: flex; + align-items: center; + gap: 6px; width: 95px; + } + span { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } + .processing { + display: flex; + justify-content: center; + text-align: center; + color: #737373 !important; + font-size: 10px; + margin-top: 5px; + } .deactivated { color: #737373 !important; } diff --git a/ui_src/src/domain/users/index.js b/ui_src/src/domain/users/index.js index b294fc40e..935166a2d 100644 --- a/ui_src/src/domain/users/index.js +++ b/ui_src/src/domain/users/index.js @@ -15,9 +15,8 @@ import './style.scss'; import React, { useEffect, useContext, useState, useRef } from 'react'; import { AccountCircleRounded } from '@material-ui/icons'; -import { LOCAL_STORAGE_USER_PASS_BASED_AUTH } from '../../const/localStorageConsts'; +import { LOCAL_STORAGE_USER_PASS_BASED_AUTH, LOCAL_STORAGE_FULL_NAME, USER_IMAGE } from '../../const/localStorageConsts'; import { isCloud, parsingDate } from '../../services/valueConvertor'; -import { ReactComponent as AddUserIcon } from '../../assets/images/addUserIcon.svg'; import { ReactComponent as DeleteWrapperIcon } from '../../assets/images/deleteWrapperIcon.svg'; import { ReactComponent as MailIcon } from '../../assets/images/mailIcon.svg'; import { ReactComponent as DeleteIcon } from '../../assets/images/deleteIcon.svg'; @@ -152,8 +151,10 @@ function Users() { } }; - const getAvatarSrc = (avatarId) => { - return require(`../../assets/images/bots/avatar${avatarId}.svg`); + const getAvatarSrc = (avatarId, full_name) => { + return ( + (localStorage.getItem(LOCAL_STORAGE_FULL_NAME) === full_name && localStorage.getItem(USER_IMAGE)) || require(`../../assets/images/bots/avatar${avatarId}.svg`) + ); }; const handleRemoveUser = async (name, type) => { @@ -303,7 +304,7 @@ function Users() { render: (text, record) => (
- avatar + avatar

{text}

@@ -360,12 +361,12 @@ function Users() { ) }, { - title: 'Creation date', - key: 'created_at', - dataIndex: 'created_at', - render: (created_at) => ( + title: 'Last login', + key: 'last_login', + dataIndex: 'last_login', + render: (last_login) => (
-

{parsingDate(created_at)}

+

{parsingDate(last_login)}

) }, diff --git a/ui_src/src/domain/users/style.scss b/ui_src/src/domain/users/style.scss index 31857516c..cc4a3f6bb 100644 --- a/ui_src/src/domain/users/style.scss +++ b/ui_src/src/domain/users/style.scss @@ -54,6 +54,9 @@ svg { color: var(--purple); } + img { + border-radius: 50%; + } } .badgeOrange { min-width: unset !important;