From e7519eef487972039af3ccd66511cc14dfdf58b4 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Mon, 23 Jun 2025 13:03:22 -0400 Subject: [PATCH] 29762: Fixed bug with run script modal on FreeTier. (#30138) For #29762 When running on FreeTier do not apply teamId criteria on end-point used by the Run Script modal. --- changes/29762-run-script-modal-free-tier | 1 + frontend/interfaces/script.ts | 6 ++++ .../hosts/ManageHostsPage/ManageHostsPage.tsx | 7 +++-- .../RunScriptBatchModal.tsx | 31 +++++++++++++------ .../RunScriptBatchPaginatedList.tsx | 21 ++++++++----- 5 files changed, 45 insertions(+), 21 deletions(-) create mode 100644 changes/29762-run-script-modal-free-tier diff --git a/changes/29762-run-script-modal-free-tier b/changes/29762-run-script-modal-free-tier new file mode 100644 index 0000000000..f48c9e6e45 --- /dev/null +++ b/changes/29762-run-script-modal-free-tier @@ -0,0 +1 @@ +* Fixed bug with the run script modal on the Hosts page when running under FreeTier due to invalid teamId filter. \ No newline at end of file diff --git a/frontend/interfaces/script.ts b/frontend/interfaces/script.ts index 7bbdd4dc21..226030f27c 100644 --- a/frontend/interfaces/script.ts +++ b/frontend/interfaces/script.ts @@ -11,6 +11,12 @@ export interface IScript { export const isScriptSupportedPlatform = (hostPlatform: string) => ["darwin", "windows", ...HOST_LINUX_PLATFORMS].includes(hostPlatform); // excludes chrome, ios, ipados, android see also https://github.com/fleetdm/fleet/blob/5a21e2cfb029053ddad0508869eb9f1f23997bf2/server/fleet/hosts.go#L775 +export const addTeamIdCriteria = ( + pred: any, + teamId: number, + isFreeTier?: boolean +) => (isFreeTier ? { ...pred } : { ...pred, team_id: teamId }); + export type IScriptExecutionStatus = "ran" | "pending" | "error"; export interface ILastExecution { diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx index 6f59eafbc0..469e24d2a3 100644 --- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx +++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx @@ -2004,18 +2004,19 @@ const ManageHostsPage = ({ totalFilteredHostsCount !== undefined && ( )} diff --git a/frontend/pages/hosts/ManageHostsPage/components/RunScriptBatchModal/RunScriptBatchModal.tsx b/frontend/pages/hosts/ManageHostsPage/components/RunScriptBatchModal/RunScriptBatchModal.tsx index bf43b33d67..1ed4ce8872 100644 --- a/frontend/pages/hosts/ManageHostsPage/components/RunScriptBatchModal/RunScriptBatchModal.tsx +++ b/frontend/pages/hosts/ManageHostsPage/components/RunScriptBatchModal/RunScriptBatchModal.tsx @@ -5,7 +5,7 @@ import classnames from "classnames"; import { NotificationContext } from "context/notification"; -import { IScript } from "interfaces/script"; +import { addTeamIdCriteria, IScript } from "interfaces/script"; import { getErrorReason } from "interfaces/errors"; import { DEFAULT_USE_QUERY_OPTIONS } from "utilities/constants"; @@ -33,6 +33,8 @@ interface IRunScriptBatchModal { // `filters` as needed filters: Omit; teamId: number; + // If we are on the free tier, we don't want to apply any kind of team filters (since the feature is Premium only). + isFreeTier?: boolean; totalFilteredHostsCount: number; selectedHostIds: number[]; onCancel: () => void; @@ -44,6 +46,7 @@ const RunScriptBatchModal = ({ totalFilteredHostsCount, selectedHostIds, teamId, + isFreeTier, onCancel, }: IRunScriptBatchModal) => { const { renderFlash } = useContext(NotificationContext); @@ -52,19 +55,14 @@ const RunScriptBatchModal = ({ const [scriptForDetails, setScriptForDetails] = useState< IPaginatedListScript | undefined >(undefined); - // just used to get total number of scripts, could be optimized by implementing a dedicated scriptsCount endpoint + // just used to get the total number of scripts, could be optimized by implementing a dedicated scriptsCount endpoint const { data: scripts } = useQuery< IScriptsResponse, Error, IScript[], IListScriptsQueryKey[] >( - [ - { - scope: "scripts", - team_id: teamId, - }, - ], + [addTeamIdCriteria({ scope: "scripts" }, teamId, isFreeTier)], ({ queryKey }) => { return scriptsAPI.getScripts(queryKey[0]); }, @@ -80,7 +78,10 @@ const RunScriptBatchModal = ({ setIsUpdating(true); const body = runByFilters ? // satisfy IScriptBatchSupportedFilters - { script_id: script.id, filters: { ...filters, team_id: teamId } } + { + script_id: script.id, + filters: addTeamIdCriteria(filters, teamId, isFreeTier), + } : { script_id: script.id, host_ids: selectedHostIds }; try { await scriptsAPI.runScriptBatch(body); @@ -118,7 +119,16 @@ const RunScriptBatchModal = ({ info={ <> You can add saved scripts{" "} - here. + + here + + . } /> @@ -140,6 +150,7 @@ const RunScriptBatchModal = ({ onRunScript={onRunScriptBatch} isUpdating={isUpdating} teamId={teamId} + isFreeTier={isFreeTier} scriptCount={scripts.length} setScriptForDetails={setScriptForDetails} /> diff --git a/frontend/pages/hosts/ManageHostsPage/components/RunScriptBatchPaginatedList/RunScriptBatchPaginatedList.tsx b/frontend/pages/hosts/ManageHostsPage/components/RunScriptBatchPaginatedList/RunScriptBatchPaginatedList.tsx index 49700fecc7..1e03645c2b 100644 --- a/frontend/pages/hosts/ManageHostsPage/components/RunScriptBatchPaginatedList/RunScriptBatchPaginatedList.tsx +++ b/frontend/pages/hosts/ManageHostsPage/components/RunScriptBatchPaginatedList/RunScriptBatchPaginatedList.tsx @@ -3,7 +3,7 @@ import { useQueryClient } from "react-query"; import scriptAPI, { IScriptsResponse } from "services/entities/scripts"; -import { IScript } from "interfaces/script"; +import { addTeamIdCriteria, IScript } from "interfaces/script"; import PaginatedList from "components/PaginatedList"; import Button from "components/buttons/Button"; @@ -19,6 +19,7 @@ interface IRunScriptBatchPaginatedList { onRunScript: (script: IPaginatedListScript) => Promise; isUpdating: boolean; teamId: number; + isFreeTier?: boolean; scriptCount: number; setScriptForDetails: (script: IPaginatedListScript) => void; } @@ -28,6 +29,7 @@ export const SCRIPT_BATCH_PAGE_SIZE = 6; const RunScriptBatchPaginatedList = ({ onRunScript: _onRunScript, isUpdating, + isFreeTier, teamId, scriptCount, setScriptForDetails, @@ -40,12 +42,15 @@ const RunScriptBatchPaginatedList = ({ // scripts not supported for All teams const fetchPromise = queryClient.fetchQuery( [ - { - scope: "scripts", - team_id: teamId, - page: pageNumber, - per_page: SCRIPT_BATCH_PAGE_SIZE, - }, + addTeamIdCriteria( + { + scope: "scripts", + page: pageNumber, + per_page: SCRIPT_BATCH_PAGE_SIZE, + }, + teamId, + isFreeTier + ), ], ({ queryKey }) => { return scriptAPI.getScripts(queryKey[0]); @@ -56,7 +61,7 @@ const RunScriptBatchPaginatedList = ({ return scripts || []; }); }, - [queryClient, teamId] + [queryClient, teamId, isFreeTier] ); const onRunScript = useCallback(