2023-04-07 15:36:47 +00:00
|
|
|
import React, { useState, useCallback, useContext } from "react";
|
2025-01-09 18:08:46 +00:00
|
|
|
import { useQuery } from "react-query";
|
2021-04-28 15:08:00 +00:00
|
|
|
import { filter, includes } from "lodash";
|
2025-01-09 18:08:46 +00:00
|
|
|
import { InjectedRouter } from "react-router";
|
|
|
|
|
|
|
|
|
|
import PATHS from "router/paths";
|
|
|
|
|
|
|
|
|
|
import permissions from "utilities/permissions";
|
|
|
|
|
|
2023-04-07 15:36:47 +00:00
|
|
|
import { AppContext } from "context/app";
|
2025-01-09 18:08:46 +00:00
|
|
|
import { QueryContext } from "context/query";
|
|
|
|
|
|
|
|
|
|
import queryAPI from "services/entities/queries";
|
2021-04-28 15:08:00 +00:00
|
|
|
|
2021-12-05 23:12:55 +00:00
|
|
|
// @ts-ignore
|
2023-07-19 14:40:59 +00:00
|
|
|
import InputFieldWithIcon from "components/forms/fields/InputFieldWithIcon";
|
2025-01-09 18:08:46 +00:00
|
|
|
import Button from "components/buttons/Button";
|
|
|
|
|
import Modal from "components/Modal";
|
2022-05-03 20:57:08 +00:00
|
|
|
import DataError from "components/DataError";
|
2025-01-09 18:08:46 +00:00
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
IListQueriesResponse,
|
|
|
|
|
IQueryKeyQueriesLoadAll,
|
|
|
|
|
ISchedulableQuery,
|
|
|
|
|
} from "interfaces/schedulable_query";
|
|
|
|
|
import { API_ALL_TEAMS_ID } from "interfaces/team";
|
|
|
|
|
import { DEFAULT_TARGETS_BY_TYPE } from "interfaces/target";
|
2025-02-27 15:53:34 +00:00
|
|
|
import { getPathWithQueryParams } from "utilities/url";
|
2021-04-28 15:08:00 +00:00
|
|
|
|
2021-12-05 23:12:55 +00:00
|
|
|
export interface ISelectQueryModalProps {
|
|
|
|
|
onCancel: () => void;
|
2023-04-07 15:36:47 +00:00
|
|
|
isOnlyObserver?: boolean;
|
2025-01-09 18:08:46 +00:00
|
|
|
hostId: number;
|
|
|
|
|
hostTeamId: number | null;
|
|
|
|
|
router: InjectedRouter; // v3
|
|
|
|
|
currentTeamId: number | undefined;
|
2021-12-05 23:12:55 +00:00
|
|
|
}
|
2021-04-28 15:08:00 +00:00
|
|
|
|
2021-12-05 23:12:55 +00:00
|
|
|
const baseClass = "select-query-modal";
|
2021-04-28 15:08:00 +00:00
|
|
|
|
2021-10-22 15:34:45 +00:00
|
|
|
const SelectQueryModal = ({
|
|
|
|
|
onCancel,
|
|
|
|
|
isOnlyObserver,
|
2025-01-09 18:08:46 +00:00
|
|
|
hostId,
|
|
|
|
|
hostTeamId,
|
|
|
|
|
router,
|
|
|
|
|
currentTeamId,
|
2022-02-14 22:11:12 +00:00
|
|
|
}: ISelectQueryModalProps): JSX.Element => {
|
2025-01-09 18:08:46 +00:00
|
|
|
const { setSelectedQueryTargetsByType } = useContext(QueryContext);
|
|
|
|
|
|
|
|
|
|
const { data: queries, error: queriesErr } = useQuery<
|
|
|
|
|
IListQueriesResponse,
|
|
|
|
|
Error,
|
|
|
|
|
ISchedulableQuery[],
|
|
|
|
|
IQueryKeyQueriesLoadAll[]
|
|
|
|
|
>(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
scope: "queries",
|
|
|
|
|
teamId: hostTeamId || API_ALL_TEAMS_ID,
|
|
|
|
|
mergeInherited: hostTeamId !== API_ALL_TEAMS_ID,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
({ queryKey }) => queryAPI.loadAll(queryKey[0]),
|
|
|
|
|
{
|
|
|
|
|
refetchOnMount: false,
|
|
|
|
|
refetchOnReconnect: false,
|
|
|
|
|
refetchOnWindowFocus: false,
|
|
|
|
|
retry: false,
|
|
|
|
|
select: (data: IListQueriesResponse) => data.queries,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const onQueryHostCustom = () => {
|
|
|
|
|
setSelectedQueryTargetsByType(DEFAULT_TARGETS_BY_TYPE);
|
|
|
|
|
router.push(
|
2026-03-06 14:24:50 +00:00
|
|
|
getPathWithQueryParams(PATHS.NEW_REPORT, {
|
2025-02-27 15:53:34 +00:00
|
|
|
host_id: hostId,
|
2026-02-17 21:19:33 +00:00
|
|
|
fleet_id: currentTeamId,
|
2025-02-27 15:53:34 +00:00
|
|
|
})
|
2025-01-09 18:08:46 +00:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onQueryHostSaved = (selectedQuery: ISchedulableQuery) => {
|
|
|
|
|
setSelectedQueryTargetsByType(DEFAULT_TARGETS_BY_TYPE);
|
|
|
|
|
router.push(
|
2026-03-06 14:24:50 +00:00
|
|
|
getPathWithQueryParams(PATHS.EDIT_REPORT(selectedQuery.id), {
|
2025-02-27 15:53:34 +00:00
|
|
|
host_id: hostId,
|
2026-02-17 21:19:33 +00:00
|
|
|
fleet_id: currentTeamId,
|
2025-02-27 15:53:34 +00:00
|
|
|
})
|
2025-01-09 18:08:46 +00:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2021-08-27 18:13:28 +00:00
|
|
|
let queriesAvailableToRun = queries;
|
|
|
|
|
|
2023-04-07 15:36:47 +00:00
|
|
|
const { currentUser, isObserverPlus } = useContext(AppContext);
|
|
|
|
|
|
|
|
|
|
/* Context team id might be different that host's team id
|
|
|
|
|
Observer plus must be checked against host's team id */
|
|
|
|
|
const isHostsTeamObserverPlus = currentUser
|
2025-01-09 18:08:46 +00:00
|
|
|
? permissions.isObserverPlus(currentUser, hostTeamId)
|
2023-04-07 15:36:47 +00:00
|
|
|
: false;
|
|
|
|
|
|
2021-12-05 23:12:55 +00:00
|
|
|
const [queriesFilter, setQueriesFilter] = useState("");
|
|
|
|
|
|
2023-04-07 15:36:47 +00:00
|
|
|
if (isOnlyObserver && !isObserverPlus && !isHostsTeamObserverPlus) {
|
2025-01-09 18:08:46 +00:00
|
|
|
queriesAvailableToRun =
|
|
|
|
|
queries?.filter((query) => query.observer_can_run === true) || [];
|
2021-08-27 18:13:28 +00:00
|
|
|
}
|
2021-04-28 15:08:00 +00:00
|
|
|
|
|
|
|
|
const getQueries = () => {
|
|
|
|
|
if (!queriesFilter) {
|
2021-08-27 18:13:28 +00:00
|
|
|
return queriesAvailableToRun;
|
2021-04-28 15:08:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lowerQueryFilter = queriesFilter.toLowerCase();
|
|
|
|
|
|
2021-08-27 18:13:28 +00:00
|
|
|
return filter(queriesAvailableToRun, (query) => {
|
2021-04-28 15:08:00 +00:00
|
|
|
if (!query.name) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lowerQueryName = query.name.toLowerCase();
|
|
|
|
|
|
|
|
|
|
return includes(lowerQueryName, lowerQueryFilter);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2021-12-05 23:12:55 +00:00
|
|
|
const onFilterQueries = useCallback(
|
|
|
|
|
(filterString: string): void => {
|
|
|
|
|
setQueriesFilter(filterString);
|
|
|
|
|
},
|
|
|
|
|
[setQueriesFilter]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const queriesFiltered = getQueries();
|
|
|
|
|
|
2025-01-09 18:08:46 +00:00
|
|
|
const queriesCount = queriesFiltered?.length || 0;
|
2021-12-05 23:12:55 +00:00
|
|
|
|
2024-04-10 17:54:31 +00:00
|
|
|
const renderDescription = (): JSX.Element => {
|
2021-05-13 23:29:31 +00:00
|
|
|
return (
|
2024-04-10 17:54:31 +00:00
|
|
|
<div className={`${baseClass}__description`}>
|
2026-02-17 21:19:33 +00:00
|
|
|
Choose a report to run on this host
|
2024-04-10 17:54:31 +00:00
|
|
|
{(!isOnlyObserver || isObserverPlus || isHostsTeamObserverPlus) && (
|
|
|
|
|
<>
|
|
|
|
|
{" "}
|
|
|
|
|
or{" "}
|
|
|
|
|
<Button variant="text-link" onClick={onQueryHostCustom}>
|
2026-02-17 21:19:33 +00:00
|
|
|
create your own report
|
2024-04-10 17:54:31 +00:00
|
|
|
</Button>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
.
|
|
|
|
|
</div>
|
2021-05-13 23:29:31 +00:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2024-10-07 22:02:05 +00:00
|
|
|
const renderQueries = (): JSX.Element => {
|
2025-01-09 18:08:46 +00:00
|
|
|
if (queriesErr) {
|
2022-05-03 20:57:08 +00:00
|
|
|
return <DataError />;
|
2021-05-13 23:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!queriesFilter && queriesCount === 0) {
|
|
|
|
|
return (
|
2021-05-18 20:46:44 +00:00
|
|
|
<div className={`${baseClass}__no-queries`}>
|
2026-02-17 21:19:33 +00:00
|
|
|
<span className="info__header">You have no saved reports.</span>
|
2021-05-13 23:29:31 +00:00
|
|
|
<span className="info__data">
|
2026-02-17 21:19:33 +00:00
|
|
|
Expecting to see reports? Try again in a few seconds as the system
|
2021-05-13 23:29:31 +00:00
|
|
|
catches up.
|
|
|
|
|
</span>
|
2021-04-28 15:08:00 +00:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (queriesCount > 0) {
|
2025-01-09 18:08:46 +00:00
|
|
|
const queryList =
|
|
|
|
|
queriesFiltered?.map((query) => {
|
|
|
|
|
return (
|
|
|
|
|
<Button
|
|
|
|
|
key={query.id}
|
|
|
|
|
variant="unstyled-modal-query"
|
|
|
|
|
className={`${baseClass}__modal-query-button`}
|
|
|
|
|
onClick={() => onQueryHostSaved(query)}
|
|
|
|
|
>
|
|
|
|
|
<>
|
|
|
|
|
<span className="info__header">{query.name}</span>
|
|
|
|
|
{query.description && (
|
|
|
|
|
<span className="info__data">{query.description}</span>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
</Button>
|
|
|
|
|
);
|
|
|
|
|
}) || [];
|
2024-04-10 17:54:31 +00:00
|
|
|
|
2021-04-28 15:08:00 +00:00
|
|
|
return (
|
2024-04-10 17:54:31 +00:00
|
|
|
<>
|
|
|
|
|
<InputFieldWithIcon
|
|
|
|
|
name="query-filter"
|
|
|
|
|
onChange={onFilterQueries}
|
2026-02-17 21:19:33 +00:00
|
|
|
placeholder="Filter reports"
|
2024-04-10 17:54:31 +00:00
|
|
|
value={queriesFilter}
|
|
|
|
|
autofocus
|
|
|
|
|
iconSvg="search"
|
|
|
|
|
/>
|
2024-10-07 22:02:05 +00:00
|
|
|
<div className={`${baseClass}__query-selection`}>{queryList}</div>
|
2024-04-10 17:54:31 +00:00
|
|
|
</>
|
2021-04-28 15:08:00 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (queriesFilter && queriesCount === 0) {
|
|
|
|
|
return (
|
2024-04-10 17:54:31 +00:00
|
|
|
<>
|
|
|
|
|
<div className={`${baseClass}__filter-queries`}>
|
|
|
|
|
<InputFieldWithIcon
|
|
|
|
|
name="query-filter"
|
|
|
|
|
onChange={onFilterQueries}
|
2026-02-17 21:19:33 +00:00
|
|
|
placeholder="Filter reports"
|
2024-04-10 17:54:31 +00:00
|
|
|
value={queriesFilter}
|
|
|
|
|
autofocus
|
|
|
|
|
iconSvg="search"
|
|
|
|
|
/>
|
2021-04-28 15:08:00 +00:00
|
|
|
</div>
|
2024-04-10 17:54:31 +00:00
|
|
|
<div className={`${baseClass}__no-queries`}>
|
2021-04-28 15:08:00 +00:00
|
|
|
<span className="info__header">
|
2026-02-17 21:19:33 +00:00
|
|
|
No reports match the current search criteria.
|
2021-04-28 15:08:00 +00:00
|
|
|
</span>
|
|
|
|
|
<span className="info__data">
|
2026-02-17 21:19:33 +00:00
|
|
|
Expecting to see reports? Try again in a few seconds as the system
|
2021-04-28 15:08:00 +00:00
|
|
|
catches up.
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
2024-04-10 17:54:31 +00:00
|
|
|
</>
|
2021-04-28 15:08:00 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-12-05 23:12:55 +00:00
|
|
|
return <></>;
|
2021-04-28 15:08:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Modal
|
2026-02-17 21:19:33 +00:00
|
|
|
title="Select a report"
|
2021-09-28 21:05:25 +00:00
|
|
|
onExit={onCancel}
|
2024-10-16 15:24:08 +00:00
|
|
|
onEnter={onCancel}
|
2024-04-10 17:54:31 +00:00
|
|
|
className={baseClass}
|
|
|
|
|
width="large"
|
2021-04-28 15:08:00 +00:00
|
|
|
>
|
2026-03-10 22:30:55 +00:00
|
|
|
{renderDescription()}
|
|
|
|
|
{renderQueries()}
|
2021-04-28 15:08:00 +00:00
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default SelectQueryModal;
|