Skip to content

Commit fcb007c

Browse files
Leshe4kaLeshe4kaHaaroleanVladSenyuta
authored
FE: Redesign menu (#227)
Co-authored-by: Leshe4ka <kozyurov.alexey@google.com> Co-authored-by: Roman Zabaluev <gpg@haarolean.dev> Co-authored-by: VladSenyuta <vlad.senyuta@gmail.com>
1 parent 79553e4 commit fcb007c

36 files changed

+653
-507
lines changed

e2e-tests/src/main/java/io/kafbat/ui/screens/panels/NaviSideBar.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
public class NaviSideBar extends BasePage {
1818

1919
protected SelenideElement dashboardMenuItem = $x("//a[@title='Dashboard']");
20-
protected String sideMenuOptionElementLocator = ".//ul/li[contains(.,'%s')]";
20+
protected String sideMenuOptionElementLocator = ".//ul/a[@title='%s']";
2121
protected String clusterElementLocator = "//aside/ul/li[contains(.,'%s')]";
2222

2323
private SelenideElement expandCluster(String clusterName) {
2424
SelenideElement clusterElement = $x(String.format(clusterElementLocator, clusterName)).shouldBe(Condition.visible);
25-
if (clusterElement.parent().$$x(".//ul").size() == 0) {
25+
if (clusterElement.parent().$$x(".//ul").isEmpty()) {
2626
WebUtil.clickByActions(clusterElement);
2727
}
2828
return clusterElement;

e2e-tests/src/main/java/io/kafbat/ui/screens/schemas/SchemaCreateForm.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import static com.codeborne.selenide.Selenide.$;
44
import static com.codeborne.selenide.Selenide.$$x;
55
import static com.codeborne.selenide.Selenide.$x;
6-
import static com.codeborne.selenide.Selenide.sleep;
76
import static org.openqa.selenium.By.id;
87

98
import com.codeborne.selenide.Condition;
@@ -36,6 +35,7 @@ public class SchemaCreateForm extends BasePage {
3635
protected ElementsCollection visibleMarkers =
3736
$$x("//div[@class='ace_scroller']//div[contains(@class,'codeMarker')]");
3837
protected ElementsCollection elementsCompareVersionDdl = $$x("//ul[@role='listbox']/ul/li");
38+
protected String versionDdlElementLocator = "//ul/li[text()='Version %s']";
3939
protected String ddlElementLocator = "//li[@value='%s']";
4040

4141
@Step
@@ -96,14 +96,14 @@ public int getVersionsNumberFromList() {
9696

9797
@Step
9898
public SchemaCreateForm selectVersionFromDropDown(int versionNumberDd) {
99-
$x(String.format(ddlElementLocator, versionNumberDd)).shouldBe(Condition.visible).click();
100-
sleep(1000);
99+
$x(String.format(versionDdlElementLocator, versionNumberDd)).shouldBe(Condition.visible).click();
100+
waitUntilSpinnerDisappear(1);
101101
return this;
102102
}
103103

104104
@Step
105105
public int getMarkedLinesNumber() {
106-
return visibleMarkers.size();
106+
return Math.toIntExact(visibleMarkers.asDynamicIterable().stream().count());
107107
}
108108

109109
@Step

e2e-tests/src/main/java/io/kafbat/ui/screens/topics/TopicCreateEditForm.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.kafbat.ui.screens.topics;
22

3+
import static com.codeborne.selenide.Condition.enabled;
34
import static com.codeborne.selenide.Selenide.$;
45
import static com.codeborne.selenide.Selenide.$$;
56
import static com.codeborne.selenide.Selenide.$x;
@@ -17,6 +18,7 @@
1718
import io.kafbat.ui.screens.topics.enums.TimeToRetain;
1819
import io.kafbat.ui.utilities.WebUtil;
1920
import io.qameta.allure.Step;
21+
import org.openqa.selenium.Keys;
2022

2123
public class TopicCreateEditForm extends BasePage {
2224

@@ -32,7 +34,7 @@ public class TopicCreateEditForm extends BasePage {
3234
protected SelenideElement customParameterDdl = $x("//input[contains(@name, 'customParams')][@role='listitem']");
3335
protected SelenideElement deleteCustomParameterBtn = $x("//span[contains(@title, 'Delete customParam')]");
3436
protected SelenideElement addCustomParameterTypeBtn = $x("//button[contains(text(), 'Add Custom Parameter')]");
35-
protected SelenideElement customParameterValueField = $x("//input[@placeholder='Value']");
37+
protected SelenideElement customParameterValueField = $x("//label[text()='Value *']/..//input");
3638
protected SelenideElement validationCustomParameterValueMsg = $x("//p[contains(text(), 'Value is required')]");
3739
protected String ddlElementLocator = "//li[@value='%s']";
3840
protected String btnTimeToRetainLocator = "//button[@class][text()='%s']";
@@ -116,20 +118,27 @@ public TopicCreateEditForm setCustomParameterType(CustomParameterType customPara
116118

117119
@Step
118120
public TopicCreateEditForm clearCustomParameterValue() {
119-
WebUtil.clearByKeyboard(customParameterValueField);
121+
customParameterValueField.shouldBe(enabled).sendKeys(Keys.END);
122+
String value = customParameterValueField.getValue();
123+
int valueLength = value != null
124+
? value.length()
125+
: 0;
126+
for (int i = 0; i < valueLength; i++) {
127+
customParameterValueField.sendKeys(Keys.BACK_SPACE);
128+
}
120129
return this;
121130
}
122131

123132
@Step
124133
public TopicCreateEditForm setNumberOfPartitions(int partitions) {
125-
partitionsField.shouldBe(Condition.enabled).clear();
134+
partitionsField.shouldBe(enabled).clear();
126135
partitionsField.sendKeys(String.valueOf(partitions));
127136
return this;
128137
}
129138

130139
@Step
131140
public TopicCreateEditForm setTimeToRetainDataByButtons(TimeToRetain timeToRetain) {
132-
$x(String.format(btnTimeToRetainLocator, timeToRetain.getButton())).shouldBe(Condition.enabled).click();
141+
$x(String.format(btnTimeToRetainLocator, timeToRetain.getButton())).shouldBe(enabled).click();
133142
return this;
134143
}
135144

e2e-tests/src/main/java/io/kafbat/ui/utilities/WebUtil.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.kafbat.ui.utilities;
22

3+
import static com.codeborne.selenide.Condition.enabled;
34
import static io.kafbat.ui.variables.Common.LOG_RESULT;
45

56
import com.codeborne.selenide.Condition;
@@ -51,8 +52,13 @@ public static void clickByJavaScript(SelenideElement element) {
5152

5253
public static void clearByKeyboard(SelenideElement field) {
5354
log.debug("\nclearByKeyboard: {{}}", field.getSearchCriteria());
54-
field.shouldBe(Condition.enabled).sendKeys(Keys.END);
55-
field.sendKeys(Keys.chord(Keys.CONTROL + "a"), Keys.DELETE);
55+
field.shouldBe(enabled).sendKeys(Keys.PAGE_DOWN);
56+
Selenide.actions()
57+
.keyDown(Keys.SHIFT)
58+
.sendKeys(Keys.PAGE_UP)
59+
.keyUp(Keys.SHIFT)
60+
.sendKeys(Keys.DELETE)
61+
.perform();
5662
}
5763

5864
public static boolean isVisible(SelenideElement element, int... timeoutInSeconds) {

e2e-tests/src/test/java/io/kafbat/ui/smokesuite/schemas/SchemasTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ public void updateSchemaAvroCheck() {
5757
AVRO_SCHEMA.setValuePath(
5858
System.getProperty("user.dir") + "/src/main/resources/testdata/schemas/schema_avro_update.json");
5959
navigateToSchemaRegistryAndOpenDetails(AVRO_SCHEMA.getName());
60+
int latestVersion = schemaDetails
61+
.getLatestVersion();
6062
schemaDetails
6163
.openEditSchema();
6264
schemaCreateForm
@@ -72,8 +74,10 @@ public void updateSchemaAvroCheck() {
7274
.clickSubmitButton();
7375
schemaDetails
7476
.waitUntilScreenReady();
75-
Assert.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.NONE.toString(),
77+
softly.assertEquals(schemaDetails.getLatestVersion(), latestVersion + 1, "getLatestVersion()");
78+
softly.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.NONE.toString(),
7679
"getCompatibility()");
80+
softly.assertAll();
7781
}
7882

7983
@Test(priority = 3)
@@ -90,7 +94,9 @@ public void compareVersionsCheck() {
9094
.getVersionsNumberFromList();
9195
Assert.assertEquals(versionsNumberFromDdl, latestVersion, "Versions number is not matched");
9296
schemaCreateForm
93-
.selectVersionFromDropDown(latestVersion);
97+
.selectVersionFromDropDown(latestVersion)
98+
.openRightVersionDdl()
99+
.selectVersionFromDropDown(latestVersion - 1);
94100
Assert.assertEquals(schemaCreateForm.getMarkedLinesNumber(), 42, "getMarkedLinesNumber()");
95101
}
96102

frontend/src/components/App.styled.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import styled from 'styled-components';
22

33
export const Layout = styled.div`
4-
min-width: 1200px;
5-
64
@media screen and (max-width: 1023px) {
75
min-width: initial;
86
}

frontend/src/components/Nav/ClusterMenu.tsx

Lines changed: 0 additions & 71 deletions
This file was deleted.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import React, { type FC, useState } from 'react';
2+
import { Cluster, ClusterFeaturesEnum } from 'generated-sources';
3+
import * as S from 'components/Nav/Nav.styled';
4+
import MenuTab from 'components/Nav/Menu/MenuTab';
5+
import MenuItem from 'components/Nav/Menu/MenuItem';
6+
import {
7+
clusterACLPath,
8+
clusterAclRelativePath,
9+
clusterBrokerRelativePath,
10+
clusterBrokersPath,
11+
clusterConnectorsPath,
12+
clusterConnectorsRelativePath,
13+
clusterConsumerGroupsPath,
14+
clusterConsumerGroupsRelativePath,
15+
clusterKsqlDbPath,
16+
clusterKsqlDbRelativePath,
17+
clusterSchemasPath,
18+
clusterSchemasRelativePath,
19+
clusterTopicsPath,
20+
clusterTopicsRelativePath,
21+
} from 'lib/paths';
22+
import { useLocation } from 'react-router-dom';
23+
24+
interface ClusterMenuProps {
25+
name: Cluster['name'];
26+
status: Cluster['status'];
27+
features: Cluster['features'];
28+
singleMode?: boolean;
29+
}
30+
31+
const ClusterMenu: FC<ClusterMenuProps> = ({
32+
name,
33+
status,
34+
features,
35+
singleMode,
36+
}) => {
37+
const hasFeatureConfigured = (key: ClusterFeaturesEnum) =>
38+
features?.includes(key);
39+
const [isOpen, setIsOpen] = useState(!!singleMode);
40+
const location = useLocation();
41+
42+
const getIsMenuItemActive = (path: string) =>
43+
location.pathname.includes(path);
44+
45+
return (
46+
<ul role="menu">
47+
<MenuTab
48+
title={name}
49+
status={status}
50+
isOpen={isOpen}
51+
toggleClusterMenu={() => setIsOpen((prev) => !prev)}
52+
/>
53+
{isOpen && (
54+
<S.List>
55+
<MenuItem
56+
isActive={getIsMenuItemActive(clusterBrokerRelativePath)}
57+
to={clusterBrokersPath(name)}
58+
title="Brokers"
59+
/>
60+
<MenuItem
61+
isActive={getIsMenuItemActive(clusterTopicsRelativePath)}
62+
to={clusterTopicsPath(name)}
63+
title="Topics"
64+
/>
65+
<MenuItem
66+
isActive={getIsMenuItemActive(clusterConsumerGroupsRelativePath)}
67+
to={clusterConsumerGroupsPath(name)}
68+
title="Consumers"
69+
/>
70+
{hasFeatureConfigured(ClusterFeaturesEnum.SCHEMA_REGISTRY) && (
71+
<MenuItem
72+
isActive={getIsMenuItemActive(clusterSchemasRelativePath)}
73+
to={clusterSchemasPath(name)}
74+
title="Schema Registry"
75+
/>
76+
)}
77+
{hasFeatureConfigured(ClusterFeaturesEnum.KAFKA_CONNECT) && (
78+
<MenuItem
79+
isActive={getIsMenuItemActive(clusterConnectorsRelativePath)}
80+
to={clusterConnectorsPath(name)}
81+
title="Kafka Connect"
82+
/>
83+
)}
84+
{hasFeatureConfigured(ClusterFeaturesEnum.KSQL_DB) && (
85+
<MenuItem
86+
isActive={getIsMenuItemActive(clusterKsqlDbRelativePath)}
87+
to={clusterKsqlDbPath(name)}
88+
title="KSQL DB"
89+
/>
90+
)}
91+
{(hasFeatureConfigured(ClusterFeaturesEnum.KAFKA_ACL_VIEW) ||
92+
hasFeatureConfigured(ClusterFeaturesEnum.KAFKA_ACL_EDIT)) && (
93+
<MenuItem
94+
isActive={getIsMenuItemActive(clusterAclRelativePath)}
95+
to={clusterACLPath(name)}
96+
title="ACL"
97+
/>
98+
)}
99+
</S.List>
100+
)}
101+
</ul>
102+
);
103+
};
104+
105+
export default ClusterMenu;

frontend/src/components/Nav/__tests__/ClusterMenu.spec.tsx renamed to frontend/src/components/Nav/ClusterMenu/__tests__/ClusterMenu.spec.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import React from 'react';
22
import { screen } from '@testing-library/react';
33
import { Cluster, ClusterFeaturesEnum } from 'generated-sources';
4-
import ClusterMenu from 'components/Nav/ClusterMenu';
4+
import ClusterMenu from 'components/Nav/ClusterMenu/ClusterMenu';
55
import userEvent from '@testing-library/user-event';
66
import { clusterConnectorsPath } from 'lib/paths';
77
import { render } from 'lib/testHelpers';
88
import { onlineClusterPayload } from 'lib/fixtures/clusters';
99

1010
describe('ClusterMenu', () => {
1111
const setupComponent = (cluster: Cluster, singleMode?: boolean) => (
12-
<ClusterMenu cluster={cluster} singleMode={singleMode} />
12+
<ClusterMenu
13+
name={cluster.name}
14+
status={cluster.status}
15+
features={cluster.features}
16+
singleMode={singleMode}
17+
/>
1318
);
1419
const getMenuItems = () => screen.getAllByRole('menuitem');
1520
const getMenuItem = () => screen.getByRole('menuitem');

frontend/src/components/Nav/ClusterMenuItem.tsx

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)