From 1139bee35689d79b7f4a5508e494b3a5bfbaca2d Mon Sep 17 00:00:00 2001
From: ek-hystax <33006768+ek-hystax@users.noreply.github.com>
Date: Wed, 11 Dec 2024 14:26:14 +0400
Subject: [PATCH] OS-7414. Publicly available run page
---
ngui/ui/src/api/restapi/actionCreators.ts | 36 ++--
.../ArtifactsTable/ArtifactsTable.tsx | 2 +-
.../DashboardControls/DashboardControls.tsx | 37 ++--
.../ExecutionBreakdown/ExecutionBreakdown.tsx | 25 ++-
.../ExecutorLabel/ExecutorLabel.tsx | 10 +-
.../components/MlArtifacts/MlArtifacts.tsx | 4 +
.../MlExecutorsTable/MlExecutorsTable.tsx | 39 ++---
.../src/components/MlExecutorsTable/utils.ts | 23 +++
.../MlTaskRun/Components/Charts/Charts.tsx | 56 +++++++
.../MlTaskRun/Components/Charts}/utils.ts | 0
.../MlTaskRun/Components/Executors.tsx | 18 --
.../Components/Executors/Executors.tsx | 33 ++++
.../Components/{ => Overview}/Overview.tsx | 106 ++++++------
.../MlTaskRun/Components/Status.tsx | 63 -------
.../MlTaskRun/Components/Status/Status.tsx | 58 +++++++
.../components/MlTaskRun/Components/Tabs.tsx | 52 ++++++
.../components/MlTaskRun/Components/index.ts | 9 +-
.../ui/src/components/MlTaskRun/MlTaskRun.tsx | 158 +++++++++---------
ngui/ui/src/components/MlTaskRun/index.ts | 3 +-
.../components/ShareRunLink/ShareRunLink.tsx | 37 ++++
ngui/ui/src/components/ShareRunLink/index.ts | 3 +
.../SelectStageOrMilestoneModal.tsx | 28 +++-
.../SideModals/ShareRunLinkModal.tsx | 20 +++
.../SideModalManager/SideModals/index.ts | 4 +-
.../ColumnSetsContainer.tsx | 6 +-
.../CreateColumnSetFormContainer.tsx | 6 +-
.../ExecutionBreakdownContainer.tsx | 28 ----
.../ExecutionBreakdownContainer/index.ts | 6 -
.../MlArtifactsContainer.tsx | 18 +-
.../MlCreateRunArtifactContainer.tsx | 2 +-
.../MlEditRunArtifactContainer.tsx | 2 +-
.../MlExecutorsContainer.tsx | 6 +-
.../MlTaskExecutorsContainer.tsx | 6 +-
.../MlTaskRunContainer/MlTaskRunContainer.tsx | 7 +-
.../PublicMlRunContainer.tsx | 48 ++++++
.../containers/PublicMlRunContainer/index.ts | 3 +
.../RunArtifactsContainer.tsx | 9 +-
.../ShareRunLinkContainer.tsx | 18 ++
.../containers/ShareRunLinkContainer/index.ts | 3 +
.../StagesAndMilestonesContainer.tsx | 40 -----
.../StagesAndMilestonesContainer/index.ts | 3 -
.../src/graphql/api/restapi/queries/index.ts | 4 +-
ngui/ui/src/hooks/useTaskRunChartState.ts | 32 +++-
ngui/ui/src/pages/PublicMlRun/PublicMlRun.tsx | 5 +
ngui/ui/src/pages/PublicMlRun/index.ts | 3 +
ngui/ui/src/services/LayoutsService.ts | 20 +--
ngui/ui/src/services/MlArtifactsService.ts | 3 +-
ngui/ui/src/services/MlExecutorsService.ts | 16 +-
ngui/ui/src/services/MlProfilingService.ts | 4 +-
ngui/ui/src/services/MlTasksService.ts | 16 +-
ngui/ui/src/translations/en-US/app.json | 2 +
ngui/ui/src/urls.ts | 12 ++
ngui/ui/src/utils/columns/executor.tsx | 10 +-
.../src/utils/columns/mlExecutorLocation.tsx | 8 +-
ngui/ui/src/utils/routes/index.ts | 2 +
ngui/ui/src/utils/routes/publicMlRun.ts | 14 ++
56 files changed, 771 insertions(+), 415 deletions(-)
create mode 100644 ngui/ui/src/components/MlExecutorsTable/utils.ts
create mode 100644 ngui/ui/src/components/MlTaskRun/Components/Charts/Charts.tsx
rename ngui/ui/src/{containers/ExecutionBreakdownContainer => components/MlTaskRun/Components/Charts}/utils.ts (100%)
delete mode 100644 ngui/ui/src/components/MlTaskRun/Components/Executors.tsx
create mode 100644 ngui/ui/src/components/MlTaskRun/Components/Executors/Executors.tsx
rename ngui/ui/src/components/MlTaskRun/Components/{ => Overview}/Overview.tsx (74%)
delete mode 100644 ngui/ui/src/components/MlTaskRun/Components/Status.tsx
create mode 100644 ngui/ui/src/components/MlTaskRun/Components/Status/Status.tsx
create mode 100644 ngui/ui/src/components/MlTaskRun/Components/Tabs.tsx
create mode 100644 ngui/ui/src/components/ShareRunLink/ShareRunLink.tsx
create mode 100644 ngui/ui/src/components/ShareRunLink/index.ts
create mode 100644 ngui/ui/src/components/SideModalManager/SideModals/ShareRunLinkModal.tsx
delete mode 100644 ngui/ui/src/containers/ExecutionBreakdownContainer/ExecutionBreakdownContainer.tsx
delete mode 100644 ngui/ui/src/containers/ExecutionBreakdownContainer/index.ts
create mode 100644 ngui/ui/src/containers/PublicMlRunContainer/PublicMlRunContainer.tsx
create mode 100644 ngui/ui/src/containers/PublicMlRunContainer/index.ts
create mode 100644 ngui/ui/src/containers/ShareRunLinkContainer/ShareRunLinkContainer.tsx
create mode 100644 ngui/ui/src/containers/ShareRunLinkContainer/index.ts
delete mode 100644 ngui/ui/src/containers/StagesAndMilestonesContainer/StagesAndMilestonesContainer.tsx
delete mode 100644 ngui/ui/src/containers/StagesAndMilestonesContainer/index.ts
create mode 100644 ngui/ui/src/pages/PublicMlRun/PublicMlRun.tsx
create mode 100644 ngui/ui/src/pages/PublicMlRun/index.ts
create mode 100644 ngui/ui/src/utils/routes/publicMlRun.ts
diff --git a/ngui/ui/src/api/restapi/actionCreators.ts b/ngui/ui/src/api/restapi/actionCreators.ts
index 07f9211b2..cf7633afb 100644
--- a/ngui/ui/src/api/restapi/actionCreators.ts
+++ b/ngui/ui/src/api/restapi/actionCreators.ts
@@ -2240,24 +2240,30 @@ export const getMlTaskRunsBulk = (organizationId, taskId, runIds) =>
}
});
-export const getMlRunDetails = (organizationId, runId) =>
+export const getMlRunDetails = (organizationId, runId, params = {}) =>
apiAction({
url: `${API_URL}/organizations/${organizationId}/runs/${runId}`,
method: "GET",
ttl: 5 * MINUTE,
onSuccess: handleSuccess(SET_ML_RUN_DETAILS),
hash: hashParams({ organizationId, runId }),
- label: GET_ML_RUN_DETAILS
+ label: GET_ML_RUN_DETAILS,
+ params: {
+ token: params.arceeToken
+ }
});
-export const getMlRunDetailsBreakdown = (organizationId, runId) =>
+export const getMlRunDetailsBreakdown = (organizationId, runId, params = {}) =>
apiAction({
url: `${API_URL}/organizations/${organizationId}/runs/${runId}/breakdown`,
method: "GET",
ttl: 5 * MINUTE,
onSuccess: handleSuccess(SET_ML_RUN_DETAILS_BREAKDOWN),
hash: hashParams({ organizationId, runId }),
- label: GET_ML_RUN_DETAILS_BREAKDOWN
+ label: GET_ML_RUN_DETAILS_BREAKDOWN,
+ params: {
+ token: params.arceeToken
+ }
});
export const createMlTask = (organizationId, params) =>
@@ -2420,7 +2426,8 @@ export const getMlExecutors = (organizationId, params) =>
onSuccess: handleSuccess(SET_ML_EXECUTORS),
params: {
task_id: params.taskIds,
- run_id: params.runIds
+ run_id: params.runIds,
+ token: params.arceeToken
}
});
@@ -2449,7 +2456,8 @@ export const getMlArtifacts = (organizationId, params = {}) =>
text_like: params.textLike,
created_at_gt: params.createdAtGt,
created_at_lt: params.createdAtLt,
- task_id: params.taskId
+ task_id: params.taskId,
+ token: params.arceeToken
}
});
@@ -2840,22 +2848,23 @@ export const removeInstancesFromSchedule = (powerScheduleId, instancesToRemove)
}
});
-export const getLayouts = (organizationId, { layoutType, entityId, includeShared }) =>
+export const getLayouts = (organizationId, { layoutType, entityId, includeShared, arceeToken }) =>
apiAction({
url: `${API_URL}/organizations/${organizationId}/layouts`,
method: "GET",
- hash: hashParams({ organizationId, layoutType, entityId, includeShared }),
+ hash: hashParams({ organizationId, layoutType, entityId, includeShared, token: arceeToken }),
onSuccess: handleSuccess(SET_LAYOUTS),
label: GET_LAYOUTS,
ttl: 5 * MINUTE,
params: {
- type: layoutType,
+ layout_type: layoutType,
entity_id: entityId,
- include_shared: includeShared
+ include_shared: includeShared,
+ token: arceeToken
}
});
-export const getLayout = (organizationId, layoutId) =>
+export const getLayout = (organizationId, layoutId, params = {}) =>
apiAction({
url: `${API_URL}/organizations/${organizationId}/layouts/${layoutId}`,
method: "GET",
@@ -2863,7 +2872,10 @@ export const getLayout = (organizationId, layoutId) =>
onSuccess: handleSuccess(SET_LAYOUT),
entityId: layoutId,
label: GET_LAYOUT,
- ttl: 5 * MINUTE
+ ttl: 5 * MINUTE,
+ params: {
+ token: params.arceeToken
+ }
});
export const createLayout = (organizationId, params = {}) =>
diff --git a/ngui/ui/src/components/ArtifactsTable/ArtifactsTable.tsx b/ngui/ui/src/components/ArtifactsTable/ArtifactsTable.tsx
index bdc2f2a79..fe0cc5807 100644
--- a/ngui/ui/src/components/ArtifactsTable/ArtifactsTable.tsx
+++ b/ngui/ui/src/components/ArtifactsTable/ArtifactsTable.tsx
@@ -5,7 +5,7 @@ import { Stack } from "@mui/material";
import { FormattedMessage } from "react-intl";
import { useNavigate } from "react-router-dom";
import LinearSelector from "components/LinearSelector";
-import { TABS } from "components/MlTaskRun";
+import { TABS } from "components/MlTaskRun/Components/Tabs";
import { MlDeleteArtifactModal } from "components/SideModalManager/SideModals";
import Table from "components/Table";
import TableCellActions from "components/TableCellActions";
diff --git a/ngui/ui/src/components/ExecutionBreakdown/DashboardControls/DashboardControls.tsx b/ngui/ui/src/components/ExecutionBreakdown/DashboardControls/DashboardControls.tsx
index 3004c7d78..09b76630a 100644
--- a/ngui/ui/src/components/ExecutionBreakdown/DashboardControls/DashboardControls.tsx
+++ b/ngui/ui/src/components/ExecutionBreakdown/DashboardControls/DashboardControls.tsx
@@ -16,6 +16,7 @@ const DashboardControls = ({
updateDashboard,
createDashboard,
removeDashboard,
+ isPublicRun,
isLoadingProps = {}
}) => {
const isOwnedDashboard = currentEmployeeId === dashboard.ownerId;
@@ -49,22 +50,26 @@ const DashboardControls = ({
isLoading={isLoadingProps.isSetupLoading || isLoadingProps.isSelectNewLoading}
/>
-
- }
- onClick={onSave}
- isLoading={isLoadingProps.isSetupLoading || isLoadingProps.isSelectNewLoading}
- />
-
-
- }
- color="error"
- onClick={onDelete}
- disabled={!isOwnedDashboard || isDefaultDashboard(dashboard.id)}
- isLoading={isLoadingProps.isSetupLoading || isLoadingProps.isSelectNewLoading}
- />
-
+ {isPublicRun ? null : (
+ <>
+
+ }
+ onClick={onSave}
+ isLoading={isLoadingProps.isSetupLoading || isLoadingProps.isSelectNewLoading}
+ />
+
+
+ }
+ color="error"
+ onClick={onDelete}
+ disabled={!isOwnedDashboard || isDefaultDashboard(dashboard.id)}
+ isLoading={isLoadingProps.isSetupLoading || isLoadingProps.isSelectNewLoading}
+ />
+
+ >
+ )}
>
);
};
diff --git a/ngui/ui/src/components/ExecutionBreakdown/ExecutionBreakdown.tsx b/ngui/ui/src/components/ExecutionBreakdown/ExecutionBreakdown.tsx
index 2ff70ce14..f84bef0ae 100644
--- a/ngui/ui/src/components/ExecutionBreakdown/ExecutionBreakdown.tsx
+++ b/ngui/ui/src/components/ExecutionBreakdown/ExecutionBreakdown.tsx
@@ -8,7 +8,6 @@ import { useTheme } from "@mui/material/styles";
import { Box } from "@mui/system";
import { extent } from "d3-array";
import { FormattedNumber, useIntl } from "react-intl";
-import { useParams } from "react-router-dom";
import Button from "components/Button";
import DynamicFractionDigitsValue, { useFormatDynamicFractionDigitsValue } from "components/DynamicFractionDigitsValue";
import FormattedDigitalUnit, { IEC_UNITS, formatDigitalUnit } from "components/FormattedDigitalUnit";
@@ -59,7 +58,16 @@ const GridButton = ({ gridType, onClick }) => (
);
-const ExecutionBreakdown = ({ breakdown, milestones, reachedGoals = {}, taskId }) => {
+const ExecutionBreakdown = ({
+ organizationId,
+ isPublicRun = false,
+ arceeToken,
+ breakdown,
+ stages,
+ milestones,
+ reachedGoals = {},
+ taskId
+}) => {
const milestonesGroupedByTimeTuples = getMilestoneTuplesGroupedByTime(milestones);
const theme = useTheme();
@@ -230,18 +238,19 @@ const ExecutionBreakdown = ({ breakdown, milestones, reachedGoals = {}, taskId }
};
const openSideModal = useOpenSideModal();
- const { runId } = useParams();
const [highlightedStage, setHighlightedStage] = useState(null);
const [selectedSegment, setSelectedSegment] = useState(null);
const onStageSelectClick = () =>
openSideModal(SelectStageOrMilestoneModal, {
- runId,
highlightedStage,
setHighlightedStage,
setSelectedSegment,
- secondsTimeRange: xValuesRange
+ secondsTimeRange: xValuesRange,
+ stages,
+ milestones,
+ milestonesGroupedByTimeTuples
});
const getSelectedSegment = () => selectedSegment ?? xValuesRange;
@@ -269,9 +278,12 @@ const ExecutionBreakdown = ({ breakdown, milestones, reachedGoals = {}, taskId }
updateGridType,
isLoadingProps
} = useTaskRunChartState({
+ organizationId,
+ arceeToken,
taskId,
implementedMetricsBreakdownNames,
- breakdownNames
+ breakdownNames,
+ isPublicRun
});
const {
@@ -353,6 +365,7 @@ const ExecutionBreakdown = ({ breakdown, milestones, reachedGoals = {}, taskId }
updateDashboard={({ name, shared }) => updateDashboard({ name, shared })}
createDashboard={({ name, shared }) => createDashboard({ name, shared })}
removeDashboard={(id) => removeDashboard(id)}
+ isPublicRun={isPublicRun}
isLoadingProps={isLoadingProps}
/>
diff --git a/ngui/ui/src/components/ExecutorLabel/ExecutorLabel.tsx b/ngui/ui/src/components/ExecutorLabel/ExecutorLabel.tsx
index 3b7575905..3b3309670 100644
--- a/ngui/ui/src/components/ExecutorLabel/ExecutorLabel.tsx
+++ b/ngui/ui/src/components/ExecutorLabel/ExecutorLabel.tsx
@@ -9,24 +9,24 @@ const PLATFORM_TYPE_TO_DATA_SOURCE_TYPE = Object.freeze({
aws: AWS_CNR
});
-const DiscoveredExecutorLabel = ({ resource }) => {
+const DiscoveredExecutorLabel = ({ resource, disableLink }) => {
const { _id: id, cloud_resource_id: cloudResourceId, cloud_account: { type } = {} } = resource;
return (
}
- label={}
+ label={}
/>
);
};
-const ExecutorLabel = ({ instanceId, platformType, discovered = false, resource }) =>
+const ExecutorLabel = ({ instanceId, platformType, discovered = false, resource, disableLink = false }) =>
discovered ? (
-
+
) : (
}
- label={}
+ label={}
/>
);
diff --git a/ngui/ui/src/components/MlArtifacts/MlArtifacts.tsx b/ngui/ui/src/components/MlArtifacts/MlArtifacts.tsx
index a98f1e79b..fea17f5da 100644
--- a/ngui/ui/src/components/MlArtifacts/MlArtifacts.tsx
+++ b/ngui/ui/src/components/MlArtifacts/MlArtifacts.tsx
@@ -5,9 +5,12 @@ import ActionBar from "components/ActionBar";
import ArtifactsTable from "components/ArtifactsTable";
import PageContentWrapper from "components/PageContentWrapper";
import MlArtifactsContainer from "containers/MlArtifactsContainer";
+import { useOrganizationInfo } from "hooks/useOrganizationInfo";
import { useRefetchApis } from "hooks/useRefetchApis";
const MlArtifacts = ({ tasks, isLoading = false }) => {
+ const { organizationId } = useOrganizationInfo();
+
const refetch = useRefetchApis();
const actionBarDefinition = {
@@ -33,6 +36,7 @@ const MlArtifacts = ({ tasks, isLoading = false }) => {
(
{
+const MlExecutorsTable = ({
+ executors,
+ withExpenses = false,
+ disableExecutorLink = false,
+ disableLocationLink = false,
+ isLoading = false
+}) => {
const memoizedExecutors = useMemo(() => executors, [executors]);
- const isFinOpsEnabled = useIsOptScaleModeEnabled(OPTSCALE_MODE.FINOPS);
-
const columns = useMemo(
- () => [
- executor(),
- mlExecutorLocation(),
- ...(isFinOpsEnabled
- ? [
- expenses({
- id: "expenses",
- headerDataTestId: "lbl_expenses",
- headerMessageId: "expenses",
- accessorFn: (rowData) => rowData.resource?.total_cost
- })
- ]
- : []),
- lastUsed({ headerDataTestId: "lbl_last_used", accessorFn: (rowData) => rowData.last_used }),
- firstSeen({ headerDataTestId: "lbl_first_seen", accessorFn: (rowData) => rowData.resource?.first_seen })
- ],
- [isFinOpsEnabled]
+ () =>
+ getColumns({
+ withExpenses,
+ disableExecutorLink,
+ disableLocationLink
+ }),
+ [disableExecutorLink, disableLocationLink, withExpenses]
);
return isLoading ? (
diff --git a/ngui/ui/src/components/MlExecutorsTable/utils.ts b/ngui/ui/src/components/MlExecutorsTable/utils.ts
new file mode 100644
index 000000000..0260bffe6
--- /dev/null
+++ b/ngui/ui/src/components/MlExecutorsTable/utils.ts
@@ -0,0 +1,23 @@
+import { lastUsed, firstSeen, mlExecutorLocation, expenses } from "utils/columns";
+import executor from "utils/columns/executor";
+
+export const getColumns = ({ withExpenses = false, disableExecutorLink = false, disableLocationLink = false } = {}) => [
+ executor({
+ disableLink: disableExecutorLink
+ }),
+ mlExecutorLocation({
+ disableLink: disableLocationLink
+ }),
+ ...(withExpenses
+ ? [
+ expenses({
+ id: "expenses",
+ headerDataTestId: "lbl_expenses",
+ headerMessageId: "expenses",
+ accessorFn: (rowData) => rowData.resource?.total_cost
+ })
+ ]
+ : []),
+ lastUsed({ headerDataTestId: "lbl_last_used", accessorFn: (rowData) => rowData.last_used }),
+ firstSeen({ headerDataTestId: "lbl_first_seen", accessorFn: (rowData) => rowData.resource?.first_seen })
+];
diff --git a/ngui/ui/src/components/MlTaskRun/Components/Charts/Charts.tsx b/ngui/ui/src/components/MlTaskRun/Components/Charts/Charts.tsx
new file mode 100644
index 000000000..d55bb3705
--- /dev/null
+++ b/ngui/ui/src/components/MlTaskRun/Components/Charts/Charts.tsx
@@ -0,0 +1,56 @@
+import { useMemo } from "react";
+import { useParams } from "react-router-dom";
+import ExecutionBreakdown, { ExecutionBreakdownLoader } from "components/ExecutionBreakdown";
+import MlTasksService from "services/MlTasksService";
+import { getData } from "./utils";
+
+const Charts = ({
+ run,
+ organizationId,
+ arceeToken,
+ isPublicRun = false,
+ isTaskRunLoading = false,
+ isTaskRunDataReady = false
+}) => {
+ const { useGetRunBreakdown } = MlTasksService();
+
+ const { runId } = useParams();
+
+ const runBreakdownParams = useMemo(
+ () => ({
+ arceeToken
+ }),
+ [arceeToken]
+ );
+
+ const {
+ isLoading: isGetRunBreakdownLoading,
+ isDataReady: isGetRunBreakdownDataReady,
+ breakdown: apiBreakdown = {},
+ milestones: apiMilestones = [],
+ stages: apiStages = []
+ } = useGetRunBreakdown(organizationId, runId, runBreakdownParams);
+
+ if (isGetRunBreakdownLoading || !isGetRunBreakdownDataReady || isTaskRunLoading || !isTaskRunDataReady) {
+ return ;
+ }
+
+ const { breakdown, milestones, stages } = getData({ breakdown: apiBreakdown, milestones: apiMilestones, stages: apiStages });
+
+ const { reached_goals: reachedGoals = [], task: { id: taskId } = {} } = run;
+
+ return (
+
+ );
+};
+
+export default Charts;
diff --git a/ngui/ui/src/containers/ExecutionBreakdownContainer/utils.ts b/ngui/ui/src/components/MlTaskRun/Components/Charts/utils.ts
similarity index 100%
rename from ngui/ui/src/containers/ExecutionBreakdownContainer/utils.ts
rename to ngui/ui/src/components/MlTaskRun/Components/Charts/utils.ts
diff --git a/ngui/ui/src/components/MlTaskRun/Components/Executors.tsx b/ngui/ui/src/components/MlTaskRun/Components/Executors.tsx
deleted file mode 100644
index dc269c18a..000000000
--- a/ngui/ui/src/components/MlTaskRun/Components/Executors.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { useMemo } from "react";
-import { useParams } from "react-router-dom";
-import MlExecutorsTable from "components/MlExecutorsTable";
-import MlExecutorsService from "services/MlExecutorsService";
-
-const Executors = () => {
- const { runId } = useParams();
-
- const { useGet } = MlExecutorsService();
-
- const runIds = useMemo(() => [runId], [runId]);
-
- const { isLoading, executors } = useGet({ runIds });
-
- return ;
-};
-
-export default Executors;
diff --git a/ngui/ui/src/components/MlTaskRun/Components/Executors/Executors.tsx b/ngui/ui/src/components/MlTaskRun/Components/Executors/Executors.tsx
new file mode 100644
index 000000000..92d6228a8
--- /dev/null
+++ b/ngui/ui/src/components/MlTaskRun/Components/Executors/Executors.tsx
@@ -0,0 +1,33 @@
+import { useMemo } from "react";
+import { useParams } from "react-router-dom";
+import MlExecutorsTable from "components/MlExecutorsTable";
+import MlExecutorsService from "services/MlExecutorsService";
+
+type ExecutorsProps = {
+ organizationId: string;
+ withExpenses: boolean;
+ isPublicRun: boolean;
+ arceeToken: string;
+};
+
+const Executors = ({ organizationId, withExpenses, isPublicRun, arceeToken }: ExecutorsProps) => {
+ const { runId } = useParams();
+
+ const { useGet } = MlExecutorsService();
+
+ const runIds = useMemo(() => [runId], [runId]);
+
+ const { isLoading, executors } = useGet({ runIds, organizationId, arceeToken });
+
+ return (
+
+ );
+};
+
+export default Executors;
diff --git a/ngui/ui/src/components/MlTaskRun/Components/Overview.tsx b/ngui/ui/src/components/MlTaskRun/Components/Overview/Overview.tsx
similarity index 74%
rename from ngui/ui/src/components/MlTaskRun/Components/Overview.tsx
rename to ngui/ui/src/components/MlTaskRun/Components/Overview/Overview.tsx
index 885cf0bf3..0939ebdb6 100644
--- a/ngui/ui/src/components/MlTaskRun/Components/Overview.tsx
+++ b/ngui/ui/src/components/MlTaskRun/Components/Overview/Overview.tsx
@@ -197,63 +197,67 @@ const StderrLog = ({ error, isLoading }) => {
return ;
};
-const Overview = ({ reachedGoals, dataset, git, tags, hyperparameters, command, console, isLoading = false }) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+const Overview = ({ run, isLoading = false }) => {
+ const { reached_goals: reachedGoals, dataset, tags, hyperparameters, git, command, console } = run;
+
+ return (
+
+
+
+
+
+
+
+
-
+
-
-
-
+
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-);
+ );
+};
export default Overview;
diff --git a/ngui/ui/src/components/MlTaskRun/Components/Status.tsx b/ngui/ui/src/components/MlTaskRun/Components/Status.tsx
deleted file mode 100644
index cbf5a1e7a..000000000
--- a/ngui/ui/src/components/MlTaskRun/Components/Status.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import FormattedDuration from "components/FormattedDuration";
-import MlRunStatus from "components/MlRunStatus";
-import SummaryGrid from "components/SummaryGrid";
-import { useIsOptScaleModeEnabled } from "hooks/useIsOptScaleModeEnabled";
-import { ML_RUN_STATUS, OPTSCALE_MODE, SUMMARY_VALUE_COMPONENT_TYPES } from "utils/constants";
-
-const Status = ({ cost, status, duration, isLoading = false }) => {
- const isFinOpsEnabled = useIsOptScaleModeEnabled(OPTSCALE_MODE.FINOPS);
-
- return (
- status !== undefined,
- isLoading,
- dataTestIds: {
- cardTestId: "card_run_status"
- }
- },
- {
- key: "duration",
- valueComponentType: SUMMARY_VALUE_COMPONENT_TYPES.Custom,
- CustomValueComponent: FormattedDuration,
- valueComponentProps: {
- durationInSeconds: duration
- },
- renderCondition: () => status !== ML_RUN_STATUS.FAILED,
- captionMessageId: "duration",
- isLoading,
- dataTestIds: {
- cardTestId: "card_run_duration"
- }
- },
- {
- key: "cost",
- valueComponentType: SUMMARY_VALUE_COMPONENT_TYPES.FormattedMoney,
- valueComponentProps: {
- value: cost
- },
- captionMessageId: "expenses",
- dataTestIds: {
- cardTestId: "card_expenses"
- },
- isLoading,
- renderCondition: () => isFinOpsEnabled
- }
- ]}
- />
- );
-};
-
-export default Status;
diff --git a/ngui/ui/src/components/MlTaskRun/Components/Status/Status.tsx b/ngui/ui/src/components/MlTaskRun/Components/Status/Status.tsx
new file mode 100644
index 000000000..fde292b08
--- /dev/null
+++ b/ngui/ui/src/components/MlTaskRun/Components/Status/Status.tsx
@@ -0,0 +1,58 @@
+import FormattedDuration from "components/FormattedDuration";
+import MlRunStatus from "components/MlRunStatus";
+import SummaryGrid from "components/SummaryGrid";
+import { ML_RUN_STATUS, SUMMARY_VALUE_COMPONENT_TYPES } from "utils/constants";
+
+const StatusSummaryGrid = ({ cost, status, duration, withCost = false, isLoading = false }) => (
+ status !== undefined,
+ isLoading,
+ dataTestIds: {
+ cardTestId: "card_run_status"
+ }
+ },
+ {
+ key: "duration",
+ valueComponentType: SUMMARY_VALUE_COMPONENT_TYPES.Custom,
+ CustomValueComponent: FormattedDuration,
+ valueComponentProps: {
+ durationInSeconds: duration
+ },
+ renderCondition: () => status !== ML_RUN_STATUS.FAILED,
+ captionMessageId: "duration",
+ isLoading,
+ dataTestIds: {
+ cardTestId: "card_run_duration"
+ }
+ },
+ {
+ key: "cost",
+ valueComponentType: SUMMARY_VALUE_COMPONENT_TYPES.FormattedMoney,
+ valueComponentProps: {
+ value: cost
+ },
+ captionMessageId: "expenses",
+ dataTestIds: {
+ cardTestId: "card_expenses"
+ },
+ isLoading,
+ renderCondition: () => withCost
+ }
+ ]}
+ />
+);
+
+export default StatusSummaryGrid;
diff --git a/ngui/ui/src/components/MlTaskRun/Components/Tabs.tsx b/ngui/ui/src/components/MlTaskRun/Components/Tabs.tsx
new file mode 100644
index 000000000..7df28ec22
--- /dev/null
+++ b/ngui/ui/src/components/MlTaskRun/Components/Tabs.tsx
@@ -0,0 +1,52 @@
+import { useState } from "react";
+import TabsWrapper from "components/TabsWrapper";
+
+export const TABS = Object.freeze({
+ OVERVIEW: "overview",
+ ARTIFACTS: "artifacts",
+ CHARTS: "charts",
+ EXECUTORS: "executors"
+});
+
+const Tabs = ({ overviewTab, chartsTab, artifactsTab, executorsTab }) => {
+ const [activeTab, setActiveTab] = useState();
+
+ const tabs = [
+ {
+ title: TABS.OVERVIEW,
+ dataTestId: "tab_overview",
+ node: overviewTab
+ },
+ {
+ title: TABS.CHARTS,
+ dataTestId: "tab_charts",
+ node: chartsTab
+ },
+ {
+ title: TABS.ARTIFACTS,
+ dataTestId: "tab_artifact",
+ node: artifactsTab
+ },
+ {
+ title: TABS.EXECUTORS,
+ dataTestId: "tab_executors",
+ node: executorsTab
+ }
+ ];
+
+ return (
+ {
+ setActiveTab(value);
+ }
+ }}
+ />
+ );
+};
+
+export default Tabs;
diff --git a/ngui/ui/src/components/MlTaskRun/Components/index.ts b/ngui/ui/src/components/MlTaskRun/Components/index.ts
index 96ae224f5..34f94c6e8 100644
--- a/ngui/ui/src/components/MlTaskRun/Components/index.ts
+++ b/ngui/ui/src/components/MlTaskRun/Components/index.ts
@@ -1,4 +1,7 @@
-import Executors from "./Executors";
-import Overview from "./Overview";
+import Charts from "./Charts/Charts";
+import Executors from "./Executors/Executors";
+import Overview from "./Overview/Overview";
+import Status from "./Status/Status";
+import Tabs from "./Tabs";
-export { Overview, Executors };
+export { Overview, Executors, Tabs, Status, Charts };
diff --git a/ngui/ui/src/components/MlTaskRun/MlTaskRun.tsx b/ngui/ui/src/components/MlTaskRun/MlTaskRun.tsx
index 9a17e0916..e604a8d19 100644
--- a/ngui/ui/src/components/MlTaskRun/MlTaskRun.tsx
+++ b/ngui/ui/src/components/MlTaskRun/MlTaskRun.tsx
@@ -1,96 +1,53 @@
-import { useState } from "react";
import RefreshOutlinedIcon from "@mui/icons-material/RefreshOutlined";
+import ShareOutlinedIcon from "@mui/icons-material/ShareOutlined";
import { Link, Stack, Typography } from "@mui/material";
import { FormattedMessage } from "react-intl";
import { Link as RouterLink } from "react-router-dom";
import { GET_ML_ARTIFACTS, GET_ML_EXECUTORS, GET_ML_RUN_DETAILS, GET_ML_RUN_DETAILS_BREAKDOWN } from "api/restapi/actionTypes";
import ActionBar from "components/ActionBar";
import PageContentWrapper from "components/PageContentWrapper";
-import TabsWrapper from "components/TabsWrapper";
-import ExecutionBreakdownContainer from "containers/ExecutionBreakdownContainer";
+import { ShareRunLinkModal } from "components/SideModalManager/SideModals";
import RunArtifactsContainer from "containers/RunArtifactsContainer";
+import { useOpenSideModal } from "hooks/useOpenSideModal";
import { useRefetchApis } from "hooks/useRefetchApis";
import { ML_TASKS, getMlTaskDetailsUrl } from "urls";
import { SPACING_2 } from "utils/layouts";
import { formatRunFullName } from "utils/ml";
-import { Executors, Overview } from "./Components";
-import Status from "./Components/Status";
+import { Charts, Executors, Overview, Status, Tabs } from "./Components";
-export const TABS = Object.freeze({
- OVERVIEW: "overview",
- ARTIFACTS: "artifacts",
- CHARTS: "charts",
- EXECUTORS: "executors"
-});
-
-const Tabs = ({ run, isLoading = false }) => {
- const [activeTab, setActiveTab] = useState();
-
- const tabs = [
- {
- title: TABS.OVERVIEW,
- dataTestId: "tab_overview",
- node: (
-
- )
- },
- {
- title: TABS.CHARTS,
- dataTestId: "tab_charts",
- node:
- },
- {
- title: TABS.ARTIFACTS,
- dataTestId: "tab_artifact",
- node:
- },
- {
- title: TABS.EXECUTORS,
- dataTestId: "tab_executors",
- node:
- }
- ];
-
- return (
- {
- setActiveTab(value);
- }
- }}
- />
- );
-};
-
-const MlTaskRun = ({ run, isLoading = false }) => {
+const MlTaskRun = ({
+ run,
+ organizationId,
+ arceeToken,
+ isFinOpsEnabled = false,
+ isPublicRun = false,
+ isLoading = false,
+ isDataReady = false
+}) => {
const { task: { id: taskId, name: taskName } = {}, name: runName, number } = run;
const refetch = useRefetchApis();
+ const openSideModal = useOpenSideModal();
+
const actionBarDefinition = {
breadcrumbs: [
-
-
- ,
-
- {taskName}
- ,
+ isPublicRun ? (
+
+
+
+ ) : (
+
+
+
+ ),
+ isPublicRun ? (
+ {taskName}
+ ) : (
+
+ {taskName}
+
+ ),
],
title: {
@@ -105,20 +62,67 @@ const MlTaskRun = ({ run, isLoading = false }) => {
dataTestId: "btn_refresh",
type: "button",
action: () => refetch([GET_ML_RUN_DETAILS, GET_ML_EXECUTORS, GET_ML_RUN_DETAILS_BREAKDOWN, GET_ML_ARTIFACTS])
- }
+ },
+ ...(isPublicRun
+ ? []
+ : [
+ {
+ key: "btn-share",
+ icon: ,
+ messageId: "share",
+ dataTestId: "btn_share",
+ type: "button",
+ isLoading,
+ action: () => {
+ openSideModal(ShareRunLinkModal, {
+ runId: run.id
+ });
+ }
+ }
+ ])
]
};
+ const overviewTab = ;
+
+ const chartsTab = (
+
+ );
+
+ const artifactsTab = ;
+
+ const executorsTab = (
+
+ );
+
return (
<>
-
+
-
+
diff --git a/ngui/ui/src/components/MlTaskRun/index.ts b/ngui/ui/src/components/MlTaskRun/index.ts
index d47d7e1b4..f5510c69d 100644
--- a/ngui/ui/src/components/MlTaskRun/index.ts
+++ b/ngui/ui/src/components/MlTaskRun/index.ts
@@ -1,4 +1,3 @@
-import MlTaskRun, { TABS } from "./MlTaskRun";
+import MlTaskRun from "./MlTaskRun";
-export { TABS };
export default MlTaskRun;
diff --git a/ngui/ui/src/components/ShareRunLink/ShareRunLink.tsx b/ngui/ui/src/components/ShareRunLink/ShareRunLink.tsx
new file mode 100644
index 000000000..2b7cb4f75
--- /dev/null
+++ b/ngui/ui/src/components/ShareRunLink/ShareRunLink.tsx
@@ -0,0 +1,37 @@
+import { Stack } from "@mui/material";
+import { FormattedMessage } from "react-intl";
+import CodeBlock from "components/CodeBlock";
+import Skeleton from "components/Skeleton";
+import { getMlPublicRunUrl } from "urls";
+import { SPACING_1 } from "utils/layouts";
+
+type ShareRunLinkProps = {
+ runId: string;
+ arceeToken: string;
+ organizationId: string;
+ isLoading?: boolean;
+};
+
+const ShareRunLink = ({ runId, arceeToken, organizationId, isLoading = false }: ShareRunLinkProps) => {
+ const route = getMlPublicRunUrl(runId, { organizationId, arceeToken });
+ const link = `${window.location.origin}${route}`;
+
+ return (
+
+
+
+
+
+ {isLoading ? (
+
+
+
+ ) : (
+
+ )}
+
+
+ );
+};
+
+export default ShareRunLink;
diff --git a/ngui/ui/src/components/ShareRunLink/index.ts b/ngui/ui/src/components/ShareRunLink/index.ts
new file mode 100644
index 000000000..3a3874d50
--- /dev/null
+++ b/ngui/ui/src/components/ShareRunLink/index.ts
@@ -0,0 +1,3 @@
+import ShareRunLink from "./ShareRunLink";
+
+export default ShareRunLink;
diff --git a/ngui/ui/src/components/SideModalManager/SideModals/SelectStageOrMilestoneModal.tsx b/ngui/ui/src/components/SideModalManager/SideModals/SelectStageOrMilestoneModal.tsx
index 881a6024c..edcd5c09c 100644
--- a/ngui/ui/src/components/SideModalManager/SideModals/SelectStageOrMilestoneModal.tsx
+++ b/ngui/ui/src/components/SideModalManager/SideModals/SelectStageOrMilestoneModal.tsx
@@ -1,4 +1,4 @@
-import StagesAndMilestonesContainer from "containers/StagesAndMilestonesContainer";
+import StagesAndMilestones from "components/StagesAndMilestones";
import BaseSideModal from "./BaseSideModal";
class SelectStageOrMilestoneModal extends BaseSideModal {
@@ -13,7 +13,31 @@ class SelectStageOrMilestoneModal extends BaseSideModal {
dataTestId = "smodal_select_stage_or_milestone";
get content() {
- return ;
+ const {
+ highlightedStage,
+ setHighlightedStage,
+ setSelectedSegment,
+ secondsTimeRange,
+ stages,
+ milestonesGroupedByTimeTuples
+ } = this.payload;
+
+ return (
+ {
+ setSelectedSegment([start, end]);
+ this.closeSideModal();
+ }}
+ stages={stages}
+ highlightedStage={highlightedStage}
+ setHighlightedStage={(stage) => {
+ setHighlightedStage(stage);
+ this.closeSideModal();
+ }}
+ secondsTimeRange={secondsTimeRange}
+ />
+ );
}
}
diff --git a/ngui/ui/src/components/SideModalManager/SideModals/ShareRunLinkModal.tsx b/ngui/ui/src/components/SideModalManager/SideModals/ShareRunLinkModal.tsx
new file mode 100644
index 000000000..74d3a471d
--- /dev/null
+++ b/ngui/ui/src/components/SideModalManager/SideModals/ShareRunLinkModal.tsx
@@ -0,0 +1,20 @@
+import ShareRunLinkContainer from "containers/ShareRunLinkContainer";
+import BaseSideModal from "./BaseSideModal";
+
+class ShareRunLinkModal extends BaseSideModal {
+ headerProps = {
+ messageId: "shareRunLinkTitle",
+ dataTestIds: {
+ title: "lbl_share_run_link",
+ closeButton: "btn_close"
+ }
+ };
+
+ dataTestId = "smodal_share_run_link";
+
+ get content() {
+ return ;
+ }
+}
+
+export default ShareRunLinkModal;
diff --git a/ngui/ui/src/components/SideModalManager/SideModals/index.ts b/ngui/ui/src/components/SideModalManager/SideModals/index.ts
index dde56a107..2fb2948bc 100644
--- a/ngui/ui/src/components/SideModalManager/SideModals/index.ts
+++ b/ngui/ui/src/components/SideModalManager/SideModals/index.ts
@@ -60,6 +60,7 @@ import S3DuplicateFinderSettingsModal from "./S3DuplicateFinderSettingsModal";
import SaveMlChartsDashboard from "./SaveMlChartsDashboard";
import SelectedBucketsInfoModal from "./SelectedBucketsInfoModal";
import SelectStageOrMilestoneModal from "./SelectStageOrMilestoneModal";
+import ShareRunLinkModal from "./ShareRunLinkModal";
import ShareSettingsModal from "./ShareSettingsModal";
import SlackIntegrationModal from "./SlackIntegrationModal";
import UnmarkEnvironmentModal from "./UnmarkEnvironmentModal";
@@ -135,5 +136,6 @@ export {
EditModelPathModal,
EditModelVersionTagsModal,
MlDeleteArtifactModal,
- DataSourceBillingReimportModal
+ DataSourceBillingReimportModal,
+ ShareRunLinkModal
};
diff --git a/ngui/ui/src/containers/ColumnSetsContainer/ColumnSetsContainer.tsx b/ngui/ui/src/containers/ColumnSetsContainer/ColumnSetsContainer.tsx
index 80d197ad9..0ff43ca17 100644
--- a/ngui/ui/src/containers/ColumnSetsContainer/ColumnSetsContainer.tsx
+++ b/ngui/ui/src/containers/ColumnSetsContainer/ColumnSetsContainer.tsx
@@ -1,14 +1,18 @@
import { useCallback } from "react";
import ColumnSets from "components/ColumnSets";
import { getHideableColumns } from "components/Table/utils";
+import { useOrganizationInfo } from "hooks/useOrganizationInfo";
import LayoutsService from "services/LayoutsService";
import { LAYOUT_TYPES } from "utils/constants";
const ColumnSetsContainer = ({ tableContext, closeSideModal }) => {
+ const { organizationId } = useOrganizationInfo();
+
const { useGetAll, useDelete, useGetOneOnDemand } = LayoutsService();
const { onDelete, isLoading: isDeleteLayoutLoading, entityId: deletionEntityId } = useDelete();
const { isLoading: isGetAllLayoutsLoading, layouts } = useGetAll({
+ organizationId,
layoutType: LAYOUT_TYPES.RESOURCE_RAW_EXPENSES_COLUMNS
});
@@ -21,7 +25,7 @@ const ColumnSetsContainer = ({ tableContext, closeSideModal }) => {
columnSets={layouts}
tableContext={tableContext}
onApply={(columnsSetId) =>
- onGet(columnsSetId).then(({ data }) => {
+ onGet(organizationId, columnsSetId).then(({ data }) => {
const { columns: savedColumns } = JSON.parse(data);
tableContext.setColumnVisibility(
diff --git a/ngui/ui/src/containers/CreateColumnSetFormContainer/CreateColumnSetFormContainer.tsx b/ngui/ui/src/containers/CreateColumnSetFormContainer/CreateColumnSetFormContainer.tsx
index 133af7efc..a62909b15 100644
--- a/ngui/ui/src/containers/CreateColumnSetFormContainer/CreateColumnSetFormContainer.tsx
+++ b/ngui/ui/src/containers/CreateColumnSetFormContainer/CreateColumnSetFormContainer.tsx
@@ -1,16 +1,20 @@
import CreateColumnSetForm from "components/forms/CreateColumnSetForm";
import { getVisibleColumnIds } from "components/Table/utils";
+import { useOrganizationInfo } from "hooks/useOrganizationInfo";
import LayoutsService from "services/LayoutsService";
import { LAYOUT_TYPES } from "utils/constants";
const CreateColumnSetFormContainer = ({ tableContext }) => {
const { useCreate } = LayoutsService();
+
+ const { organizationId } = useOrganizationInfo();
+
const { onCreate, isLoading: isCreateLayoutLoading } = useCreate();
const createColumnSet = (name: string) => {
const visibleColumnIds = getVisibleColumnIds(tableContext);
- return onCreate({
+ return onCreate(organizationId, {
name,
data: JSON.stringify({
columns: visibleColumnIds
diff --git a/ngui/ui/src/containers/ExecutionBreakdownContainer/ExecutionBreakdownContainer.tsx b/ngui/ui/src/containers/ExecutionBreakdownContainer/ExecutionBreakdownContainer.tsx
deleted file mode 100644
index 3764d036d..000000000
--- a/ngui/ui/src/containers/ExecutionBreakdownContainer/ExecutionBreakdownContainer.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { useParams } from "react-router-dom";
-import ExecutionBreakdown, { ExecutionBreakdownLoader } from "components/ExecutionBreakdown";
-import MlTasksService from "services/MlTasksService";
-import { getData } from "./utils";
-
-const ExecutionBreakdownContainer = ({ reachedGoals, ...rest }) => {
- const { useGetRunBreakdown, useGetTaskRun } = MlTasksService();
-
- const { taskId, runId } = useParams();
-
- const {
- isLoading: isGetRunBreakdownLoading,
- isDataReady: isGetRunBreakdownDataReady,
- breakdown = {},
- milestones = [],
- stages = []
- } = useGetRunBreakdown(runId);
-
- const { isLoading: isTaskRunLoading, isDataReady: isTaskRunDataReady } = useGetTaskRun(runId);
-
- return isGetRunBreakdownLoading || !isGetRunBreakdownDataReady || isTaskRunLoading || !isTaskRunDataReady ? (
-
- ) : (
-
- );
-};
-
-export default ExecutionBreakdownContainer;
diff --git a/ngui/ui/src/containers/ExecutionBreakdownContainer/index.ts b/ngui/ui/src/containers/ExecutionBreakdownContainer/index.ts
deleted file mode 100644
index 210a13f9a..000000000
--- a/ngui/ui/src/containers/ExecutionBreakdownContainer/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import ExecutionBreakdownContainer from "./ExecutionBreakdownContainer";
-import { getData } from "./utils";
-
-export { getData };
-
-export default ExecutionBreakdownContainer;
diff --git a/ngui/ui/src/containers/MlArtifactsContainer/MlArtifactsContainer.tsx b/ngui/ui/src/containers/MlArtifactsContainer/MlArtifactsContainer.tsx
index c86cf9004..1d0b9ece6 100644
--- a/ngui/ui/src/containers/MlArtifactsContainer/MlArtifactsContainer.tsx
+++ b/ngui/ui/src/containers/MlArtifactsContainer/MlArtifactsContainer.tsx
@@ -54,8 +54,10 @@ export type TasksFilter = {
};
type MlArtifactsContainerProps = {
+ organizationId: string;
runId?: string | string[];
tasks?: { id: string; name: string }[];
+ arceeToken?: string;
isLoading?: boolean;
render: (props: {
artifacts: Artifact[];
@@ -99,7 +101,14 @@ const getRangeQueryParams = (minRange: number, maxRange: number) => {
return [minRange, maxRange] as const;
};
-const MlArtifactsContainer = ({ runId, tasks = [], isLoading = false, render }: MlArtifactsContainerProps) => {
+const MlArtifactsContainer = ({
+ organizationId,
+ runId,
+ tasks = [],
+ arceeToken,
+ isLoading = false,
+ render
+}: MlArtifactsContainerProps) => {
const { useGet } = MlArtifactsService();
const [pageIndex, setPageIndex] = useState(getDefaultPageIndexValue());
@@ -149,9 +158,10 @@ const MlArtifactsContainer = ({ runId, tasks = [], isLoading = false, render }:
textLike: searchValue,
createdAtGt: debouncedRange[0],
createdAtLt: debouncedRange[1],
- taskId: appliedFilters[TASKS_FILTER]
+ taskId: appliedFilters[TASKS_FILTER],
+ arceeToken
}),
- [pageIndex, runId, searchValue, debouncedRange, appliedFilters]
+ [pageIndex, runId, searchValue, debouncedRange, appliedFilters, arceeToken]
);
const onSearchChange = (newSearch: string) => {
@@ -177,7 +187,7 @@ const MlArtifactsContainer = ({ runId, tasks = [], isLoading = false, render }:
});
}, [pageIndex, debouncedRange, searchValue, appliedFilters]);
- const { isLoading: isGetArtifactsLoading, data } = useGet(params);
+ const { isLoading: isGetArtifactsLoading, data } = useGet(organizationId, params);
const totalArtifactsCount = data?.total_count ?? 0;
diff --git a/ngui/ui/src/containers/MlCreateRunArtifactContainer/MlCreateRunArtifactContainer.tsx b/ngui/ui/src/containers/MlCreateRunArtifactContainer/MlCreateRunArtifactContainer.tsx
index fa980fd11..db5206f21 100644
--- a/ngui/ui/src/containers/MlCreateRunArtifactContainer/MlCreateRunArtifactContainer.tsx
+++ b/ngui/ui/src/containers/MlCreateRunArtifactContainer/MlCreateRunArtifactContainer.tsx
@@ -3,7 +3,7 @@ import { FormattedMessage } from "react-intl";
import { useParams, Link as RouterLink, useNavigate } from "react-router-dom";
import ActionBar from "components/ActionBar";
import { MlCreateArtifactForm } from "components/forms/MlArtifactForm";
-import { TABS } from "components/MlTaskRun";
+import { TABS } from "components/MlTaskRun/Components/Tabs";
import PageContentWrapper from "components/PageContentWrapper";
import MlArtifactsService from "services/MlArtifactsService";
import MlTasksService from "services/MlTasksService";
diff --git a/ngui/ui/src/containers/MlEditRunArtifactContainer/MlEditRunArtifactContainer.tsx b/ngui/ui/src/containers/MlEditRunArtifactContainer/MlEditRunArtifactContainer.tsx
index a2ac9016f..7b2d585e7 100644
--- a/ngui/ui/src/containers/MlEditRunArtifactContainer/MlEditRunArtifactContainer.tsx
+++ b/ngui/ui/src/containers/MlEditRunArtifactContainer/MlEditRunArtifactContainer.tsx
@@ -3,7 +3,7 @@ import { FormattedMessage } from "react-intl";
import { useParams, Link as RouterLink, useNavigate } from "react-router-dom";
import ActionBar from "components/ActionBar";
import { MlEditArtifactForm } from "components/forms/MlArtifactForm";
-import { TABS } from "components/MlTaskRun";
+import { TABS } from "components/MlTaskRun/Components/Tabs";
import PageContentWrapper from "components/PageContentWrapper";
import MlArtifactsService from "services/MlArtifactsService";
import MlTasksService from "services/MlTasksService";
diff --git a/ngui/ui/src/containers/MlExecutorsContainer/MlExecutorsContainer.tsx b/ngui/ui/src/containers/MlExecutorsContainer/MlExecutorsContainer.tsx
index 5c861110e..19d98afb0 100644
--- a/ngui/ui/src/containers/MlExecutorsContainer/MlExecutorsContainer.tsx
+++ b/ngui/ui/src/containers/MlExecutorsContainer/MlExecutorsContainer.tsx
@@ -1,5 +1,7 @@
import MlExecutorsTable from "components/MlExecutorsTable";
+import { useIsOptScaleModeEnabled } from "hooks/useIsOptScaleModeEnabled";
import MlExecutorsService from "services/MlExecutorsService";
+import { OPTSCALE_MODE } from "utils/constants";
import { inDateRange, secondsToMilliseconds } from "utils/datetime";
const MlExecutorsContainer = ({ dateRange }) => {
@@ -9,7 +11,9 @@ const MlExecutorsContainer = ({ dateRange }) => {
const { useGet } = MlExecutorsService();
const { isLoading, executors } = useGet();
- return ;
+ const isFinOpsEnabled = useIsOptScaleModeEnabled(OPTSCALE_MODE.FINOPS);
+
+ return ;
};
export default MlExecutorsContainer;
diff --git a/ngui/ui/src/containers/MlTaskExecutorsContainer/MlTaskExecutorsContainer.tsx b/ngui/ui/src/containers/MlTaskExecutorsContainer/MlTaskExecutorsContainer.tsx
index e1f086078..c8fabac79 100644
--- a/ngui/ui/src/containers/MlTaskExecutorsContainer/MlTaskExecutorsContainer.tsx
+++ b/ngui/ui/src/containers/MlTaskExecutorsContainer/MlTaskExecutorsContainer.tsx
@@ -1,7 +1,9 @@
import { useMemo } from "react";
import { useParams } from "react-router-dom";
import MlExecutorsTable from "components/MlExecutorsTable";
+import { useIsOptScaleModeEnabled } from "hooks/useIsOptScaleModeEnabled";
import MlExecutorsService from "services/MlExecutorsService";
+import { OPTSCALE_MODE } from "utils/constants";
const MlTaskExecutorsContainer = () => {
const { taskId } = useParams();
@@ -12,6 +14,8 @@ const MlTaskExecutorsContainer = () => {
const { isLoading, executors = [] } = useGet({ taskIds });
- return ;
+ const isFinOpsEnabled = useIsOptScaleModeEnabled(OPTSCALE_MODE.FINOPS);
+
+ return ;
};
export default MlTaskExecutorsContainer;
diff --git a/ngui/ui/src/containers/MlTaskRunContainer/MlTaskRunContainer.tsx b/ngui/ui/src/containers/MlTaskRunContainer/MlTaskRunContainer.tsx
index ff33cc872..4bb198103 100644
--- a/ngui/ui/src/containers/MlTaskRunContainer/MlTaskRunContainer.tsx
+++ b/ngui/ui/src/containers/MlTaskRunContainer/MlTaskRunContainer.tsx
@@ -1,15 +1,18 @@
import { useParams } from "react-router-dom";
import MlTaskRun from "components/MlTaskRun";
+import { useOrganizationInfo } from "hooks/useOrganizationInfo";
import MlTasksService from "services/MlTasksService";
const MlTaskRunContainer = () => {
const { runId } = useParams();
+ const { organizationId } = useOrganizationInfo();
+
const { useGetTaskRun } = MlTasksService();
- const { isLoading, run } = useGetTaskRun(runId);
+ const { isLoading, isDataReady, run } = useGetTaskRun(organizationId, runId);
- return ;
+ return ;
};
export default MlTaskRunContainer;
diff --git a/ngui/ui/src/containers/PublicMlRunContainer/PublicMlRunContainer.tsx b/ngui/ui/src/containers/PublicMlRunContainer/PublicMlRunContainer.tsx
new file mode 100644
index 000000000..56e458f75
--- /dev/null
+++ b/ngui/ui/src/containers/PublicMlRunContainer/PublicMlRunContainer.tsx
@@ -0,0 +1,48 @@
+import { useMemo } from "react";
+import { useTheme } from "@mui/material/styles";
+import { useParams } from "react-router-dom";
+import MlTaskRun from "components/MlTaskRun";
+import MlTasksService from "services/MlTasksService";
+import { getQueryParams } from "utils/network";
+
+const PublicMlRunContainer = () => {
+ const theme = useTheme();
+
+ const { useGetTaskRun } = MlTasksService();
+
+ const { runId } = useParams();
+
+ const { organizationId, token: arceeToken } = getQueryParams() as {
+ organizationId: string;
+ token: string;
+ };
+
+ const params = useMemo(
+ () => ({
+ arceeToken
+ }),
+ [arceeToken]
+ );
+
+ const { isLoading, isDataReady, run } = useGetTaskRun(organizationId, runId, params);
+
+ return (
+
+
+
+ );
+};
+
+export default PublicMlRunContainer;
diff --git a/ngui/ui/src/containers/PublicMlRunContainer/index.ts b/ngui/ui/src/containers/PublicMlRunContainer/index.ts
new file mode 100644
index 000000000..d74b1b3b8
--- /dev/null
+++ b/ngui/ui/src/containers/PublicMlRunContainer/index.ts
@@ -0,0 +1,3 @@
+import PublicMlRunContainer from "./PublicMlRunContainer";
+
+export default PublicMlRunContainer;
diff --git a/ngui/ui/src/containers/RunArtifactsContainer/RunArtifactsContainer.tsx b/ngui/ui/src/containers/RunArtifactsContainer/RunArtifactsContainer.tsx
index e39c12f79..62d227d89 100644
--- a/ngui/ui/src/containers/RunArtifactsContainer/RunArtifactsContainer.tsx
+++ b/ngui/ui/src/containers/RunArtifactsContainer/RunArtifactsContainer.tsx
@@ -2,12 +2,19 @@ import { useParams } from "react-router-dom";
import RunArtifactsTable from "components/RunArtifactsTable";
import MlArtifactsContainer from "containers/MlArtifactsContainer";
-const RunArtifactsContainer = () => {
+type RunArtifactsContainerProps = {
+ organizationId: string;
+ arceeToken: string;
+};
+
+const RunArtifactsContainer = ({ organizationId, arceeToken }: RunArtifactsContainerProps) => {
const { runId } = useParams() as { runId: string };
return (
(
)}
diff --git a/ngui/ui/src/containers/ShareRunLinkContainer/ShareRunLinkContainer.tsx b/ngui/ui/src/containers/ShareRunLinkContainer/ShareRunLinkContainer.tsx
new file mode 100644
index 000000000..4ab077ac0
--- /dev/null
+++ b/ngui/ui/src/containers/ShareRunLinkContainer/ShareRunLinkContainer.tsx
@@ -0,0 +1,18 @@
+import ShareRunLink from "components/ShareRunLink";
+import { useOrganizationInfo } from "hooks/useOrganizationInfo";
+import MlProfilingService from "services/MlProfilingService";
+
+type ShareRunLinkContainerProps = {
+ runId: string;
+};
+
+const ShareRunLinkContainer = ({ runId }: ShareRunLinkContainerProps) => {
+ const { useGetToken } = MlProfilingService();
+ const { isLoading, md5Token } = useGetToken();
+
+ const { organizationId } = useOrganizationInfo();
+
+ return ;
+};
+
+export default ShareRunLinkContainer;
diff --git a/ngui/ui/src/containers/ShareRunLinkContainer/index.ts b/ngui/ui/src/containers/ShareRunLinkContainer/index.ts
new file mode 100644
index 000000000..abffa3ed5
--- /dev/null
+++ b/ngui/ui/src/containers/ShareRunLinkContainer/index.ts
@@ -0,0 +1,3 @@
+import ShareRunLinkContainer from "./ShareRunLinkContainer";
+
+export default ShareRunLinkContainer;
diff --git a/ngui/ui/src/containers/StagesAndMilestonesContainer/StagesAndMilestonesContainer.tsx b/ngui/ui/src/containers/StagesAndMilestonesContainer/StagesAndMilestonesContainer.tsx
deleted file mode 100644
index be42119c6..000000000
--- a/ngui/ui/src/containers/StagesAndMilestonesContainer/StagesAndMilestonesContainer.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { getMilestoneTuplesGroupedByTime } from "components/ExecutionBreakdown/utils";
-import StagesAndMilestones from "components/StagesAndMilestones";
-import { getData } from "containers/ExecutionBreakdownContainer/utils";
-import MlTasksService from "services/MlTasksService";
-
-const StagesAndMilestonesContainer = ({
- runId,
- closeSideModal,
- highlightedStage,
- setHighlightedStage,
- setSelectedSegment,
- secondsTimeRange
-}) => {
- const { useGetRunBreakdown } = MlTasksService();
-
- const { breakdown = {}, milestones: milestonesApi = [], stages: stagesApi = [] } = useGetRunBreakdown(runId);
-
- const { stages, milestones } = getData({ breakdown, milestones: milestonesApi, stages: stagesApi });
-
- const milestonesGroupedByTimeTuples = getMilestoneTuplesGroupedByTime(milestones);
-
- return (
- {
- setSelectedSegment([start, end]);
- closeSideModal();
- }}
- stages={stages}
- highlightedStage={highlightedStage}
- setHighlightedStage={(stage) => {
- setHighlightedStage(stage);
- closeSideModal();
- }}
- secondsTimeRange={secondsTimeRange}
- />
- );
-};
-
-export default StagesAndMilestonesContainer;
diff --git a/ngui/ui/src/containers/StagesAndMilestonesContainer/index.ts b/ngui/ui/src/containers/StagesAndMilestonesContainer/index.ts
deleted file mode 100644
index 5643b4a20..000000000
--- a/ngui/ui/src/containers/StagesAndMilestonesContainer/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import StagesAndMilestonesContainer from "./StagesAndMilestonesContainer";
-
-export default StagesAndMilestonesContainer;
diff --git a/ngui/ui/src/graphql/api/restapi/queries/index.ts b/ngui/ui/src/graphql/api/restapi/queries/index.ts
index ee27c5be1..8140da054 100644
--- a/ngui/ui/src/graphql/api/restapi/queries/index.ts
+++ b/ngui/ui/src/graphql/api/restapi/queries/index.ts
@@ -1,3 +1,3 @@
-import { GET_DATA_SOURCE } from "./restapi.queries";
+import { GET_DATA_SOURCE, GET_LAYOUTS, GET_ML_EXECUTORS, GET_ML_RUN, GET_ML_RUN_BREAKDOWN } from "./restapi.queries";
-export { GET_DATA_SOURCE };
+export { GET_DATA_SOURCE, GET_ML_RUN, GET_ML_EXECUTORS, GET_ML_RUN_BREAKDOWN, GET_LAYOUTS };
diff --git a/ngui/ui/src/hooks/useTaskRunChartState.ts b/ngui/ui/src/hooks/useTaskRunChartState.ts
index 6e7646e96..714a3ddf6 100644
--- a/ngui/ui/src/hooks/useTaskRunChartState.ts
+++ b/ngui/ui/src/hooks/useTaskRunChartState.ts
@@ -197,7 +197,14 @@ const useGridTypeActions = ({ setSaved, setDashboard }) => {
return { updateGridType };
};
-export const useTaskRunChartState = ({ taskId, implementedMetricsBreakdownNames, breakdownNames }) => {
+export const useTaskRunChartState = ({
+ organizationId,
+ arceeToken,
+ taskId,
+ implementedMetricsBreakdownNames,
+ breakdownNames,
+ isPublicRun = false
+}) => {
const { dashboardId: selectedDashboardId, setDashboardId: setSelectedDashboardId } = useTaskRunsDashboardState(taskId);
const { useGetAll, useGetOneOnDemand, useUpdate, useDelete, useCreate } = LayoutsService();
@@ -206,7 +213,14 @@ export const useTaskRunChartState = ({ taskId, implementedMetricsBreakdownNames,
const { onCreate } = useCreate();
const { onUpdate } = useUpdate();
- const [saved, setSaved] = useState(true);
+ const [saved, setSavedState] = useState(true);
+
+ const setSaved = (newState: boolean) => {
+ if (isPublicRun) {
+ return;
+ }
+ setSavedState(newState);
+ };
const initializeDashboardState = useCallback(
(dashboard) => {
@@ -241,11 +255,13 @@ export const useTaskRunChartState = ({ taskId, implementedMetricsBreakdownNames,
const getAllLayoutsApiParams = useMemo(
() => ({
+ organizationId,
+ arceeToken,
layoutType: LAYOUT_TYPES.ML_RUN_CHARTS_DASHBOARD,
entityId: taskId,
includeShared: true
}),
- [taskId]
+ [arceeToken, organizationId, taskId]
);
const onSuccessGetAllLayouts = useCallback(
@@ -254,12 +270,14 @@ export const useTaskRunChartState = ({ taskId, implementedMetricsBreakdownNames,
setDashboard(initializeDashboardState(DEFAULT_DASHBOARD));
}
if (apiLayouts.find(({ id }) => id === selectedDashboardId)) {
- onGet(selectedDashboardId).then((dashboardInfo) => {
+ onGet(organizationId, selectedDashboardId, {
+ arceeToken
+ }).then((dashboardInfo) => {
setDashboard(initializeDashboardState(dashboardInfo));
});
}
},
- [initializeDashboardState, onGet, selectedDashboardId]
+ [arceeToken, initializeDashboardState, onGet, organizationId, selectedDashboardId]
);
const { layouts, currentEmployeeId, isLoading: isGetAllLoading } = useGetAll(getAllLayoutsApiParams, onSuccessGetAllLayouts);
@@ -271,7 +289,9 @@ export const useTaskRunChartState = ({ taskId, implementedMetricsBreakdownNames,
setDashboard(initializeDashboardState(DEFAULT_DASHBOARD));
setSelectedDashboardId(newDashboardId);
} else {
- onGet(newDashboardId).then((dashboardInfo) => {
+ onGet(organizationId, newDashboardId, {
+ arceeToken
+ }).then((dashboardInfo) => {
setDashboard(initializeDashboardState(dashboardInfo));
setSelectedDashboardId(newDashboardId);
});
diff --git a/ngui/ui/src/pages/PublicMlRun/PublicMlRun.tsx b/ngui/ui/src/pages/PublicMlRun/PublicMlRun.tsx
new file mode 100644
index 000000000..278d9a4bf
--- /dev/null
+++ b/ngui/ui/src/pages/PublicMlRun/PublicMlRun.tsx
@@ -0,0 +1,5 @@
+import PublicMlRunContainer from "containers/PublicMlRunContainer";
+
+const PublicMlRun = () => ;
+
+export default PublicMlRun;
diff --git a/ngui/ui/src/pages/PublicMlRun/index.ts b/ngui/ui/src/pages/PublicMlRun/index.ts
new file mode 100644
index 000000000..87c265d74
--- /dev/null
+++ b/ngui/ui/src/pages/PublicMlRun/index.ts
@@ -0,0 +1,3 @@
+import PublicMlRun from "./PublicMlRun";
+
+export default PublicMlRun;
diff --git a/ngui/ui/src/services/LayoutsService.ts b/ngui/ui/src/services/LayoutsService.ts
index 088838cb5..9d9dc2226 100644
--- a/ngui/ui/src/services/LayoutsService.ts
+++ b/ngui/ui/src/services/LayoutsService.ts
@@ -20,9 +20,11 @@ type LayoutData = {
const useGetAll = (
params: {
+ organizationId: string;
layoutType: (typeof LAYOUT_TYPES)[keyof typeof LAYOUT_TYPES];
entityId?: string;
includeShared?: boolean;
+ arceeToken?: string;
},
onSuccess?: (layout: LayoutData) => void
): {
@@ -32,9 +34,7 @@ const useGetAll = (
} => {
const dispatch = useDispatch();
- const { layoutType, entityId, includeShared } = params;
-
- const { organizationId } = useOrganizationInfo();
+ const { organizationId, layoutType, entityId, includeShared, arceeToken } = params;
const { isLoading, shouldInvoke } = useApiState(GET_LAYOUTS, {
organizationId,
@@ -50,7 +50,7 @@ const useGetAll = (
useEffect(() => {
if (shouldInvoke) {
dispatch((_, getState) => {
- dispatch(getLayouts(organizationId, { layoutType, entityId, includeShared })).then(() => {
+ dispatch(getLayouts(organizationId, { layoutType, entityId, includeShared, arceeToken })).then(() => {
if (!isError(GET_LAYOUTS, getState())) {
const apiData = getState()[RESTAPI][GET_LAYOUTS];
if (typeof onSuccess === "function") {
@@ -60,7 +60,7 @@ const useGetAll = (
});
});
}
- }, [shouldInvoke, dispatch, organizationId, entityId, includeShared, layoutType, onSuccess]);
+ }, [shouldInvoke, dispatch, organizationId, entityId, includeShared, layoutType, onSuccess, arceeToken]);
return {
isLoading,
@@ -99,12 +99,10 @@ const useGetOneOnDemand = (): {
isLoading: boolean;
entityId: string;
layout: LayoutData;
- onGet: (layoutId: string) => Promise;
+ onGet: (organizationId: string, layoutId: string, params: { arceeToken?: string }) => Promise;
} => {
const dispatch = useDispatch();
- const { organizationId } = useOrganizationInfo();
-
const { isLoading, entityId } = useApiState(GET_LAYOUT);
const { apiData: layout } = useApiData(GET_LAYOUT);
@@ -114,10 +112,10 @@ const useGetOneOnDemand = (): {
entityId,
layout,
onGet: useCallback(
- (layoutId) =>
+ (organizationId, layoutId, params) =>
new Promise((resolve, reject) => {
dispatch((_, getState) => {
- dispatch(getLayout(organizationId, layoutId)).then(() => {
+ dispatch(getLayout(organizationId, layoutId, params)).then(() => {
if (!isError(GET_LAYOUT, getState())) {
const apiData = getState()[RESTAPI][GET_LAYOUT];
@@ -127,7 +125,7 @@ const useGetOneOnDemand = (): {
});
});
}),
- [dispatch, organizationId]
+ [dispatch]
)
};
};
diff --git a/ngui/ui/src/services/MlArtifactsService.ts b/ngui/ui/src/services/MlArtifactsService.ts
index 1702df8e4..425cf19ff 100644
--- a/ngui/ui/src/services/MlArtifactsService.ts
+++ b/ngui/ui/src/services/MlArtifactsService.ts
@@ -53,6 +53,7 @@ type CreateApplicationApiParams = {
};
const useGet = (
+ organizationId: string,
params?: GetApiParams
): {
isLoading: boolean;
@@ -65,8 +66,6 @@ const useGet = (
} => {
const dispatch = useDispatch();
- const { organizationId } = useOrganizationInfo();
-
const { apiData } = useApiData(GET_ML_ARTIFACTS);
const { isLoading, shouldInvoke } = useApiState(GET_ML_ARTIFACTS, { organizationId, ...params });
diff --git a/ngui/ui/src/services/MlExecutorsService.ts b/ngui/ui/src/services/MlExecutorsService.ts
index aaed3e76e..728b63f6d 100644
--- a/ngui/ui/src/services/MlExecutorsService.ts
+++ b/ngui/ui/src/services/MlExecutorsService.ts
@@ -6,25 +6,31 @@ import { useApiData } from "hooks/useApiData";
import { useApiState } from "hooks/useApiState";
import { useOrganizationInfo } from "hooks/useOrganizationInfo";
-const useGet = ({ taskIds, runIds } = {}) => {
+const useGet = ({ taskIds, runIds, organizationId, arceeToken } = {}) => {
const dispatch = useDispatch();
- const { organizationId } = useOrganizationInfo();
+
const {
apiData: { executors = [] }
} = useApiData(GET_ML_EXECUTORS);
- const { isLoading, shouldInvoke } = useApiState(GET_ML_EXECUTORS, { organizationId, taskIds, runIds });
+ const { isLoading, shouldInvoke } = useApiState(GET_ML_EXECUTORS, {
+ organizationId,
+ taskIds,
+ runIds,
+ arceeToken
+ });
useEffect(() => {
if (shouldInvoke) {
dispatch(
getMlExecutors(organizationId, {
taskIds,
- runIds
+ runIds,
+ arceeToken
})
);
}
- }, [taskIds, dispatch, organizationId, runIds, shouldInvoke]);
+ }, [taskIds, dispatch, organizationId, runIds, arceeToken, shouldInvoke]);
return { isLoading, executors };
};
diff --git a/ngui/ui/src/services/MlProfilingService.ts b/ngui/ui/src/services/MlProfilingService.ts
index dbab98180..fcf5b83cb 100644
--- a/ngui/ui/src/services/MlProfilingService.ts
+++ b/ngui/ui/src/services/MlProfilingService.ts
@@ -12,7 +12,7 @@ const useGetToken = () => {
const { organizationId } = useOrganizationInfo();
const {
- apiData: { token = "" }
+ apiData: { token = "", md5_token: md5Token = "" }
} = useApiData(GET_PROFILING_TOKEN);
const { isLoading, shouldInvoke } = useApiState(GET_PROFILING_TOKEN, { organizationId });
@@ -23,7 +23,7 @@ const useGetToken = () => {
}
}, [shouldInvoke, dispatch, organizationId]);
- return { isLoading, token };
+ return { isLoading, token, md5Token };
};
function MlProfilingService() {
diff --git a/ngui/ui/src/services/MlTasksService.ts b/ngui/ui/src/services/MlTasksService.ts
index 698d7a2d1..6d3a6b142 100644
--- a/ngui/ui/src/services/MlTasksService.ts
+++ b/ngui/ui/src/services/MlTasksService.ts
@@ -276,20 +276,18 @@ const useGetTaskRunsBulk = (taskId, runIds) => {
return { isLoading, isDataReady, runs };
};
-const useGetTaskRun = (runId) => {
+const useGetTaskRun = (organizationId, runId, params) => {
const dispatch = useDispatch();
- const { organizationId } = useOrganizationInfo();
-
const { isLoading, isDataReady, shouldInvoke } = useApiState(GET_ML_RUN_DETAILS, { organizationId, runId });
const { apiData } = useApiData(GET_ML_RUN_DETAILS);
useEffect(() => {
if (shouldInvoke) {
- dispatch(getMlRunDetails(organizationId, runId));
+ dispatch(getMlRunDetails(organizationId, runId, params));
}
- }, [dispatch, organizationId, runId, shouldInvoke]);
+ }, [dispatch, organizationId, runId, shouldInvoke, params]);
return { isLoading, isDataReady, run: apiData };
};
@@ -314,11 +312,9 @@ const useGetTaskTags = (taskId) => {
return { isLoading, tags };
};
-const useGetRunBreakdown = (runId) => {
+const useGetRunBreakdown = (organizationId, runId, params) => {
const dispatch = useDispatch();
- const { organizationId } = useOrganizationInfo();
-
const { isLoading, isDataReady, shouldInvoke } = useApiState(GET_ML_RUN_DETAILS_BREAKDOWN, {
organizationId,
runId
@@ -330,9 +326,9 @@ const useGetRunBreakdown = (runId) => {
useEffect(() => {
if (shouldInvoke) {
- dispatch(getMlRunDetailsBreakdown(organizationId, runId));
+ dispatch(getMlRunDetailsBreakdown(organizationId, runId, params));
}
- }, [dispatch, organizationId, runId, shouldInvoke]);
+ }, [dispatch, organizationId, runId, shouldInvoke, params]);
return { isLoading, isDataReady, breakdown, stages, milestones };
};
diff --git a/ngui/ui/src/translations/en-US/app.json b/ngui/ui/src/translations/en-US/app.json
index 0746c0d5c..22b2b47f1 100644
--- a/ngui/ui/src/translations/en-US/app.json
+++ b/ngui/ui/src/translations/en-US/app.json
@@ -2020,6 +2020,8 @@
"shareLinkGoogleSingleHeader": "Single day expenses",
"shareLinkGoogleSingleTip": "Expenses for a single day will be returned if just start_date is passed.",
"shareLinkRemoveTip": "By toggling off that switch you will make current link obsolete. Each link is unique and could not be restored!",
+ "shareRunLinkDescription": "This link allows you to share the run with others. Anyone with the link will have access to view and analyze the run. Please ensure sharing complies with your organization's data-sharing policies.",
+ "shareRunLinkTitle": "Share Run Link",
"shared": "Shared",
"shortLivingInstances": "Short living instances",
"shortLivingInstancesDescription": "Some of the instances you have been running for the last {daysThreshold} {daysThreshold, plural,\n =1 {day}\n other {days}\n} have existed for less than 6 hours and were not created as Spot (or Preemptible) Instances. Consider using Spot (Preemptible) Instances.",
diff --git a/ngui/ui/src/urls.ts b/ngui/ui/src/urls.ts
index 3f30f914c..080be4c0b 100644
--- a/ngui/ui/src/urls.ts
+++ b/ngui/ui/src/urls.ts
@@ -334,6 +334,18 @@ const ML_LAUNCH_BASE = "launch";
export const ML_RUNSETS_BASE = "runsets";
export const ML_RUN_BASE = "run";
+export const ML_PUBLIC_RUN_BASE = "run";
+export const ML_PUBLIC_RUN = concatenateUrl([ML_PUBLIC_RUN_BASE, ML_TASK_RUN_IDENTIFIER]);
+export const getMlPublicRunUrl = (runId, { organizationId, arceeToken }) => {
+ const urlBase = ML_PUBLIC_RUN.replace(ML_TASK_RUN_IDENTIFIER, runId);
+ const searchParams = new URLSearchParams({
+ organizationId,
+ token: arceeToken
+ });
+
+ return `${urlBase}?${searchParams.toString()}`;
+};
+
export const ML_TASKS = concatenateUrl([ML_TASKS_BASE]);
export const ML_TASK_CREATE = concatenateUrl([ML_TASKS_BASE, CREATE]);
diff --git a/ngui/ui/src/utils/columns/executor.tsx b/ngui/ui/src/utils/columns/executor.tsx
index d5e092f84..a7ec20a01 100644
--- a/ngui/ui/src/utils/columns/executor.tsx
+++ b/ngui/ui/src/utils/columns/executor.tsx
@@ -4,7 +4,7 @@ import ExecutorLabel from "components/ExecutorLabel";
import KeyValueLabel from "components/KeyValueLabel/KeyValueLabel";
import TextWithDataTestId from "components/TextWithDataTestId";
-const executor = () => ({
+const executor = ({ disableLink = false }) => ({
header: (
@@ -38,7 +38,13 @@ const executor = () => ({
}
]}
>
-
+
);
}
diff --git a/ngui/ui/src/utils/columns/mlExecutorLocation.tsx b/ngui/ui/src/utils/columns/mlExecutorLocation.tsx
index 6504f2d17..a1d182a1e 100644
--- a/ngui/ui/src/utils/columns/mlExecutorLocation.tsx
+++ b/ngui/ui/src/utils/columns/mlExecutorLocation.tsx
@@ -5,13 +5,13 @@ import QuestionMark from "components/QuestionMark";
import TextWithDataTestId from "components/TextWithDataTestId";
import { useOrganizationInfo } from "hooks/useOrganizationInfo";
-const Cell = ({ discovered, resource }) => {
+const Cell = ({ discovered, resource, disableLink = false }) => {
const { isDemo } = useOrganizationInfo();
if (discovered) {
const { cloud_account: { id, name, type } = {} } = resource ?? {};
- return ;
+ return ;
}
return (
@@ -24,7 +24,7 @@ const Cell = ({ discovered, resource }) => {
);
};
-const mlExecutorLocation = ({ headerDataTestId = "lbl_location", headerMessageId = "location" } = {}) => ({
+const mlExecutorLocation = ({ headerDataTestId = "lbl_location", headerMessageId = "location", disableLink = false } = {}) => ({
header: (
@@ -35,7 +35,7 @@ const mlExecutorLocation = ({ headerDataTestId = "lbl_location", headerMessageId
row: {
original: { discovered, resource }
}
- }) => |
+ }) => |
});
export default mlExecutorLocation;
diff --git a/ngui/ui/src/utils/routes/index.ts b/ngui/ui/src/utils/routes/index.ts
index ccd826f96..2ad92cdfa 100644
--- a/ngui/ui/src/utils/routes/index.ts
+++ b/ngui/ui/src/utils/routes/index.ts
@@ -77,6 +77,7 @@ import poolsRoute from "./poolsRoute";
import poolTtlAnalysisRoute from "./poolTtlAnalysisRoute";
import powerScheduleDetailsRoute from "./powerScheduleDetailsRoute";
import powerSchedulesRoute from "./powerSchedulesRoute";
+import publicMlRun from "./publicMlRun";
import quotaRoute from "./quotaRoute";
import quotasRoute from "./quotasRoute";
import recommendationsRoute from "./recommendationsRoute";
@@ -192,6 +193,7 @@ export const routes = [
mlCreateRunArtifactRoute,
mlEditArtifactRoute,
emailVerificationRoute,
+ publicMlRun,
// React router 6.x does not require the not found route (*) to be at the end,
// but the matchPath hook that is used in the DocsPanel component seems to honor the order.
// Moving it to the bottom for "safety" reasons.
diff --git a/ngui/ui/src/utils/routes/publicMlRun.ts b/ngui/ui/src/utils/routes/publicMlRun.ts
new file mode 100644
index 000000000..9fbe316d5
--- /dev/null
+++ b/ngui/ui/src/utils/routes/publicMlRun.ts
@@ -0,0 +1,14 @@
+import { ML_PUBLIC_RUN } from "urls";
+import BaseRoute from "./baseRoute";
+
+class PublicMlRun extends BaseRoute {
+ isTokenRequired = false;
+
+ page = "PublicMlRun";
+
+ link = ML_PUBLIC_RUN;
+
+ layout = null;
+}
+
+export default new PublicMlRun();