From aefa0dd01fcd816f4d03de1ccee4bec815e570c7 Mon Sep 17 00:00:00 2001 From: ek-hystax <33006768+ek-hystax@users.noreply.github.com> Date: Wed, 3 Jan 2024 12:45:24 +0400 Subject: [PATCH 1/7] OS-7189. Cover leaderboard actions with permission --- .../LeaderboardDatasetDetails.tsx | 28 +++-- .../components/LeaderboardDatasets.tsx | 115 ++++++++++-------- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/ngui/ui/src/components/LeaderboardDatasetDetails/LeaderboardDatasetDetails.tsx b/ngui/ui/src/components/LeaderboardDatasetDetails/LeaderboardDatasetDetails.tsx index a762229f7..425ad4b27 100644 --- a/ngui/ui/src/components/LeaderboardDatasetDetails/LeaderboardDatasetDetails.tsx +++ b/ngui/ui/src/components/LeaderboardDatasetDetails/LeaderboardDatasetDetails.tsx @@ -8,20 +8,24 @@ import LeaderboardDatasetDetailsTable from "components/MlModelLeaderboard/compon import SubTitle from "components/SubTitle"; import TableLoader from "components/TableLoader"; import TypographyLoader from "components/TypographyLoader"; +import { useIsAllowed } from "hooks/useAllowedActions"; -const Title = ({ leaderboard, leaderboardDataset, isLoading }) => - isLoading ? ( - - ) : ( +const Title = ({ leaderboard, leaderboardDataset }) => { + const isManageLeaderboardDatasetAllowed = useIsAllowed({ requiredActions: ["EDIT_PARTNER"] }); + + return ( {leaderboardDataset.name} - - - - - + {isManageLeaderboardDatasetAllowed && ( + + + + + + )} ); +}; const Datasets = ({ datasets = [], isLoading }) => isLoading ? ( @@ -54,7 +58,11 @@ const LeaderboardDatasetDetails = ({ leaderboard, leaderboardDataset, leaderboar return (
- + {isGetLeaderboardDatasetLoading ? ( + <TypographyLoader /> + ) : ( + <Title leaderboard={leaderboard} leaderboardDataset={leaderboardDataset} isLoading={isGetLeaderboardDatasetLoading} /> + )} </div> <div> <Datasets datasets={leaderboardDataset.datasets} isLoading={isGetLeaderboardDatasetLoading} /> diff --git a/ngui/ui/src/components/MlModelLeaderboard/components/LeaderboardDatasets.tsx b/ngui/ui/src/components/MlModelLeaderboard/components/LeaderboardDatasets.tsx index d6c93b5fc..f4be3cbc7 100644 --- a/ngui/ui/src/components/MlModelLeaderboard/components/LeaderboardDatasets.tsx +++ b/ngui/ui/src/components/MlModelLeaderboard/components/LeaderboardDatasets.tsx @@ -1,79 +1,90 @@ import { Box, Typography } from "@mui/material"; import { FormattedMessage } from "react-intl"; import LeaderboardDatasetDetailsContainer from "containers/LeaderboardDatasetDetailsContainer"; +import { useIsAllowed } from "hooks/useAllowedActions"; import { isEmpty as isEmptyArray } from "utils/arrays"; import AddLeaderboardCriteriaButton from "./AddLeaderboardCriteriaButton"; import LeaderboardDatasetCard from "./LeaderboardDatasetCard"; -const NoLeaderboards = ({ leaderboardId }) => ( - <Box> - <Typography gutterBottom> - <FormattedMessage id="noLeaderboards" /> - </Typography> - <AddLeaderboardCriteriaButton leaderboardId={leaderboardId} /> - </Box> -); +const NoLeaderboards = ({ leaderboardId }) => { + const isAddLeaderboardCriteriaAllowed = useIsAllowed({ requiredActions: ["EDIT_PARTNER"] }); + + return ( + <Box> + <Typography gutterBottom> + <FormattedMessage id="noLeaderboards" /> + </Typography> + {isAddLeaderboardCriteriaAllowed && <AddLeaderboardCriteriaButton leaderboardId={leaderboardId} />} + </Box> + ); +}; const LeaderboardDatasetsListSection = ({ leaderboard, leaderboardDatasets, selectedLeaderboardDataset, onSelectedLeaderboardDashboardChange -}) => ( - <Box - sx={{ - display: "flex", - gap: 1, - alignItems: "center", - flexDirection: { - xs: "row", - md: "column" - }, - justifyContent: { - xs: "space-between", - md: "normal" - } - }} - > - <AddLeaderboardCriteriaButton - leaderboardId={leaderboard.id} - sx={{ - width: { - md: "100%" - }, - order: { - xs: 1, - md: 0 - } - }} - /> +}) => { + const isAddLeaderboardCriteriaAllowed = useIsAllowed({ requiredActions: ["EDIT_PARTNER"] }); + + return ( <Box sx={{ display: "flex", gap: 1, - overflow: "auto", - minWidth: "150px", + alignItems: "center", flexDirection: { xs: "row", md: "column" + }, + justifyContent: { + xs: "space-between", + md: "normal" } }} > - {selectedLeaderboardDataset && - leaderboardDatasets.map((leaderboardDataset) => { - const isSelected = leaderboardDataset.id === selectedLeaderboardDataset.id; - return ( - <LeaderboardDatasetCard - key={leaderboard.id} - leaderboardDataset={leaderboardDataset} - onClick={() => onSelectedLeaderboardDashboardChange(leaderboardDataset)} - selected={isSelected} - /> - ); - })} + {isAddLeaderboardCriteriaAllowed && ( + <AddLeaderboardCriteriaButton + leaderboardId={leaderboard.id} + sx={{ + width: { + md: "100%" + }, + order: { + xs: 1, + md: 0 + } + }} + /> + )} + <Box + sx={{ + display: "flex", + gap: 1, + overflow: "auto", + minWidth: "150px", + flexDirection: { + xs: "row", + md: "column" + } + }} + > + {selectedLeaderboardDataset && + leaderboardDatasets.map((leaderboardDataset) => { + const isSelected = leaderboardDataset.id === selectedLeaderboardDataset.id; + return ( + <LeaderboardDatasetCard + key={leaderboard.id} + leaderboardDataset={leaderboardDataset} + onClick={() => onSelectedLeaderboardDashboardChange(leaderboardDataset)} + selected={isSelected} + /> + ); + })} + </Box> </Box> - </Box> -); + ); +}; const LeaderboardDatasets = ({ leaderboard, From 78890ef57f201d97f78ce0c07a3fc94e04845b01 Mon Sep 17 00:00:00 2001 From: ek-hystax <33006768+ek-hystax@users.noreply.github.com> Date: Wed, 3 Jan 2024 12:47:31 +0400 Subject: [PATCH 2/7] OS-7197. Add pagination for leaderboard details runs table --- .../components/RunsTab.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ngui/ui/src/components/LeaderboardRunGroupDetailsModalContent/components/RunsTab.tsx b/ngui/ui/src/components/LeaderboardRunGroupDetailsModalContent/components/RunsTab.tsx index 1cc9100d5..7bd72adf1 100644 --- a/ngui/ui/src/components/LeaderboardRunGroupDetailsModalContent/components/RunsTab.tsx +++ b/ngui/ui/src/components/LeaderboardRunGroupDetailsModalContent/components/RunsTab.tsx @@ -15,6 +15,8 @@ import { dataset } from "utils/columns"; import { SPACING_2 } from "utils/layouts"; import { formatRunFullName } from "utils/ml"; +const RUNS_TABLE_ROWS_PER_PAGE = 10; + const RunsTable = ({ runGroupPrimaryMetric, runGroupSecondaryMetrics, runsData }) => { const tableData = useMemo(() => runsData, [runsData]); const formatIntervalTimeAgo = useFormatIntervalTimeAgo(); @@ -99,6 +101,8 @@ const RunsTable = ({ runGroupPrimaryMetric, runGroupSecondaryMetrics, runsData } localization={{ emptyMessageId: "noRuns" }} + pageSize={RUNS_TABLE_ROWS_PER_PAGE} + enablePaginationQueryParam={false} /> ); }; From 42c6dc293bb85902ea3405b61975e9277295bde5 Mon Sep 17 00:00:00 2001 From: ek-hystax <33006768+ek-hystax@users.noreply.github.com> Date: Wed, 3 Jan 2024 12:56:30 +0400 Subject: [PATCH 3/7] OS-7191. Cover "Setup leaderboards" button with permission --- .../components/SetupLeaderboardsInvitation.tsx | 9 ++++++++- ngui/ui/src/translations/en-US/app.json | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ngui/ui/src/components/MlModelLeaderboard/components/SetupLeaderboardsInvitation.tsx b/ngui/ui/src/components/MlModelLeaderboard/components/SetupLeaderboardsInvitation.tsx index d785ad597..cbd048ee6 100644 --- a/ngui/ui/src/components/MlModelLeaderboard/components/SetupLeaderboardsInvitation.tsx +++ b/ngui/ui/src/components/MlModelLeaderboard/components/SetupLeaderboardsInvitation.tsx @@ -4,6 +4,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import { useParams } from "react-router-dom"; import finopsCloudCostOptimization from "assets/ml/leaderbords.svg"; import Button from "components/Button"; +import { useIsAllowed } from "hooks/useAllowedActions"; import { getMlSetupLeaderboards } from "urls"; import { SPACING_1, SPACING_2 } from "utils/layouts"; @@ -11,6 +12,8 @@ const SetupLeaderboardsInvitation = () => { const intl = useIntl(); const { taskId } = useParams(); + const isLeaderboardSetupEnabled = useIsAllowed({ requiredActions: ["EDIT_PARTNER"] }); + return ( <Stack alignItems="center" spacing={SPACING_1} mt={SPACING_2}> <img @@ -25,7 +28,11 @@ const SetupLeaderboardsInvitation = () => { <FormattedMessage id="nothingToShowHereYet" /> </Box> <Box> - <Button messageId="setupLeaderboards" color="primary" variant="contained" link={getMlSetupLeaderboards(taskId)} /> + {isLeaderboardSetupEnabled ? ( + <Button messageId="setupLeaderboards" color="primary" variant="contained" link={getMlSetupLeaderboards(taskId)} /> + ) : ( + <FormattedMessage id="leaderboardContactManagerMessage" /> + )} </Box> </Stack> ); diff --git a/ngui/ui/src/translations/en-US/app.json b/ngui/ui/src/translations/en-US/app.json index 024ea924e..6bb931365 100644 --- a/ngui/ui/src/translations/en-US/app.json +++ b/ngui/ui/src/translations/en-US/app.json @@ -974,6 +974,7 @@ "latest": "Latest", "launch": "Launch", "leaderboard": "Leaderboard", + "leaderboardContactManagerMessage": "Please contact your organization manager to setup a leadearboard.", "leaderboardQualificationProtocol.coverDatasets": "Run should cover the following datasets:", "leaderboardQualificationProtocol.metricRestrictions": "Run should fit the following metric restrictions:", "leaderboards": "Leaderboards", From a637663929285c391c8e744e836fdfd2e45d0e32 Mon Sep 17 00:00:00 2001 From: ek-hystax <33006768+ek-hystax@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:03:04 +0400 Subject: [PATCH 4/7] OS-7198. Add search for leaderboard details runs table --- .../components/RunsTab.tsx | 38 +++++++++++++++---- ngui/ui/src/utils/columns/dataset.tsx | 9 +++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/ngui/ui/src/components/LeaderboardRunGroupDetailsModalContent/components/RunsTab.tsx b/ngui/ui/src/components/LeaderboardRunGroupDetailsModalContent/components/RunsTab.tsx index 7bd72adf1..5bc5ab33e 100644 --- a/ngui/ui/src/components/LeaderboardRunGroupDetailsModalContent/components/RunsTab.tsx +++ b/ngui/ui/src/components/LeaderboardRunGroupDetailsModalContent/components/RunsTab.tsx @@ -1,9 +1,9 @@ -import { useMemo } from "react"; +import { useCallback, useMemo } from "react"; import { Link, Stack, Typography } from "@mui/material"; import { FormattedMessage } from "react-intl"; import { Link as RouterLink } from "react-router-dom"; import CaptionedCell from "components/CaptionedCell"; -import DynamicFractionDigitsValue from "components/DynamicFractionDigitsValue"; +import { useFormatDynamicFractionDigitsValue } from "components/DynamicFractionDigitsValue"; import KeyValueLabel from "components/KeyValueLabel"; import SubTitle from "components/SubTitle"; import Table from "components/Table"; @@ -17,9 +17,17 @@ import { formatRunFullName } from "utils/ml"; const RUNS_TABLE_ROWS_PER_PAGE = 10; +const useFormatRunTimeAgo = () => { + const formatIntervalTimeAgo = useFormatIntervalTimeAgo(); + + return useCallback((finish) => formatIntervalTimeAgo(finish, 1), [formatIntervalTimeAgo]); +}; + const RunsTable = ({ runGroupPrimaryMetric, runGroupSecondaryMetrics, runsData }) => { const tableData = useMemo(() => runsData, [runsData]); - const formatIntervalTimeAgo = useFormatIntervalTimeAgo(); + + const formatRunTimeAgo = useFormatRunTimeAgo(); + const formatDynamicFractionDigitsValue = useFormatDynamicFractionDigitsValue(); const columns = useMemo( () => [ @@ -35,10 +43,17 @@ const RunsTable = ({ runGroupPrimaryMetric, runGroupSecondaryMetrics, runsData } const search = filterValue.toLocaleLowerCase(); const { - original: { runset_name: runsetName = "" } + original: { runset_name: runsetName, finish } } = row; - return [runName, runsetName].some((str) => str.toLocaleLowerCase().includes(search)); + const timeAgo = formatRunTimeAgo(finish); + + return [ + runName, + timeAgo, + // runsetName can be null + runsetName ?? "" + ].some((str) => str.toLocaleLowerCase().includes(search)); }, sortingFn: "alphanumeric", cell: ({ cell, row: { original } }) => { @@ -48,7 +63,7 @@ const RunsTable = ({ runGroupPrimaryMetric, runGroupSecondaryMetrics, runsData } <CaptionedCell caption={[ { - node: <Typography variant="caption">{formatIntervalTimeAgo(finish, 1)}</Typography>, + node: <Typography variant="caption">{formatRunTimeAgo(finish)}</Typography>, key: "timeAgo" }, ...(runsetName @@ -87,11 +102,16 @@ const RunsTable = ({ runGroupPrimaryMetric, runGroupSecondaryMetrics, runsData } ...[runGroupPrimaryMetric, ...runGroupSecondaryMetrics].map(({ key, name }) => ({ header: <TextWithDataTestId dataTestId={`lbl_${key}`}>{name}</TextWithDataTestId>, id: key, + searchFn: (value, filterValue) => { + const search = filterValue.toLocaleLowerCase(); + + return formatDynamicFractionDigitsValue({ value }).includes(search); + }, accessorFn: (originalRow) => originalRow.data?.[key]?.value, - cell: ({ cell }) => <DynamicFractionDigitsValue value={cell.getValue()} /> + cell: ({ cell }) => formatDynamicFractionDigitsValue({ value: cell.getValue() }) })) ], - [formatIntervalTimeAgo, runGroupPrimaryMetric, runGroupSecondaryMetrics] + [formatDynamicFractionDigitsValue, formatRunTimeAgo, runGroupPrimaryMetric, runGroupSecondaryMetrics] ); return ( @@ -101,8 +121,10 @@ const RunsTable = ({ runGroupPrimaryMetric, runGroupSecondaryMetrics, runsData } localization={{ emptyMessageId: "noRuns" }} + withSearch pageSize={RUNS_TABLE_ROWS_PER_PAGE} enablePaginationQueryParam={false} + enableSearchQueryParam={false} /> ); }; diff --git a/ngui/ui/src/utils/columns/dataset.tsx b/ngui/ui/src/utils/columns/dataset.tsx index 882279034..e377b1505 100644 --- a/ngui/ui/src/utils/columns/dataset.tsx +++ b/ngui/ui/src/utils/columns/dataset.tsx @@ -15,6 +15,15 @@ const dataset = ({ id, accessorFn, accessorKey }) => ({ <FormattedMessage id="dataset" /> </TextWithDataTestId> ), + searchFn: (_, filterValue, { row }) => { + const search = filterValue.toLocaleLowerCase(); + + const { dataset: rowDataset } = row.original; + + const { name, path, labels = [] } = rowDataset; + + return [name, path, labels.join(" ")].some((str) => str.toLocaleLowerCase().includes(search)); + }, cell: ({ row: { original } }) => { const { dataset: rowDataset } = original; From d8290e0225d80cf6c46a85c38e427a86ebc60a05 Mon Sep 17 00:00:00 2001 From: nk-hystax <128669932+nk-hystax@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:14:26 +0300 Subject: [PATCH 5/7] OS-7206. Fixed typos in variable name in herald --- herald/modules/email_generator/generator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/herald/modules/email_generator/generator.py b/herald/modules/email_generator/generator.py index b3875f5b1..1b56f388a 100644 --- a/herald/modules/email_generator/generator.py +++ b/herald/modules/email_generator/generator.py @@ -16,9 +16,9 @@ def _generate_context(template_params, config_client): def update_template(template, params): for key, value in params.items(): if isinstance(value, collections.abc.Mapping): - template[k] = update_template(template.get(key, {}), value) + template[key] = update_template(template.get(key, {}), value) else: - template[k] = value + template[key] = value return template def get_numbered_params(params_dict): From ca1bd6c0e38077bbb308d3175ea25fd867b9719e Mon Sep 17 00:00:00 2001 From: nk-hystax <128669932+nk-hystax@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:05:07 +0300 Subject: [PATCH 6/7] OS-7206. Fixed param name in herald --- herald/modules/email_generator/generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/herald/modules/email_generator/generator.py b/herald/modules/email_generator/generator.py index 1b56f388a..7620cb16c 100644 --- a/herald/modules/email_generator/generator.py +++ b/herald/modules/email_generator/generator.py @@ -25,7 +25,7 @@ def get_numbered_params(params_dict): numbered_dict = {} for key, value in params_dict.items(): if isinstance(value, numbers.Number): - numbered_dict[k] = value + numbered_dict[key] = value return numbered_dict def update_template_style(numbered_dict): From 53931d29217cd2439d0043abbefc811c2a65db77 Mon Sep 17 00:00:00 2001 From: nk-hystax <128669932+nk-hystax@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:21:43 +0300 Subject: [PATCH 7/7] OS-7206. Fixed var name in herald --- herald/modules/email_generator/generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/herald/modules/email_generator/generator.py b/herald/modules/email_generator/generator.py index 7620cb16c..3d50bfa5e 100644 --- a/herald/modules/email_generator/generator.py +++ b/herald/modules/email_generator/generator.py @@ -32,7 +32,7 @@ def update_template_style(numbered_dict): style = {} display_visibility_name = 'element_visibility_%s' for key, value in numbered_dict.items(): - style[display_visibility_name % k] = 'table-row' if value else 'none' + style[display_visibility_name % key] = 'table-row' if value else 'none' return style def generate_control_panel_parameters(organization_map):