Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

teams page redesign #563

Merged
merged 5 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion playwright/e2eTests/teamsOperations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ test("Add team", async ({ page, teamName, teamDescription, teamsPage }) => {
});

test("Edit team description", async ({ page, teamDescription, teamsPage, teamName }) => {
await teamsPage.teamCardKebab.click();
await teamsPage.editTeamButton.click();
await expect(teamsPage.nameInput("Team name")).toHaveValue(teamName);
await expect(teamsPage.teamDescription).toContainText(teamDescription);
Expand Down Expand Up @@ -64,7 +65,8 @@ test("Delete user", async ({ page, userName, teamsPage }) => {
});

test("Delete team", async ({ page, teamName, teamsPage }) => {
await teamsPage.deleteTeamButton(teamName + " changed").click();
await teamsPage.teamCardKebab.click();
await teamsPage.deleteTeamButton.click();
await page.getByRole("button", { name: "Confirm" }).click();
await expect(
page.locator(`:text("${teamName}"):right-of(span[data-tid='Delete team ${teamName}'])`)
Expand Down
3 changes: 1 addition & 2 deletions playwright/e2eTests/triggerOperations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ test("Set trigger maintenance for all intervals", async ({ triggerName, page })

const requestBody = JSON.parse(setMaintenanceRequest.postData() || "{}");
expect(requestBody).not.toBeNull();
expect(requestBody.trigger).toEqual(expectedTriggerTime);

expect(Math.abs(requestBody.trigger - expectedTriggerTime)).toBeLessThanOrEqual(1);
if (maintenance === Maintenance.off) {
await expect(page.getByText("Maintenance")).toBeVisible();
} else
Expand Down
8 changes: 5 additions & 3 deletions playwright/pages/teams.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@ export class TeamsPage {
readonly nameInput: (testId: string) => Locator;
readonly teamDescription: Locator;
readonly previewButton: Locator;
readonly teamCardKebab: Locator;
readonly editTeamButton: Locator;
readonly showUsersButton: Locator;
readonly addUserModalButton: Locator;
readonly deleteUserButton: (userName: string) => Locator;
readonly deleteTeamButton: (teamName: string) => Locator;
readonly deleteTeamButton: Locator;

constructor(page: Page) {
this.page = page;
this.addTeamButton = page.getByText("Add team");
this.nameInput = (testId) => page.locator(`label[data-tid='${testId}'] > span > input`);
this.teamDescription = page.locator("[data-tid='Team description']");
this.previewButton = page.getByText("Preview");
this.editTeamButton = page.getByRole("button", { name: "Edit Team" });
this.teamCardKebab = page.locator("[data-tid='Team card kebab']");
this.editTeamButton = page.getByRole("button", { name: "Edit" });
this.showUsersButton = page.getByText("Show users");
this.addUserModalButton = page.locator("[data-tid='Add user modal']");
this.deleteUserButton = (userName) => page.locator(`[data-tid="Delete user ${userName}"]`);
this.deleteTeamButton = (teamName) => page.locator(`[data-tid="Delete team ${teamName}"]`);
this.deleteTeamButton = page.getByRole("button", { name: "Delete" });
}

async gotoTeamsPage(): Promise<void> {
Expand Down
13 changes: 10 additions & 3 deletions src/Components/ChristmasMoodToggle/ChristmasMoodToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@ import { Toggle } from "@skbkontur/react-ui/components/Toggle";
import { useChristmasMood } from "../../hooks/useChristmasMood";
import { useAppDispatch } from "../../store/hooks";
import { toggleChristmasMood } from "../../store/Reducers/UIReducer.slice";
import { useSelector } from "react-redux";
import { selectIsChristmasMood } from "../../store/Reducers/ConfigReducer.slice";

export const ChristmasMoodToggle: FC = () => {
const dispatch = useAppDispatch();
const [isChristmasMood, setChristmasMood] = useChristmasMood();
const isChristmasMoodEnabled = useSelector(selectIsChristmasMood);

const handleToggleChristmasMood = (selected: boolean) => {
setChristmasMood(selected);
dispatch(toggleChristmasMood(selected));
};
return (
<Toggle checked={isChristmasMood} onValueChange={handleToggleChristmasMood}>
<span style={{ color: "#fff" }}>New Year mood</span>
</Toggle>
<>
{isChristmasMoodEnabled ? (
<Toggle checked={isChristmasMood} onValueChange={handleToggleChristmasMood}>
<span style={{ color: "#fff" }}>New Year mood</span>
</Toggle>
) : null}
</>
);
};
1 change: 0 additions & 1 deletion src/Components/Grid/Grid.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.grid {
display: grid;
align-items: baseline;
}
5 changes: 2 additions & 3 deletions src/Components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import RouterLink from "../RouterLink/RouterLink";
import svgLogo from "./moira-logo.svg";
import { AdminMenu } from "./Components/AdminMenu";
import { useSelector } from "react-redux";
import { selectIsChristmasMood, selectPlatform } from "../../store/Reducers/ConfigReducer.slice";
import { selectPlatform } from "../../store/Reducers/ConfigReducer.slice";
import { useGetConfigQuery } from "../../services/BaseApi";
import { Platform } from "../../Domain/Config";
import { ChristmasHatSVG } from "./Components/ChristmasHat";
Expand All @@ -29,7 +29,6 @@ export default function Header(): React.ReactElement {
const { isLoading } = useGetConfigQuery();
const theme = useTheme();
const { isChristmasMood } = useAppSelector(UIState);
const isChristmasMoodEnabled = useSelector(selectIsChristmasMood);

return (
<header
Expand All @@ -46,7 +45,7 @@ export default function Header(): React.ReactElement {
<img className={cn("logo-img")} src={svgLogo} alt="Moira" />
</Link>
<nav className={cn("menu")}>
{isChristmasMoodEnabled && <ChristmasMoodToggle />}
<ChristmasMoodToggle />
<ThemeSwitchModal />
<AdminMenu />
<RouterLink to={getPageLink("teams")} icon={<PeopleIcon />}>
Expand Down
7 changes: 6 additions & 1 deletion src/Components/Teams/TeamCard/TeamCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ export const TeamCard: FC<ITeamCardProps> = ({ team, isDeleting, onOpenDelete, o
className={cn("team-card")}
>
<Flexbox gap={5}>
<Kebab className={cn("team-card-kebab")} size="large">
<Kebab
data-tid="Team card kebab"
className={cn("team-card-kebab")}
size="large"
>
<MenuItem icon={<EditIcon />} onClick={openModal}>
Edit
</MenuItem>
Expand All @@ -100,6 +104,7 @@ export const TeamCard: FC<ITeamCardProps> = ({ team, isDeleting, onOpenDelete, o
onClick={handleConfirm}
use={"primary"}
width={100}
data-tid={`Delete team ${name}`}
>
Confirm
</Button>
Expand Down
10 changes: 2 additions & 8 deletions src/Components/Teams/Teams.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,15 @@ import { Grid } from "../Grid/Grid";
import { TeamEditor } from "./TeamEditor/TeamEditor";
import { useGetUserTeamsQuery } from "../../services/TeamsApi";
import { useModal } from "../../hooks/useModal";
import { TeamWithUsers } from "../../Containers/TeamWithUsers";
import { TeamsList } from "../TeamsList/TeamsList";

export function Teams(): ReactElement {
const { isModalOpen, openModal, closeModal } = useModal();
const { data: teams } = useGetUserTeamsQuery();

return (
<>
{teams?.map((team) => {
return (
<div key={team.id}>
<TeamWithUsers team={team} />
</div>
);
})}
<TeamsList teams={teams} />
<Grid columns="100px" margin="24px 0">
<Button onClick={openModal}>Add team</Button>
</Grid>
Expand Down
23 changes: 23 additions & 0 deletions src/Components/TeamsList/TeamsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { FC, useState } from "react";
import { TeamCard } from "../../Components/Teams/TeamCard/TeamCard";
import { Grid } from "../../Components/Grid/Grid";
import { EmptyListText } from "../../Components/TriggerInfo/Components/EmptyListMessage/EmptyListText";
import { Team } from "../../Domain/Team";

export const TeamsList: FC<{ teams?: Team[] }> = ({ teams }) => {
const [deletingTeam, setDeletingTeam] = useState<Team | null>(null);
if (!teams?.length) return <EmptyListText text={"There are no teams"} />;
return (
<Grid gap="16px" columns="repeat(auto-fit, minmax(300px, 1fr))">
{teams?.map((team) => (
<TeamCard
key={team.id}
team={team}
isDeleting={deletingTeam?.id === team.id}
onOpenDelete={() => setDeletingTeam(team)}
onCloseDelete={() => setDeletingTeam(null)}
/>
))}
</Grid>
);
};
5 changes: 0 additions & 5 deletions src/Containers/AllTeamsContainer/AllTeamsContainer.less

This file was deleted.

30 changes: 5 additions & 25 deletions src/Containers/AllTeamsContainer/AllTeamsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,15 @@ import { setDocumentTitle } from "../../helpers/setDocumentTitle";
import { useAppDispatch, useAppSelector } from "../../store/hooks";
import { UIState } from "../../store/selectors";
import { useGetAllTeamsQuery } from "../../services/TeamsApi";
import classNames from "classnames/bind";
import { Team } from "../../Domain/Team";
import { Flexbox } from "../../Components/Flexbox/FlexBox";
import { SearchInput } from "../../Components/TriggerInfo/Components/SearchInput/SearchInput";
import { useDebounce } from "../../hooks/useDebounce";
import { Paging } from "@skbkontur/react-ui/components/Paging";
import transformPageFromHumanToProgrammer from "../../logic/transformPageFromHumanToProgrammer";
import { Select } from "@skbkontur/react-ui/components/Select";
import { EmptyListText } from "../../Components/TriggerInfo/Components/EmptyListMessage/EmptyListText";
import { TeamCard } from "../../Components/Teams/TeamCard/TeamCard";
import { setError } from "../../store/Reducers/UIReducer.slice";

import styles from "./AllTeamsContainer.less";

const cn = classNames.bind(styles);
import { TeamsList } from "../../Components/TeamsList/TeamsList";
import { useQueryState } from "../../hooks/useQueryState";

type SortDirection = "asc" | "desc";

Expand All @@ -29,8 +23,7 @@ const SORT_OPTIONS: Array<[SortDirection, string]> = [

const AllTeamsContainer: FC = () => {
const { error, isLoading } = useAppSelector(UIState);
const [deletingTeam, setDeletingTeam] = useState<Team | null>(null);
const [searchValue, setSearchValue] = useState("");
const [searchValue, setSearchValue] = useQueryState<string>("team", "");
const [activePage, setActivePage] = useState(1);
const [sortDirection, setSortDirection] = useState<SortDirection>("asc");
const debouncedSearchMetric = useDebounce(searchValue, 500);
Expand Down Expand Up @@ -75,21 +68,8 @@ const AllTeamsContainer: FC = () => {
items={SORT_OPTIONS}
/>
</Flexbox>
{teams?.list.length ? (
<div className={cn("teams-container")}>
{teams?.list.map((team) => (
<TeamCard
key={team.id}
team={team}
isDeleting={deletingTeam?.id === team.id}
onOpenDelete={() => setDeletingTeam(team)}
onCloseDelete={() => setDeletingTeam(null)}
/>
))}
</div>
) : (
<EmptyListText text={"There are no teams"} />
)}

<TeamsList teams={teams?.list} />

<Paging
shouldBeVisibleWithLessThanTwoPages={false}
Expand Down
2 changes: 1 addition & 1 deletion src/Containers/SettingsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const SettingsContainer: FC<ISettingsContainerProps> = ({ isTeamMember, history
<Flexbox align="baseline" direction="row" gap={4}>
<span>Shown for {team ? "team" : "user"}</span>
{isAdminLink ? (
<RouterLink to={getPageLink("team", team.id)}>
<RouterLink to={`${getPageLink("allTeams")}?team=${team.id}`}>
{team.name}
</RouterLink>
) : (
Expand Down
25 changes: 0 additions & 25 deletions src/Containers/TeamContainer.tsx

This file was deleted.

25 changes: 0 additions & 25 deletions src/Containers/TeamWithUsers.tsx

This file was deleted.

4 changes: 1 addition & 3 deletions src/Containers/TeamsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ const TeamsContainer = () => {
<Layout loading={isLoading} error={error}>
<LayoutContent>
<LayoutTitle>Teams</LayoutTitle>
<LayoutContent>
<Teams />
</LayoutContent>
<Teams />
</LayoutContent>
</Layout>
);
Expand Down
2 changes: 0 additions & 2 deletions src/Domain/Global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export const PagesPaths = {
tags: "/tags",
patterns: "/patterns",
teams: "/teams",
team: "/teams/:teamId?",
contacts: "/contacts",
allTeams: "/teams/all",
};
Expand All @@ -27,7 +26,6 @@ export const PagesLinks = {
tags: "/tags",
patterns: "/patterns",
teams: "/teams",
team: "/teams/%id%",
docs: "//moira.readthedocs.org/",
contacts: "/contacts",
allTeams: "/teams/all",
Expand Down
2 changes: 0 additions & 2 deletions src/desktop.bundle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import Trigger, { TriggerProps } from "./pages/trigger/trigger";
import TriggerDesktop, { TriggerDesktopProps } from "./pages/trigger/trigger.desktop";
import { AdminRoute } from "./PrivateRoutes/AdminRoute";
import TeamsContainer from "./Containers/TeamsContainer";
import { TeamContainer } from "./Containers/TeamContainer";
import { TeamSettingsPrivateRoute } from "./PrivateRoutes/TeamSettingsPrivateRoute";
import AllTeamsContainer from "./Containers/AllTeamsContainer/AllTeamsContainer";
import { ChristmasLights } from "./Components/ChristmasLights/ChristmasLights";
Expand Down Expand Up @@ -80,7 +79,6 @@ function Desktop() {
<Route exact path={getPagePath("settings")} component={SettingsContainer} />
<Route exact path={getPagePath("teams")} component={TeamsContainer} />
<AdminRoute exact path={getPagePath("allTeams")} component={AllTeamsContainer} />
<AdminRoute exact path={getPagePath("team")} component={TeamContainer} />
<AdminRoute
exact
path={getPagePath("notifications")}
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/themes/useThemeFeature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const useThemeFeature = () => {
const resultTheme = isSystemTheme ? browserTheme : localValue;

document.body.dataset.theme = resultTheme;
}, [localValue]);
}, [localValue, isBrowserDarkThemeEnabled]);

return useFeatureFlag<EThemesNames>({ ...ThemeFlag, defaultValue: localValue });
};
4 changes: 2 additions & 2 deletions src/hooks/useChristmasMood.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ export const useChristmasMood = () => {
);

useEffect(() => {
if (localChristmasMood !== moodFromStore) {
if (localChristmasMood !== moodFromStore && isChristmasMoodApiff) {
dispatch(toggleChristmasMood(localChristmasMood));
}
}, [localChristmasMood, moodFromStore]);
}, [localChristmasMood, moodFromStore, isChristmasMoodApiff]);

return [localChristmasMood, setLocalChristmasMood] as const;
};
2 changes: 1 addition & 1 deletion src/hooks/useFeatureFlag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const useFeatureFlag = <T>(
return;
}
window.localStorage.setItem(key, JSON.stringify(value));
}, [value]);
}, [value, shouldPersist]);

return [value, setValue];
};
Loading
Loading