mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Show all teams for global users and save team selection between pages (#3204)
This commit is contained in:
parent
b3a69680e7
commit
78d5e13a97
6 changed files with 134 additions and 94 deletions
1
changes/issue-3193-show-all-teams
Normal file
1
changes/issue-3193-show-all-teams
Normal file
|
|
@ -0,0 +1 @@
|
|||
* Ensure show all teams is displayed to global users and save team selection between pages
|
||||
|
|
@ -102,6 +102,9 @@ describe("Teams flow", () => {
|
|||
cy.visit("/schedule/manage");
|
||||
|
||||
cy.wait(2000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
||||
cy.get(".component__team-dropdown").click();
|
||||
|
||||
cy.findByText(/valor/i).should("exist");
|
||||
cy.findByText(/query all window crashes/i).should("exist");
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import hostSummaryAPI from "services/entities/host_summary";
|
|||
import teamsAPI from "services/entities/teams";
|
||||
import { IHostSummary, IHostSummaryPlatforms } from "interfaces/host_summary";
|
||||
import { ITeam } from "interfaces/team";
|
||||
import { getSortedTeamOptions } from "fleet/helpers";
|
||||
import sortUtils from "utilities/sort";
|
||||
|
||||
import TeamsDropdown from "components/TeamsDropdown";
|
||||
|
|
@ -38,6 +37,7 @@ const Homepage = (): JSX.Element => {
|
|||
config,
|
||||
currentTeam,
|
||||
isPremiumTier,
|
||||
isFreeTier,
|
||||
isPreviewMode,
|
||||
isOnGlobalTeam,
|
||||
setCurrentTeam,
|
||||
|
|
@ -53,24 +53,20 @@ const Homepage = (): JSX.Element => {
|
|||
const [offlineCount, setOfflineCount] = useState<string | undefined>();
|
||||
const [newCount, setNewCount] = useState<string | undefined>();
|
||||
|
||||
const { data: teams, isLoading: isLoadingTeams } = useQuery<
|
||||
ITeamsResponse,
|
||||
Error,
|
||||
ITeam[]
|
||||
>(["teams"], () => teamsAPI.loadAll(), {
|
||||
enabled: !!isPremiumTier,
|
||||
select: (data: ITeamsResponse) =>
|
||||
data.teams.sort((a, b) => sortUtils.caseInsensitiveAsc(a.name, b.name)),
|
||||
onSuccess: (responseTeams) => {
|
||||
if (!isOnGlobalTeam) {
|
||||
const sortedTeams = getSortedTeamOptions(responseTeams);
|
||||
const firstTeamOption = responseTeams.find(
|
||||
(responseTeam) => responseTeam.id === sortedTeams[0].value
|
||||
);
|
||||
setCurrentTeam(firstTeamOption);
|
||||
}
|
||||
},
|
||||
});
|
||||
const { data: teams } = useQuery<ITeamsResponse, Error, ITeam[]>(
|
||||
["teams"],
|
||||
() => teamsAPI.loadAll(),
|
||||
{
|
||||
enabled: !!isPremiumTier,
|
||||
select: (data: ITeamsResponse) =>
|
||||
data.teams.sort((a, b) => sortUtils.caseInsensitiveAsc(a.name, b.name)),
|
||||
onSuccess: (responseTeams) => {
|
||||
if (!currentTeam && !isOnGlobalTeam && responseTeams.length) {
|
||||
setCurrentTeam(responseTeams[0]);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const handleTeamSelect = (teamId: number) => {
|
||||
const selectedTeam = find(teams, ["id", teamId]);
|
||||
|
|
@ -108,19 +104,22 @@ const Homepage = (): JSX.Element => {
|
|||
<div className={`${baseClass}__header`}>
|
||||
<div className={`${baseClass}__text`}>
|
||||
<div className={`${baseClass}__title`}>
|
||||
{isPremiumTier && teams && teams.length > 1 && (
|
||||
<TeamsDropdown
|
||||
selectedTeamId={currentTeam?.id || 0}
|
||||
currentUserTeams={teams || []}
|
||||
onChange={(newSelectedValue: number) =>
|
||||
handleTeamSelect(newSelectedValue)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isPremiumTier && teams && teams.length === 1 && (
|
||||
<h1>{teams[0].name}</h1>
|
||||
)}
|
||||
{!isPremiumTier && <h1>{config?.org_name}</h1>}
|
||||
{isFreeTier && <h1>{config?.org_name}</h1>}
|
||||
{isPremiumTier &&
|
||||
teams &&
|
||||
(teams.length > 1 || isOnGlobalTeam) && (
|
||||
<TeamsDropdown
|
||||
selectedTeamId={currentTeam?.id || 0}
|
||||
currentUserTeams={teams || []}
|
||||
onChange={(newSelectedValue: number) =>
|
||||
handleTeamSelect(newSelectedValue)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isPremiumTier &&
|
||||
!isOnGlobalTeam &&
|
||||
teams &&
|
||||
teams.length === 1 && <h1>{teams[0].name}</h1>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ const ManageHostsPage = ({
|
|||
router,
|
||||
params: routeParams,
|
||||
location,
|
||||
}: IManageHostsProps) => {
|
||||
}: IManageHostsProps): JSX.Element => {
|
||||
const dispatch = useDispatch();
|
||||
const queryParams = location.query;
|
||||
const {
|
||||
|
|
@ -137,6 +137,7 @@ const ManageHostsPage = ({
|
|||
isOnGlobalTeam,
|
||||
isOnlyObserver,
|
||||
isPremiumTier,
|
||||
isFreeTier,
|
||||
currentTeam,
|
||||
setCurrentTeam,
|
||||
} = useContext(AppContext);
|
||||
|
|
@ -316,7 +317,7 @@ const ManageHostsPage = ({
|
|||
select: (data: ITeamsResponse) =>
|
||||
data.teams.sort((a, b) => sortUtils.caseInsensitiveAsc(a.name, b.name)),
|
||||
onSuccess: (responseTeams: ITeam[]) => {
|
||||
if (responseTeams.length === 1) {
|
||||
if (!currentTeam && !isOnGlobalTeam && responseTeams.length) {
|
||||
setCurrentTeam(responseTeams[0]);
|
||||
}
|
||||
},
|
||||
|
|
@ -460,7 +461,9 @@ const ManageHostsPage = ({
|
|||
// set the team object in context
|
||||
const teamId = parseInt(queryParams?.team_id, 10) || 0;
|
||||
const selectedTeam = find(teams, ["id", teamId]);
|
||||
setCurrentTeam(selectedTeam);
|
||||
if (selectedTeam) {
|
||||
setCurrentTeam(selectedTeam);
|
||||
}
|
||||
setShowNoEnrollSecretBanner(true);
|
||||
|
||||
// set selected label
|
||||
|
|
@ -495,7 +498,9 @@ const ManageHostsPage = ({
|
|||
// set the team object in context
|
||||
const teamId = parseInt(queryParams?.team_id, 10) || 0;
|
||||
const selectedTeam = find(teams, ["id", teamId]);
|
||||
setCurrentTeam(selectedTeam);
|
||||
if (selectedTeam) {
|
||||
setCurrentTeam(selectedTeam);
|
||||
}
|
||||
setShowNoEnrollSecretBanner(true);
|
||||
|
||||
// set selected label
|
||||
|
|
@ -620,12 +625,11 @@ const ManageHostsPage = ({
|
|||
setSoftwareDetails(null);
|
||||
};
|
||||
|
||||
// The handleChange method below is for the filter-by-team dropdown rather than the dropdown used in modals
|
||||
const handleChangeSelectedTeamFilter = (selectedTeam: number) => {
|
||||
const handleTeamSelect = (teamId: number) => {
|
||||
const { MANAGE_HOSTS } = PATHS;
|
||||
const teamIdParam = getValidatedTeamId(
|
||||
teams || [],
|
||||
selectedTeam,
|
||||
teamId,
|
||||
currentUser,
|
||||
isOnGlobalTeam as boolean
|
||||
);
|
||||
|
|
@ -647,6 +651,8 @@ const ManageHostsPage = ({
|
|||
queryParams: newQueryParams,
|
||||
});
|
||||
router.replace(nextLocation);
|
||||
const selectedTeam = find(teams, ["id", teamId]);
|
||||
setCurrentTeam(selectedTeam);
|
||||
};
|
||||
|
||||
const handleStatusDropdownChange = (statusName: string) => {
|
||||
|
|
@ -1078,7 +1084,7 @@ const ManageHostsPage = ({
|
|||
(policyId && policy?.team_id) || (currentTeam?.id as number)
|
||||
}
|
||||
onChange={(newSelectedValue: number) =>
|
||||
handleChangeSelectedTeamFilter(newSelectedValue)
|
||||
handleTeamSelect(newSelectedValue)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
@ -1340,14 +1346,15 @@ const ManageHostsPage = ({
|
|||
<div className={`${baseClass}__header`}>
|
||||
<div className={`${baseClass}__text`}>
|
||||
<div className={`${baseClass}__title`}>
|
||||
{!isPremiumTier && <h1>Hosts</h1>}
|
||||
{isFreeTier && <h1>Hosts</h1>}
|
||||
{isPremiumTier &&
|
||||
teams &&
|
||||
teams.length > 1 &&
|
||||
(teams.length > 1 || isOnGlobalTeam) &&
|
||||
renderTeamsFilterDropdown()}
|
||||
{isPremiumTier && teams && teams.length === 1 && (
|
||||
<h1>{teams[0].name}</h1>
|
||||
)}
|
||||
{isPremiumTier &&
|
||||
!isOnGlobalTeam &&
|
||||
teams &&
|
||||
teams.length === 1 && <h1>{teams[0].name}</h1>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useCallback, useContext, useEffect, useState } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { noop } from "lodash";
|
||||
import { find, noop } from "lodash";
|
||||
|
||||
// @ts-ignore
|
||||
import { renderFlash } from "redux/nodes/notifications/actions";
|
||||
|
|
@ -67,6 +67,8 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
|||
isOnGlobalTeam,
|
||||
isFreeTier,
|
||||
isPremiumTier,
|
||||
currentTeam,
|
||||
setCurrentTeam,
|
||||
} = useContext(AppContext);
|
||||
|
||||
const {
|
||||
|
|
@ -181,6 +183,8 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
|||
setShowInheritedPolicies(false);
|
||||
setSelectedPolicyIds([]);
|
||||
setPolicyTeamId(id);
|
||||
const selectedTeam = find(teams, ["id", id]);
|
||||
setCurrentTeam(selectedTeam);
|
||||
};
|
||||
|
||||
const toggleAddPolicyModal = () => setShowAddPolicyModal(!showAddPolicyModal);
|
||||
|
|
@ -266,7 +270,7 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
|||
if (userTeams && !userTeams.find((t) => t.id === teamId)) {
|
||||
if (isOnGlobalTeam) {
|
||||
// For global users, default to zero (i.e. all teams).
|
||||
if (teamId === undefined) {
|
||||
if (teamId === undefined && !currentTeam) {
|
||||
handleTeamSelect(0);
|
||||
return;
|
||||
}
|
||||
|
|
@ -275,7 +279,7 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
|||
// If there is no default team, set teamId to null so that getPolicies
|
||||
// API request will not be triggered.
|
||||
teamId = userTeams[0]?.id || null;
|
||||
if (teamId) {
|
||||
if (!currentTeam && teamId) {
|
||||
handleTeamSelect(teamId);
|
||||
return;
|
||||
}
|
||||
|
|
@ -284,7 +288,11 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
|||
// Null case must be distinguished from 0 (which is used as the id for the "All teams" option)
|
||||
// so a falsiness check cannot be used here. Null case here allows us to skip API call
|
||||
// that would be triggered on a change to selectedTeamId.
|
||||
teamId !== null && setSelectedTeamId(teamId);
|
||||
if (currentTeam) {
|
||||
setSelectedTeamId(currentTeam.id);
|
||||
} else {
|
||||
teamId !== null && setSelectedTeamId(teamId);
|
||||
}
|
||||
}, [isOnGlobalTeam, location, userTeams]);
|
||||
|
||||
// Watch for selected team changes and call getPolicies to make new policies API request.
|
||||
|
|
@ -348,8 +356,7 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
|||
{isFreeTier && <h1>Policies</h1>}
|
||||
{isPremiumTier &&
|
||||
userTeams &&
|
||||
userTeams.length > 1 &&
|
||||
selectedTeamId >= 0 && (
|
||||
(userTeams.length > 1 || isOnGlobalTeam) && (
|
||||
<TeamsDropdown
|
||||
selectedTeamId={selectedTeamId}
|
||||
currentUserTeams={userTeams || []}
|
||||
|
|
@ -358,9 +365,10 @@ const ManagePolicyPage = (managePoliciesPageProps: {
|
|||
}
|
||||
/>
|
||||
)}
|
||||
{isPremiumTier && userTeams && userTeams.length === 1 && (
|
||||
<h1>{userTeams[0].name}</h1>
|
||||
)}
|
||||
{isPremiumTier &&
|
||||
!isOnGlobalTeam &&
|
||||
userTeams &&
|
||||
userTeams.length === 1 && <h1>{userTeams[0].name}</h1>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { useQuery } from "react-query";
|
|||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { AppContext } from "context/app";
|
||||
import { push } from "react-router-redux";
|
||||
import { find } from "lodash";
|
||||
|
||||
// @ts-ignore
|
||||
import deepDifference from "utilities/deep_difference";
|
||||
|
|
@ -123,9 +124,14 @@ const ManageSchedulePage = ({
|
|||
const { MANAGE_PACKS, MANAGE_SCHEDULE, MANAGE_TEAM_SCHEDULE } = paths;
|
||||
const handleAdvanced = () => dispatch(push(MANAGE_PACKS));
|
||||
|
||||
const { currentUser, isOnGlobalTeam, isPremiumTier, isFreeTier } = useContext(
|
||||
AppContext
|
||||
);
|
||||
const {
|
||||
currentUser,
|
||||
isOnGlobalTeam,
|
||||
isPremiumTier,
|
||||
isFreeTier,
|
||||
currentTeam,
|
||||
setCurrentTeam,
|
||||
} = useContext(AppContext);
|
||||
|
||||
const filterAndSortTeamOptions = (allTeams: ITeam[], userTeams: ITeam[]) => {
|
||||
const filteredSortedTeams = allTeams
|
||||
|
|
@ -167,31 +173,39 @@ const ManageSchedulePage = ({
|
|||
}
|
||||
);
|
||||
|
||||
const teamId = team_id ? parseInt(team_id, 10) : 0;
|
||||
let selectedTeamId: number;
|
||||
|
||||
const handleTeamSelect = (selectedTeamId: number) => {
|
||||
if (selectedTeamId) {
|
||||
dispatch(push(MANAGE_TEAM_SCHEDULE(selectedTeamId)));
|
||||
if (currentTeam) {
|
||||
selectedTeamId = currentTeam.id;
|
||||
} else {
|
||||
selectedTeamId = team_id ? parseInt(team_id, 10) : 0;
|
||||
}
|
||||
|
||||
const handleTeamSelect = (teamId: number) => {
|
||||
if (teamId) {
|
||||
dispatch(push(MANAGE_TEAM_SCHEDULE(teamId)));
|
||||
} else {
|
||||
dispatch(push(MANAGE_SCHEDULE));
|
||||
}
|
||||
const selectedTeam = find(teams, ["id", teamId]);
|
||||
setCurrentTeam(selectedTeam);
|
||||
};
|
||||
|
||||
if (!isOnGlobalTeam && !teamId && teams) {
|
||||
if (!isOnGlobalTeam && !selectedTeamId && teams) {
|
||||
handleTeamSelect(teams[0].id);
|
||||
}
|
||||
|
||||
// TODO: move team scheduled queries and global scheduled queries into services entities, remove redux
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
teamId
|
||||
? teamScheduledQueryActions.loadAll(teamId)
|
||||
selectedTeamId
|
||||
? teamScheduledQueryActions.loadAll(selectedTeamId)
|
||||
: globalScheduledQueryActions.loadAll()
|
||||
);
|
||||
}, [dispatch, teamId]);
|
||||
}, [dispatch, selectedTeamId]);
|
||||
|
||||
const allScheduledQueries = useSelector((state: IRootState) => {
|
||||
if (teamId) {
|
||||
if (selectedTeamId) {
|
||||
return state.entities.team_scheduled_queries;
|
||||
}
|
||||
return state.entities.global_scheduled_queries;
|
||||
|
|
@ -212,7 +226,7 @@ const ManageSchedulePage = ({
|
|||
const inheritedQueryOrQueries =
|
||||
allTeamsScheduledQueriesList.length === 1 ? "query" : "queries";
|
||||
|
||||
const selectedTeam = !teamId ? "global" : teamId;
|
||||
const selectedTeam = !selectedTeamId ? "global" : selectedTeamId;
|
||||
|
||||
const selectedTeamData =
|
||||
teams?.find((team: ITeam) => selectedTeam === team.id) || undefined;
|
||||
|
|
@ -267,8 +281,8 @@ const ManageSchedulePage = ({
|
|||
const onRemoveScheduledQuerySubmit = useCallback(() => {
|
||||
const promises = selectedQueryIds.map((id: number) => {
|
||||
return dispatch(
|
||||
teamId
|
||||
? teamScheduledQueryActions.destroy(teamId, id)
|
||||
selectedTeamId
|
||||
? teamScheduledQueryActions.destroy(selectedTeamId, id)
|
||||
: globalScheduledQueryActions.destroy({ id })
|
||||
);
|
||||
});
|
||||
|
|
@ -283,8 +297,8 @@ const ManageSchedulePage = ({
|
|||
);
|
||||
toggleRemoveScheduledQueryModal();
|
||||
dispatch(
|
||||
teamId
|
||||
? teamScheduledQueryActions.loadAll(teamId)
|
||||
selectedTeamId
|
||||
? teamScheduledQueryActions.loadAll(selectedTeamId)
|
||||
: globalScheduledQueryActions.loadAll()
|
||||
);
|
||||
})
|
||||
|
|
@ -297,7 +311,12 @@ const ManageSchedulePage = ({
|
|||
);
|
||||
toggleRemoveScheduledQueryModal();
|
||||
});
|
||||
}, [dispatch, teamId, selectedQueryIds, toggleRemoveScheduledQueryModal]);
|
||||
}, [
|
||||
dispatch,
|
||||
selectedTeamId,
|
||||
selectedQueryIds,
|
||||
toggleRemoveScheduledQueryModal,
|
||||
]);
|
||||
|
||||
const onAddScheduledQuerySubmit = useCallback(
|
||||
(
|
||||
|
|
@ -307,7 +326,7 @@ const ManageSchedulePage = ({
|
|||
if (editQuery) {
|
||||
const updatedAttributes = deepDifference(formData, editQuery);
|
||||
dispatch(
|
||||
teamId
|
||||
selectedTeamId
|
||||
? teamScheduledQueryActions.update(editQuery, updatedAttributes)
|
||||
: globalScheduledQueryActions.update(editQuery, updatedAttributes)
|
||||
)
|
||||
|
|
@ -319,8 +338,8 @@ const ManageSchedulePage = ({
|
|||
)
|
||||
);
|
||||
dispatch(
|
||||
teamId
|
||||
? teamScheduledQueryActions.loadAll(teamId)
|
||||
selectedTeamId
|
||||
? teamScheduledQueryActions.loadAll(selectedTeamId)
|
||||
: globalScheduledQueryActions.loadAll()
|
||||
);
|
||||
})
|
||||
|
|
@ -334,7 +353,7 @@ const ManageSchedulePage = ({
|
|||
});
|
||||
} else {
|
||||
dispatch(
|
||||
teamId
|
||||
selectedTeamId
|
||||
? teamScheduledQueryActions.create({ ...formData })
|
||||
: globalScheduledQueryActions.create({ ...formData })
|
||||
)
|
||||
|
|
@ -346,8 +365,8 @@ const ManageSchedulePage = ({
|
|||
)
|
||||
);
|
||||
dispatch(
|
||||
teamId
|
||||
? teamScheduledQueryActions.loadAll(teamId)
|
||||
selectedTeamId
|
||||
? teamScheduledQueryActions.loadAll(selectedTeamId)
|
||||
: globalScheduledQueryActions.loadAll()
|
||||
);
|
||||
})
|
||||
|
|
@ -362,7 +381,7 @@ const ManageSchedulePage = ({
|
|||
}
|
||||
toggleScheduleEditorModal();
|
||||
},
|
||||
[dispatch, teamId, toggleScheduleEditorModal]
|
||||
[dispatch, selectedTeamId, toggleScheduleEditorModal]
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
@ -373,18 +392,21 @@ const ManageSchedulePage = ({
|
|||
<div className={`${baseClass}__text`}>
|
||||
<div className={`${baseClass}__title`}>
|
||||
{isFreeTier && <h1>Schedule</h1>}
|
||||
{isPremiumTier && teams && teams.length > 1 && (
|
||||
<TeamsDropdown
|
||||
selectedTeamId={teamId}
|
||||
currentUserTeams={teams || []}
|
||||
onChange={(newSelectedValue: number) =>
|
||||
handleTeamSelect(newSelectedValue)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isPremiumTier && teams && teams.length === 1 && (
|
||||
<h1>{teams[0].name}</h1>
|
||||
)}
|
||||
{isPremiumTier &&
|
||||
teams &&
|
||||
(teams.length > 1 || isOnGlobalTeam) && (
|
||||
<TeamsDropdown
|
||||
selectedTeamId={selectedTeamId}
|
||||
currentUserTeams={teams || []}
|
||||
onChange={(newSelectedValue: number) =>
|
||||
handleTeamSelect(newSelectedValue)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isPremiumTier &&
|
||||
!isOnGlobalTeam &&
|
||||
teams &&
|
||||
teams.length === 1 && <h1>{teams[0].name}</h1>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -413,7 +435,7 @@ const ManageSchedulePage = ({
|
|||
<div className={`${baseClass}__description`}>
|
||||
{!isLoadingTeams && (
|
||||
<div>
|
||||
{!teamId ? (
|
||||
{!selectedTeamId ? (
|
||||
<p>
|
||||
Schedule queries to run at regular intervals across{" "}
|
||||
<strong>all of your hosts.</strong>
|
||||
|
|
@ -440,7 +462,7 @@ const ManageSchedulePage = ({
|
|||
)}
|
||||
</div>
|
||||
{/* must use ternary for NaN */}
|
||||
{teamId && allTeamsScheduledQueriesList.length > 0 ? (
|
||||
{selectedTeamId && allTeamsScheduledQueriesList.length > 0 ? (
|
||||
<>
|
||||
<span>
|
||||
<Button
|
||||
|
|
@ -479,7 +501,7 @@ const ManageSchedulePage = ({
|
|||
onScheduleSubmit={onAddScheduledQuerySubmit}
|
||||
allQueries={fleetQueries}
|
||||
editQuery={selectedScheduledQuery}
|
||||
teamId={teamId}
|
||||
teamId={selectedTeamId}
|
||||
togglePreviewDataModal={togglePreviewDataModal}
|
||||
showPreviewDataModal={showPreviewDataModal}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue