diff --git a/designer/client/cypress/e2e/counts.cy.ts b/designer/client/cypress/e2e/counts.cy.ts index 6a3042c53ed..a7a57092dd7 100644 --- a/designer/client/cypress/e2e/counts.cy.ts +++ b/designer/client/cypress/e2e/counts.cy.ts @@ -22,7 +22,7 @@ describe("Counts", () => { cy.get("@button").click(); cy.get("[data-testid=window]").contains("Quick ranges").should("be.visible"); - cy.contains(/^latest deploy$/i).should("not.exist"); + cy.contains(/^latest run$/i).should("not.exist"); cy.get("[data-testid=window]").matchImage({ maxDiffThreshold }); cy.get("[data-testid=window]") .contains(/^cancel$/i) @@ -31,7 +31,7 @@ describe("Counts", () => { cy.deployScenario(); cy.get("@button").click(); cy.get("[data-testid=window]").contains("Quick ranges").should("be.visible"); - cy.contains(/^latest deploy$/i).should("be.visible"); + cy.contains(/^latest run$/i).should("be.visible"); cy.get("[data-testid=window]").matchImage({ maxDiffThreshold }); cy.get("[data-testid=window]") .contains(/^cancel$/i) @@ -44,12 +44,12 @@ describe("Counts", () => { cy.get("@button").click(); cy.get("[data-testid=window]").contains("Quick ranges").should("be.visible"); - cy.contains(/^previous deployments...$/i) + cy.contains(/^previous activities...$/i) .should("be.visible") .click(); cy.get("[data-testid=window]").matchImage({ maxDiffThreshold }); cy.get("[data-testid=window]").contains("no refresh").should("be.visible"); - cy.get("[data-testid=window]").contains("Latest deploy").click(); + cy.get("[data-testid=window]").contains("Latest Run").click(); cy.get("[data-testid=window]").contains("10 seconds").should("be.visible"); }); diff --git a/designer/client/src/components/modals/CalculateCounts/CountsRanges.tsx b/designer/client/src/components/modals/CalculateCounts/CountsRanges.tsx index ea53dc1c1c5..a41c688397c 100644 --- a/designer/client/src/components/modals/CalculateCounts/CountsRanges.tsx +++ b/designer/client/src/components/modals/CalculateCounts/CountsRanges.tsx @@ -2,11 +2,11 @@ import { Moment } from "moment"; import React, { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; -import { getProcessName } from "../../../reducers/selectors/graph"; +import { getProcessingType, getProcessName } from "../../../reducers/selectors/graph"; import { CountsRangesButtons } from "./CountsRangesButtons"; -import { useDeployHistory } from "./useDeployHistory"; import { predefinedRanges } from "./utils"; import { StyledRangesWrapper } from "./CountsStyled"; +import { useActivityHistory } from "./useActivityHistory"; interface RangesProps { label: string; @@ -16,7 +16,8 @@ interface RangesProps { export function CountsRanges({ label, onChange }: RangesProps): JSX.Element { const { t } = useTranslation(); const processName = useSelector(getProcessName); - const deploys = useDeployHistory(processName); + const processCategory = useSelector(getProcessingType); + const activities = useActivityHistory(processName, processCategory); const dates = useMemo(() => predefinedRanges(t), [t]); return ( @@ -24,8 +25,8 @@ export function CountsRanges({ label, onChange }: RangesProps): JSX.Element {

{label}

- - {t("calculateCounts.deployments", "Previous deployments...")} + + {t("calculateCounts.activities", "Previous activities...")} diff --git a/designer/client/src/components/modals/CalculateCounts/useActivityHistory.ts b/designer/client/src/components/modals/CalculateCounts/useActivityHistory.ts new file mode 100644 index 00000000000..c491351f35f --- /dev/null +++ b/designer/client/src/components/modals/CalculateCounts/useActivityHistory.ts @@ -0,0 +1,68 @@ +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import HttpService from "../../../http/HttpService"; +import { DATE_FORMAT } from "../../../config"; +import { Range } from "./CountsRangesButtons"; +import moment from "moment"; +import { ActivityTypesRelatedToExecutions } from "../../toolbars/activities/types"; + +function displayableNameOfPredefinedActivityType(predefinedActivityType: ActivityTypesRelatedToExecutions) { + switch (predefinedActivityType) { + case ActivityTypesRelatedToExecutions.ScenarioCanceled: + return "Cancel"; + case ActivityTypesRelatedToExecutions.ScenarioDeployed: + return "Deployment"; + case ActivityTypesRelatedToExecutions.PerformedScheduledExecution: + return "Scheduled deployment"; + case ActivityTypesRelatedToExecutions.PerformedSingleExecution: + return "Run now"; + default: + return "Unknown activity type"; + } +} +/* + In the context of batch processing, the information about a performed deployment does not provide meaningful insights for range calculations. + This is because batch processes do not execute immediately after a deployment action. To address this, deployment-related activities + (of type `ScenarioDeployed`) are excluded when computing ranges for batch processes. + + Additionally, the `Cancel` activity type (`ScenarioCanceled`) plays a role in determining count ranges during internal processing, + but it is not relevant to the end user. As a result, activities with this type are filtered out at the end of the computation process + (handled using the `isOmitted` variable). + */ +export function useActivityHistory(processName: string, processingMode: string): Range[] { + const { t } = useTranslation(); + const [activities, setActivities] = useState([]); + + useEffect(() => { + HttpService.fetchActivitiesRelatedToExecutions(processName) + .then((activities) => + processingMode.includes("batch") + ? activities.filter((activity) => activity.type !== ActivityTypesRelatedToExecutions.ScenarioDeployed) + : activities, + ) + .then((activities) => + activities.map((current, i, all) => { + const from = moment(current.date); + const to = all[i - 1]?.date; + const isOmitted = current.type === ActivityTypesRelatedToExecutions.ScenarioCanceled; + return { + from: () => from, + to: () => (to ? moment(to) : moment().add(1, "day").startOf("day")), + name: t("calculateCounts.range.prevAction", "{{activity}} {{date}}", { + activity: displayableNameOfPredefinedActivityType(current.type), + date: from.format(DATE_FORMAT), + }), + isOmitted, + }; + }), + ) + .then((res) => res.filter((activity) => !activity.isOmitted)) + .then((res) => { + res[0].name = t("calculateCounts.range.lastAction", "Latest Run"); + return res; + }) + .then(setActivities); + }, [t, processName]); + + return activities; +} diff --git a/designer/client/src/components/modals/CalculateCounts/useDeployHistory.ts b/designer/client/src/components/modals/CalculateCounts/useDeployHistory.ts deleted file mode 100644 index 1a5fc6fc019..00000000000 --- a/designer/client/src/components/modals/CalculateCounts/useDeployHistory.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import HttpService from "../../../http/HttpService"; -import { DATE_FORMAT } from "../../../config"; -import { Range } from "./CountsRangesButtons"; -import moment from "moment"; - -export function useDeployHistory(processName: string): Range[] { - const { t } = useTranslation(); - const [deploys, setDeploys] = useState([]); - - useEffect(() => { - HttpService.fetchProcessesDeployments(processName) - .then((dates) => - dates.map((current, i, all) => { - const from = moment(current); - const to = all[i - 1]; - return { - from: () => from, - to: () => (to ? moment(to) : moment().add(1, "day").startOf("day")), - name: i - ? t("calculateCounts.range.prevDeploy", "Previous deploy #{{i}} ({{date}})", { - i: all.length - i, - date: from.format(DATE_FORMAT), - }) - : t("calculateCounts.range.lastDeploy", "Latest deploy"), - }; - }), - ) - .then(setDeploys); - }, [t, processName]); - - return deploys; -} diff --git a/designer/client/src/components/toolbars/activities/types.ts b/designer/client/src/components/toolbars/activities/types.ts index 2c7712826ae..66f11b14772 100644 --- a/designer/client/src/components/toolbars/activities/types.ts +++ b/designer/client/src/components/toolbars/activities/types.ts @@ -17,6 +17,13 @@ export type ActivityType = | "AUTOMATIC_UPDATE" | "CUSTOM_ACTION"; +export enum ActivityTypesRelatedToExecutions { + ScenarioDeployed = "SCENARIO_DEPLOYED", + ScenarioCanceled = "SCENARIO_CANCELED", + PerformedSingleExecution = "PERFORMED_SINGLE_EXECUTION", + PerformedScheduledExecution = "PERFORMED_SCHEDULED_EXECUTION", +} + export interface ActivityMetadata { type: ActivityType; displayableName: string; diff --git a/designer/client/src/http/HttpService.ts b/designer/client/src/http/HttpService.ts index d5bae6579c2..ff0cf6554b7 100644 --- a/designer/client/src/http/HttpService.ts +++ b/designer/client/src/http/HttpService.ts @@ -22,7 +22,12 @@ import { Scenario, StatusDefinitionType, } from "../components/Process/types"; -import { ActivitiesResponse, ActivityMetadataResponse } from "../components/toolbars/activities/types"; +import { + ActivitiesResponse, + ActivityMetadataResponse, + ActivityType, + ActivityTypesRelatedToExecutions, +} from "../components/toolbars/activities/types"; import { ToolbarsConfig } from "../components/toolbarSettings/types"; import { EventTrackingSelectorType, EventTrackingType } from "../containers/event-tracking"; import { BackendNotification } from "../containers/Notifications"; @@ -321,17 +326,17 @@ class HttpService { return promise; } - fetchProcessesDeployments(processName: string) { + fetchActivitiesRelatedToExecutions(processName: string) { return api - .get< - { - performedAt: string; - actionName: ActionName; - }[] - >(`/processes/${encodeURIComponent(processName)}/deployments`) - .then((res) => - res.data.filter(({ actionName }) => actionName === PredefinedActionName.Deploy).map(({ performedAt }) => performedAt), - ); + .get<{ activities: { date: string; type: ActivityType }[] }>( + `/processes/${encodeURIComponent(processName)}/activity/activities`, + ) + .then((res) => { + return res.data.activities.filter(({ date, type }) => + Object.values(ActivityTypesRelatedToExecutions).includes(type as ActivityTypesRelatedToExecutions), + ); + }) + .then((res) => res.reverse().map((item) => ({ ...item, type: item.type as ActivityTypesRelatedToExecutions }))); } deploy(