From 21cfb70d29f1a705d851025565bda603887bfb01 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Tue, 3 Jun 2025 18:22:18 +0900 Subject: [PATCH 001/228] Bump DRC version `3.0.4` (#3281) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fadad6e468..b7a489f518 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.0.3", + "iguazio.dashboard-react-controls": "3.0.4", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", From 3fdb586494979468dacb62732a9f37bd86d1a442 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:23:32 +0300 Subject: [PATCH 002/228] Fix [Scheduled] Edit job - Uncaught runtime error (#3274) --- src/components/JobWizard/JobWizard.util.js | 2 +- src/reducers/jobReducer.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/JobWizard/JobWizard.util.js b/src/components/JobWizard/JobWizard.util.js index f41c20071f..3a5dcdf0ea 100644 --- a/src/components/JobWizard/JobWizard.util.js +++ b/src/components/JobWizard/JobWizard.util.js @@ -1153,7 +1153,7 @@ export const getNewJobErrorMsg = error => { } export const getSaveJobErrorMsg = error => { - return error.response.status === FORBIDDEN_ERROR_STATUS_CODE + return error?.response?.status === FORBIDDEN_ERROR_STATUS_CODE ? 'You do not have permission to run a new job.' : getErrorDetail(error) || 'Unable to save the job.' } diff --git a/src/reducers/jobReducer.js b/src/reducers/jobReducer.js index d86387ec5e..6bca5d0be2 100644 --- a/src/reducers/jobReducer.js +++ b/src/reducers/jobReducer.js @@ -140,8 +140,8 @@ export const deleteAllJobRuns = createAsyncThunk('deleteAllJobRuns', ({ project, export const deleteJob = createAsyncThunk('deleteJob', ({ project, job }) => { return jobsApi.deleteJob(project, job.uid) }) -export const editJob = createAsyncThunk('editJob', ({ postData, project }) => { - return jobsApi.editJob(postData, project) +export const editJob = createAsyncThunk('editJob', ({ postData, project }, thunkAPI) => { + return jobsApi.editJob(postData, project).catch(thunkAPI.rejectWithValue) }) export const fetchAllJobRuns = createAsyncThunk( 'fetchAllJobRuns', From 67d6b84717a14cfe1226b48549435a99cd410c2b Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:23:44 +0300 Subject: [PATCH 003/228] Fix [Scheduled] Unexpected application error when editing a scheduled job (#3276) --- src/components/JobWizard/JobWizard.jsx | 21 ++++++++++----------- src/hooks/useJobsPageData.js | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/components/JobWizard/JobWizard.jsx b/src/components/JobWizard/JobWizard.jsx index da8727b86d..9278b8cf95 100644 --- a/src/components/JobWizard/JobWizard.jsx +++ b/src/components/JobWizard/JobWizard.jsx @@ -378,16 +378,17 @@ const JobWizard = ({ setShowSchedule(state => !state) } resolveModal() - onSuccessRequest && onSuccessRequest() - dispatch( - setNotification({ - status: 200, - id: Math.random(), - message: 'Job saved successfully' - }) - ) + + return onSuccessRequest && onSuccessRequest() }) .then(() => { + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: 'Job saved successfully' + }) + ) navigate(`/projects/${params.projectName}/jobs/${SCHEDULE_TAB}${window.location.search}`) }) .catch(error => { @@ -472,9 +473,7 @@ const JobWizard = ({ formState={formState} id="jobWizard" isWizardOpen={isOpen} - onWizardResolve={() => { - handleCloseModal() - }} + onWizardResolve={handleCloseModal} previewText={isBatchInference ? 'Tech Preview' : ''} size={MODAL_MAX} stepsConfig={getStepsConfig(formState)} diff --git a/src/hooks/useJobsPageData.js b/src/hooks/useJobsPageData.js index 6499f0d44a..e2f889ac20 100644 --- a/src/hooks/useJobsPageData.js +++ b/src/hooks/useJobsPageData.js @@ -196,7 +196,7 @@ export const useJobsPageData = (initialTabData, selectedTab) => { setScheduledJobs([]) abortControllerRef.current = new AbortController() - dispatch( + return dispatch( fetchScheduledJobs({ project: filters.project ? filters.project.toLowerCase() : params.projectName || '*', filters, From ed2e6dde0084814f5207566bbd7d21bbc449a5d7 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:23:55 +0300 Subject: [PATCH 004/228] Fix [Projects, Jobs] Unexpected redirection to the Projects page when clicking on tabs (#3277) --- src/elements/ContentMenu/ContentMenu.jsx | 37 +++++++++++++++-------- src/elements/ContentMenu/contentMenu.scss | 0 2 files changed, 24 insertions(+), 13 deletions(-) delete mode 100644 src/elements/ContentMenu/contentMenu.scss diff --git a/src/elements/ContentMenu/ContentMenu.jsx b/src/elements/ContentMenu/ContentMenu.jsx index 3c4d01b514..2995824c3f 100644 --- a/src/elements/ContentMenu/ContentMenu.jsx +++ b/src/elements/ContentMenu/ContentMenu.jsx @@ -29,7 +29,7 @@ const ContentMenu = ({ disabled = false, fontSize = 'md', onClick = null, - screen= '', + screen = '', tabs = [] }) => { const params = useParams() @@ -52,6 +52,16 @@ const ContentMenu = ({ } } + const getContentMenuItem = tab => ( + + {tab.icon && {tab.icon}} + {tab.label ?? tab.id} + {window.mlrunConfig.betaMode === 'enabled' && tab.preview && ( + (Beta) + )} + + ) + return (
diff --git a/src/elements/ContentMenu/contentMenu.scss b/src/elements/ContentMenu/contentMenu.scss deleted file mode 100644 index e69de29bb2..0000000000 From 9958f72ecaa521038672d3cc34bbaed8649dbc28 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:24:13 +0300 Subject: [PATCH 005/228] Impl [Monitoring application] Add Model endpoints with detection chart (#3279) --- .../MlChart/MetricChart/MetricChart.jsx | 7 +- .../MetricsCards/InvocationsMetricCard.jsx | 1 + .../MEPsWithDetections.jsx | 97 +++++++++++++++++++ .../MonitoringApplications.jsx | 10 +- .../monitoringApplications.util.js | 78 +++++++++++++++ .../monitoringApplicationsPage.scss | 20 +++- src/utils/getChartConfig.jsx | 68 +++++++++++-- 7 files changed, 260 insertions(+), 21 deletions(-) create mode 100644 src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx diff --git a/src/common/MlChart/MetricChart/MetricChart.jsx b/src/common/MlChart/MetricChart/MetricChart.jsx index de2c9d5b4c..e49bfc4bc7 100644 --- a/src/common/MlChart/MetricChart/MetricChart.jsx +++ b/src/common/MlChart/MetricChart/MetricChart.jsx @@ -26,7 +26,7 @@ import { setChartGradient } from './metricChart.util' import './metricChart.scss' -const MetricChart = ({ config, isInvocationCardExpanded = false }) => { +const MetricChart = ({ config, isInvocationCardExpanded = false, isInvocationChart = false }) => { const chartRef = useRef(null) const contextRef = useRef(null) @@ -76,7 +76,7 @@ const MetricChart = ({ config, isInvocationCardExpanded = false }) => { ) useEffect(() => { - if (chartRef?.current) { + if (chartRef?.current && isInvocationChart) { if (chartRef.current.options.scales.x.grid.display !== isInvocationCardExpanded) { chartRef.current.options.scales.x.grid.display = isInvocationCardExpanded chartRef.current.options.scales.y.grid.display = isInvocationCardExpanded @@ -92,7 +92,7 @@ const MetricChart = ({ config, isInvocationCardExpanded = false }) => { chartRef.current.update() } - }, [backgroundColor, config.gradient, isInvocationCardExpanded]) + }, [backgroundColor, config.gradient, isInvocationCardExpanded, isInvocationChart]) return ( { MetricChart.propTypes = { config: PropTypes.object.isRequired, isInvocationCardExpanded: PropTypes.bool, + isInvocationChart: PropTypes.bool } export default memo(MetricChart) diff --git a/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard.jsx b/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard.jsx index d33f5e8386..40077e8d49 100644 --- a/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard.jsx +++ b/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard.jsx @@ -167,6 +167,7 @@ const InvocationsMetricCard = forwardRef(
diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx new file mode 100644 index 0000000000..c2c93bb6d2 --- /dev/null +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx @@ -0,0 +1,97 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React, { memo, useMemo } from 'react' +import moment from 'moment' +import PropTypes from 'prop-types' + +import MlChart from '../../../common/MlChart/MlChart' +import { Tip } from 'igz-controls/components' +import NoData from '../../../common/NoData/NoData' + +import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicationsPage.util' +import { getMEPsWithDetectionChartConfig } from '../../../utils/getChartConfig' +import { groupDataToBins } from './monitoringApplications.util' + +const generateDummyData = (startTime, endTime) => { + const data = [] + const endDate = moment(endTime) + + for (const startDate = moment(startTime); startDate < endDate; startDate.add(30, 'minute')) { + data.push([ + startDate.utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]'), + Math.floor(Math.random() * 11) + ]) + } + + return data +} + +const MEPsWithDetections = ({ + // data, + startTime = '2025-05-22T13:32:26.685Z', + endTime = '2025-05-23T13:22:26.685Z' +}) => { + const barConfig = useMemo(() => getMEPsWithDetectionChartConfig(), []) + const data = generateDummyData(startTime, endTime) // TODO: remove and use real data + + const barChartConfig = useMemo(() => { + const datasets = groupDataToBins(data, startTime, endTime) + + return { + ...barConfig, + data: { + datasets: [ + { + data: datasets, + chartType: 'bar', + tension: 0.2, + borderWidth: 2, + backgroundColor: '#13bbb1', + borderColor: '#13bbb1' + } + ] + } + } + }, [barConfig, data, endTime, startTime]) + + return data?.length ? ( +
+
+ Model Endpoint with detections + +
+
+
+ +
+
+
+ ) : ( + + ) +} + +MEPsWithDetections.propTypes = { + // data: PropTypes.array, + startTime: PropTypes.string, + endTime: PropTypes.string +} + +export default memo(MEPsWithDetections) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx index 335b304a99..ef8464cb48 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx @@ -26,11 +26,13 @@ import NoData from '../../../common/NoData/NoData' import SectionTable from '../../../elements/SectionTable/SectionTable' import { Tip } from 'igz-controls/components' import ApplicationTableRow from '../../../elements/ApplicationTableRow/ApplicationTableRow' +import MEPsWithDetections from './MEPsWithDetections' import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicationsPage.util' import { generateOperatingFunctionsTable } from './monitoringApplications.util' import { createApplicationContent } from '../../../utils/createApplicationContent' import { removeMonitoringApplications } from '../../../reducers/monitoringApplicationsReducer' + import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' const MonitoringApplications = () => { @@ -77,13 +79,7 @@ const MonitoringApplications = () => { return (
-
-
- Controller calls - -
- -
+
Operating functions diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js index 4283181c30..0f070f0103 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js @@ -19,6 +19,7 @@ such restriction. */ import { capitalize } from 'lodash' import classnames from 'classnames' +import moment from 'moment' import { formatDatetime, generateNuclioLink } from '../../../utils' @@ -76,3 +77,80 @@ export const generateOperatingFunctionsTable = functions => { body: tableBody } } + +export function groupDataToBins(data, startTime, endTime) { + const grouped = new Map() + const endDate = new Date(endTime).setMinutes(0, 0, 0) + const basePeriod = + (new Date(endTime) - new Date(startTime)) / (1000 * 60 * 60) > 24 ? 'day' : 'hour' + + const roundDate = date => { + const dateToRound = new Date(date) + basePeriod === 'hour' ? dateToRound.setMinutes(0, 0, 0) : dateToRound.setHours(0, 0, 0, 0) + + return dateToRound + } + + // generate bins + for ( + const period = roundDate(startTime); + period.getTime() <= endDate && grouped.size < 33; + basePeriod === 'hour' + ? period.setHours(period.getHours() + 1) + : period.setDate(period.getDate() + 1) + ) { + grouped.set(period.toISOString(), 0) + } + + data.forEach(([timestamp, value]) => { + const date = roundDate(timestamp) + const dateKey = date.toISOString() + + grouped.set(dateKey, grouped.get(dateKey) + value) + }) + + const getLabel = (from, to) => { + const fromDate = moment(from) + const toDate = moment(to || from) + const shortFormatString = basePeriod === 'hour' ? 'HH-mm' : 'MM-DD' + const fullFormatString = 'YY/MM/DD, hh:mm A' + + if (!to) { + toDate.add(1, basePeriod) + } + + return { + label: `${fromDate.format(shortFormatString)} - ${toDate.format(shortFormatString)}`, + fullDate: `${fromDate.format(fullFormatString)} - ${toDate.format(fullFormatString)}` + } + } + + const groupedData = Array.from(grouped.entries()) + const dataset = groupedData.reduce((dataset, [date, value]) => { + const labelData = getLabel(date) + dataset.push({ + x: labelData.label, + y: value, + fullDate: labelData.fullDate + }) + + return dataset + }, []) + + if (dataset.length) { + // update first and last label to include more specific time + const firstLabel = getLabel(startTime, groupedData.length > 1 ? groupedData[1][0] : startTime) + + dataset[0].x = firstLabel.label + dataset[0].fullDate = firstLabel.fullDate + + if (groupedData.length > 1) { + const lastLabel = getLabel(endDate, endTime) + + dataset[dataset.length - 1].x = lastLabel.label + dataset[dataset.length - 1].fullDate = lastLabel.fullDate + } + } + + return dataset +} diff --git a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss index 06a08a1faa..503461e1c3 100644 --- a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss +++ b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss @@ -38,21 +38,21 @@ $applicationRowHeightExtended: variables.$rowHeightExtended; .monitoring-app__section-item { display: flex; flex-direction: column; - border: 1px solid colors.$frenchLilac; + padding: 20px; color: colors.$topaz; background-color: colors.$white; + border: 1px solid colors.$frenchLilac; border-radius: 8px; box-shadow: shadows.$previewBoxShadowInit; - padding: 20px; transition: all 0.3s ease-in-out; .section-item_title { display: flex; align-items: center; + margin-bottom: 20px; color: colors.$primary; font-size: 1rem; line-height: 23px; - margin-bottom: 20px; } .section-table { @@ -63,5 +63,19 @@ $applicationRowHeightExtended: variables.$rowHeightExtended; .applications-table { @include mixins.rowsHeight($applicationHeaderRowHeight, $applicationRowHeight, $applicationRowHeightExtended); } + + .section-item_chart-wrapper { + position: relative; + width: 100%; + height: 268px; + + .section-item_chart { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } + } } } diff --git a/src/utils/getChartConfig.jsx b/src/utils/getChartConfig.jsx index f161efab82..194384e382 100644 --- a/src/utils/getChartConfig.jsx +++ b/src/utils/getChartConfig.jsx @@ -106,7 +106,21 @@ const setMetricChartText = (context, tooltipModel, tooltipEl, chartType) => { } } -const generateCustomTooltip = (context, applicationChartType) => { +const setMEPWithDetectionChartText = (context, tooltipModel, tooltipEl) => { + if (tooltipModel.body) { + let innerHtml = '
' + + innerHtml += `
Date: ${context.tooltip.dataPoints[0].raw.fullDate}
` + innerHtml += `
Value: ${context.tooltip.dataPoints[0].raw.y}
` + + innerHtml += '
' + + const divRoot = tooltipEl.querySelector('div') + divRoot.innerHTML = innerHtml + } +} + +const generateCustomTooltip = (context, applicationChartType, setText = setMetricChartText) => { // ChartJs type const chartType = context.tooltip.dataPoints[0].dataset.chartType @@ -134,12 +148,7 @@ const generateCustomTooltip = (context, applicationChartType) => { return } - // Set Text - if (applicationChartType === CHART_TYPE_HISTOGRAM) { - setHistogramChartText(context, tooltipModel, tooltipEl) - } else { - setMetricChartText(context, tooltipModel, tooltipEl, chartType) - } + setText(context, tooltipModel, tooltipEl, chartType) // Display, position, and set styles for font const position = context.chart.canvas.getBoundingClientRect() @@ -238,6 +247,10 @@ export const getMetricChartConfig = type => { const barOptions = { ...defaultOptions, barThickness: 20, + borderRadius: { + topLeft: 4, + topRight: 4 + }, scales: { ...defaultOptions.scales, x: { @@ -297,7 +310,8 @@ export const getHistogramChartConfig = () => { }, tooltip: { enabled: false, - external: context => generateCustomTooltip(context, CHART_TYPE_HISTOGRAM), + external: context => + generateCustomTooltip(context, CHART_TYPE_HISTOGRAM, setHistogramChartText), mode: 'index', intersect: false, callbacks: { @@ -312,3 +326,41 @@ export const getHistogramChartConfig = () => { } } } + +export const getMEPsWithDetectionChartConfig = () => { + const barConfig = getMetricChartConfig(CHART_TYPE_BAR) + + return { + ...barConfig, + options: { + ...barConfig.options, + scales: { + ...barConfig.options.scales, + x: { + ...barConfig.options.scales.x, + title: { + ...barConfig.options.scales.x.title, + text: 'Time range' + } + }, + y: { + ...barConfig.options.scales.y, + title: { + ...barConfig.options.scales.y.title, + text: 'Model endpoint with detections' + } + } + }, + plugins: { + ...barConfig.options.plugins, + tooltip: { + enabled: false, + intersect: false, + mode: 'index', + external: context => + generateCustomTooltip(context, null, setMEPWithDetectionChartText), + } + } + } + } +} From 2d565a420503f80f086c92906e17bb8309f02ccd Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:32:10 +0300 Subject: [PATCH 006/228] Impl [LLM Prompt Artifact] Add a details overview and prompt template tabs (#3275) --- src/api/artifacts-api.js | 28 +++ .../CopyToClipboard/CopyToClipboard.jsx | 2 +- src/common/Search/Search.jsx | 9 + .../SearchNavigator/SearchNavigator.jsx | 171 ++++++++++++++++++ .../SearchNavigator/searchNavigator.scss | 58 ++++++ .../DetailsPromptTemplate.jsx | 27 +++ .../DetailsPromptTemplate/PromptTab.jsx | 87 +++++++++ .../detailsPromptTemplate.scss | 42 +++++ .../DetailsTabsContent/DetailsTabsContent.jsx | 4 + .../DetailsInfo/DetailsInfoView.jsx | 7 +- src/components/LLMPrompts/llmPrompts.util.jsx | 8 +- src/constants.js | 3 + src/elements/ContentMenu/ContentMenu.jsx | 2 +- src/elements/TableLinkCell/TableLinkCell.jsx | 11 +- src/scss/main.scss | 4 + 15 files changed, 449 insertions(+), 14 deletions(-) create mode 100644 src/common/SearchNavigator/SearchNavigator.jsx create mode 100644 src/common/SearchNavigator/searchNavigator.scss create mode 100644 src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx create mode 100644 src/components/Details/DetailsPromptTemplate/PromptTab.jsx create mode 100644 src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss diff --git a/src/api/artifacts-api.js b/src/api/artifacts-api.js index 0e9f581fc9..f63677468e 100644 --- a/src/api/artifacts-api.js +++ b/src/api/artifacts-api.js @@ -157,6 +157,34 @@ const artifactsApi = { newConfig.params.iter = iter } + // return Promise.resolve({ + // data: { + // kind: 'dataset', + // metadata: { + // key: 'test3', + // project: 'default', + // tree: '3c9a5fe2-1ffc-4c4c-864b-a712a8899fe0', + // description: '', + // iter: null, + // uid: 'c4dc3113a581a11ed69ef09258fdc0584d590f74', + // updated: '2025-05-06 08:50:01.714000+00:00', + // created: '2025-05-06 08:50:01.714000+00:00', + // tag: 'latest' + // }, + // spec: { + // target_path: 'v3io:///asd/asd', + // producer: { + // kind: 'api', + // name: 'UI', + // uri: 'dashboard.default-tenant.app.vmdev63.lab.iguazeng.com' + // }, + // db_key: 'test3' + // }, + // status: {}, + // project: 'default' + // } + // }) + return mainHttpClientV2.get(`/projects/${projectName}/artifacts/${artifactName}`, newConfig) }, getArtifacts: (project, filters, config, withExactName) => { diff --git a/src/common/CopyToClipboard/CopyToClipboard.jsx b/src/common/CopyToClipboard/CopyToClipboard.jsx index 95ec2ee0e8..7c07a3fc0a 100644 --- a/src/common/CopyToClipboard/CopyToClipboard.jsx +++ b/src/common/CopyToClipboard/CopyToClipboard.jsx @@ -75,7 +75,7 @@ const CopyToClipboard = ({ } CopyToClipboard.propTypes = { - children: PropTypes.string, + children: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), className: PropTypes.string, disabled: PropTypes.bool, textToCopy: PropTypes.string, diff --git a/src/common/Search/Search.jsx b/src/common/Search/Search.jsx index 1d7469a226..a798b8299a 100644 --- a/src/common/Search/Search.jsx +++ b/src/common/Search/Search.jsx @@ -41,6 +41,7 @@ const Search = ({ placeholder = '', searchWhileTyping = false, value = '', + withoutBorder = false, wrapperClassName = '' }) => { const [searchValue, setSearchValue] = useState(value ?? '') @@ -112,6 +113,12 @@ const Search = ({ } } + useEffect(() => { + if (searchValue.length > 0 && value !== searchValue) { + setSearchValue(value) + } + }, [searchValue, value]) + return (
{matches.length > 0 && label.length > 0 && inputIsFocused && ( { + const [matchCount, setMatchCount] = useState(0) + const [activeMatchIndex, setActiveMatchIndex] = useState(0) + const [matches, setMatches] = useState([]) + const [searchValue, setSearchValue] = useState('') + const navigatorCounterClassNames = classnames( + 'search-navigator__counter', + matchCount > 0 && 'search-navigator__counter_with-divider' + ) + + const clearResults = useCallback(() => { + setSearchResult(promptTemplate) + setMatches([]) + setActiveMatchIndex(0) + setSearchValue('') + setMatchCount(0) + }, [promptTemplate, setSearchResult]) + + const searchOnChangeHandler = useCallback( + value => { + if (value.length === 0) { + return clearResults() + } + + const regex = new RegExp(value, 'gi') + const allMatches = [...promptTemplate.matchAll(regex)] + const count = allMatches.length + let index = 0 + + const highlighted = promptTemplate.replace(regex, match => { + const marker = `${match}` + + index++ + + return marker + }) + + setSearchResult(highlighted) + setMatchCount(count) + setMatches(allMatches) + setActiveMatchIndex(0) + setSearchValue(value) + }, + [clearResults, promptTemplate, setSearchResult] + ) + + const highlightMatch = useCallback( + index => { + if (!matches.length) return + + const regex = new RegExp(promptTemplate.match(matches[0])[0], 'gi') + let current = 0 + + const highlighted = promptTemplate.replace(regex, match => { + const marker = `${match}` + + current++ + + return marker + }) + + setSearchResult(highlighted) + setActiveMatchIndex(index) + }, + [matches, promptTemplate, setSearchResult] + ) + + const goToPrevMatch = () => { + if (!matches.length) return + const prevIndex = (activeMatchIndex - 1 + matchCount) % matchCount + highlightMatch(prevIndex) + } + + const goToNextMatch = () => { + if (!matches.length) return + const nextIndex = (activeMatchIndex + 1) % matchCount + highlightMatch(nextIndex) + } + + useEffect(() => { + const activeMark = document.querySelector(`mark[data-index="${activeMatchIndex}"]`) + + if (activeMark) { + activeMark.scrollIntoView({ + behavior: 'smooth', + block: 'center' + }) + } + }, [activeMatchIndex]) + + return ( +
+ +
+ {matchCount > 0 && `${activeMatchIndex + 1}/${matchCount}`} +
+ {searchValue.length > 0 && ( +
+ + + + + + + + + +
+ )} +
+ ) +} + +SearchNavigator.propTypes = { + promptTemplate: PropTypes.string.isRequired, + setSearchResult: PropTypes.func.isRequired +} + +export default SearchNavigator diff --git a/src/common/SearchNavigator/searchNavigator.scss b/src/common/SearchNavigator/searchNavigator.scss new file mode 100644 index 0000000000..020ed961fd --- /dev/null +++ b/src/common/SearchNavigator/searchNavigator.scss @@ -0,0 +1,58 @@ +@use 'igz-controls/scss/borders'; +@use 'igz-controls/scss/colors'; + +.search-navigator { + display: flex; + align-items: center; + min-width: 280px; + border: borders.$primaryBorder; + border-radius: 4px; + + &__counter { + display: flex; + font-size: 13px; + color: colors.$topaz; + + &:after { + display: none; + content: ''; + width: 5px; + height: 15px; + margin: 0 5px 0 8px; + border-right: borders.$primaryBorder; + } + + &_with-divider { + &:after { + display: block; + } + } + } + + &__buttons { + display: flex; + padding-right: 10px; + } + + &__button { + .round-icon-cp__circle { + width: 26px; + height: 26px; + } + + &_back { + rotate: -90deg; + } + + &_next { + rotate: 90deg; + } + + &_cancel { + .round-icon-cp__circle { + width: 24px; + height: 24px; + } + } + } +} \ No newline at end of file diff --git a/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx b/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx new file mode 100644 index 0000000000..1d1dceec11 --- /dev/null +++ b/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx @@ -0,0 +1,27 @@ +import { useCallback, useState } from 'react' +import { ARGUMENTS_TAB, PROMPT_TAB } from '../../../constants' +import PromptTab from './PromptTab' + +import './detailsPromptTemplate.scss' + +const DetailsPromptTemplate = () => { + const [selectedTab, setSelectedTab] = useState(PROMPT_TAB) + const tabs = [ + { id: PROMPT_TAB, label: 'Prompt' }, + { id: ARGUMENTS_TAB, label: 'Arguments' } + ] + + const handleTabChange = useCallback(tabName => { + setSelectedTab(tabName) + }, []) + + return ( +
+ {selectedTab === PROMPT_TAB ? ( + + ) : null} +
+ ) +} + +export default DetailsPromptTemplate diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx new file mode 100644 index 0000000000..fd200c7f71 --- /dev/null +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -0,0 +1,87 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import { useState } from 'react' +import PropTypes from 'prop-types' + +import ContentMenu from '../../../elements/ContentMenu/ContentMenu' +import SearchNavigator from '../../../common/SearchNavigator/SearchNavigator' +import CopyToClipboard from '../../../common/CopyToClipboard/CopyToClipboard' + +import Copy from 'igz-controls/images/copy-to-clipboard-icon.svg?react' + +const PromptTab = ({ handleTabChange, selectedTab, tabs }) => { + const [promptTemplate] = useState( + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + + '\n' + + 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.' + ) + const [searchResult, setSearchResult] = useState('') + + const createMarkup = html => { + return { __html: html } + } + + return ( +
+
+ + + + + + Copy prompt + + +
+
+
+ ) +} + +PromptTab.propTypes = { + handleTabChange: PropTypes.func.isRequired, + selectedTab: PropTypes.string.isRequired, + tabs: PropTypes.array.isRequired +} + +export default PromptTab diff --git a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss new file mode 100644 index 0000000000..f882c18c44 --- /dev/null +++ b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss @@ -0,0 +1,42 @@ +@use 'igz-controls/scss/borders'; + +.prompt-template { + .prompt-tab { + &__header { + display: flex; + align-items: center; + margin-top: 20px; + padding-bottom: 10px; + background-color: white; + } + + &__template { + max-height: 425px; + padding: 25px 15px; + overflow-y: scroll; + border: borders.$primaryBorder; + border-radius: 4px; + } + + &__copy-btn { + display: flex; + align-items: center; + justify-content: space-between; + width: 135px; + padding: 11px 18px; + border: borders.$primaryBorder; + border-radius: 4px; + font-size: 14px; + cursor: pointer; + + &-wrapper { + margin-left: 10px; + } + + svg { + width: 14px; + height: 14px; + } + } + } +} \ No newline at end of file diff --git a/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx b/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx index 84b3adad60..3ad0c8f926 100644 --- a/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx +++ b/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx @@ -63,12 +63,14 @@ import { DETAILS_OVERVIEW_TAB, DETAILS_PODS_TAB, DETAILS_PREVIEW_TAB, + DETAILS_PROMPT_TEMPLATE_TAB, DETAILS_REQUESTED_FEATURES_TAB, DETAILS_RESULTS_TAB, DETAILS_RETURNED_FEATURES_TAB, DETAILS_STATISTICS_TAB, DETAILS_TRANSFORMATIONS_TAB } from '../../../constants' +import DetailsPromptTemplate from '../DetailsPromptTemplate/DetailsPromptTemplate' const DetailsTabsContent = ({ applyChangesRef, @@ -236,6 +238,8 @@ const DetailsTabsContent = ({ ) case DETAILS_COLLECTIONS_TAB: return + case DETAILS_PROMPT_TEMPLATE_TAB: + return default: return null } diff --git a/src/components/DetailsInfo/DetailsInfoView.jsx b/src/components/DetailsInfo/DetailsInfoView.jsx index 50075014d9..4b8defee30 100644 --- a/src/components/DetailsInfo/DetailsInfoView.jsx +++ b/src/components/DetailsInfo/DetailsInfoView.jsx @@ -37,6 +37,7 @@ import { FILES_PAGE, FUNCTIONS_PAGE, JOBS_PAGE, + LLM_PROMPTS_PAGE, MODELS_PAGE } from '../../constants' import { parseKeyValues } from '../../utils' @@ -90,7 +91,8 @@ const DetailsInfoView = React.forwardRef( pageData.page === FUNCTIONS_PAGE || pageData.page === MODELS_PAGE || pageData.page === FEATURE_STORE_PAGE || - pageData.page === DOCUMENTS_PAGE) && + pageData.page === DOCUMENTS_PAGE || + pageData.page === LLM_PROMPTS_PAGE) && params.pageTab !== FEATURE_SETS_TAB &&

General

}
    {pageData.details.infoHeaders?.map(header => { @@ -139,7 +141,8 @@ const DetailsInfoView = React.forwardRef( pageData.page === FILES_PAGE || pageData.page === MODELS_PAGE || pageData.page === FEATURE_STORE_PAGE || - pageData.page === DOCUMENTS_PAGE + pageData.page === DOCUMENTS_PAGE || + pageData.page === LLM_PROMPTS_PAGE ) { if (header.id === 'labels') { chipsData.validationRules = infoContent[header.id]?.validationRules diff --git a/src/components/LLMPrompts/llmPrompts.util.jsx b/src/components/LLMPrompts/llmPrompts.util.jsx index a00532803d..d4bb7a5bc1 100644 --- a/src/components/LLMPrompts/llmPrompts.util.jsx +++ b/src/components/LLMPrompts/llmPrompts.util.jsx @@ -49,12 +49,12 @@ export const detailsMenu = [ id: 'overview' }, { - label: 'prompt-template', - id: 'Prompt template' + label: 'Prompt template', + id: 'prompt-template' }, { - label: 'generation-configuration', - id: 'Generation configuration' + label: 'Generation configuration', + id: 'generation-configuration' } ] diff --git a/src/constants.js b/src/constants.js index a03e10ffc6..6991cac238 100644 --- a/src/constants.js +++ b/src/constants.js @@ -135,6 +135,8 @@ export const MONITORING_APP_PAGE = 'monitoring-app' export const DOCUMENTS_PAGE = 'documents' export const LLM_PROMPTS_PAGE = 'llm-prompts' +export const PROMPT_TAB = 'prompt' +export const ARGUMENTS_TAB = 'arguments' export const PROJECT_MONITOR = 'monitor' @@ -317,6 +319,7 @@ export const DETAILS_RESULTS_TAB = 'results' export const DETAILS_RETURNED_FEATURES_TAB = 'returned-features' export const DETAILS_STATISTICS_TAB = 'statistics' export const DETAILS_TRANSFORMATIONS_TAB = 'transformations' +export const DETAILS_PROMPT_TEMPLATE_TAB = 'prompt-template' export const FETCH_MODEL_FEATURE_VECTOR_BEGIN = 'FETCH_MODEL_FEATURE_VECTOR_BEGIN' export const FETCH_MODEL_FEATURE_VECTOR_FAILURE = 'FETCH_MODEL_FEATURE_VECTOR_FAILURE' export const FETCH_MODEL_FEATURE_VECTOR_SUCCESS = 'FETCH_MODEL_FEATURE_VECTOR_SUCCESS' diff --git a/src/elements/ContentMenu/ContentMenu.jsx b/src/elements/ContentMenu/ContentMenu.jsx index 2995824c3f..137a629da9 100644 --- a/src/elements/ContentMenu/ContentMenu.jsx +++ b/src/elements/ContentMenu/ContentMenu.jsx @@ -104,7 +104,7 @@ const ContentMenu = ({ ContentMenu.propTypes = { activeTab: PropTypes.string.isRequired, disabled: PropTypes.bool, - fontSize: PropTypes.oneOf(['sm', 'md', 'lg']), + fontSize: PropTypes.oneOf(['xs', 'sm', 'md', 'lg']), onClick: PropTypes.func, screen: PropTypes.string, tabs: CONTENT_MENU_TABS.isRequired diff --git a/src/elements/TableLinkCell/TableLinkCell.jsx b/src/elements/TableLinkCell/TableLinkCell.jsx index 6ac5539b31..8725530168 100644 --- a/src/elements/TableLinkCell/TableLinkCell.jsx +++ b/src/elements/TableLinkCell/TableLinkCell.jsx @@ -80,10 +80,7 @@ const TableLinkCell = ({ {data.showStatus && stateValue && stateLabel && ( - } - > + }> )} @@ -99,7 +96,8 @@ const TableLinkCell = ({ link.match(/models/) || link.match(/files/) || link.match(/datasets/) || - link.match(/documents/)) && + link.match(/documents/) || + link.match(/llm-prompts/)) && Object.values(selectedItem).length !== 0)) && (
    {(item.startTime || item.updated) && ( @@ -108,7 +106,8 @@ const TableLinkCell = ({ (link.match(/functions/) || link.match(/models/) || link.match(/files/) || - link.match(/datasets/) + link.match(/datasets/) || + link.match(/llm-prompts/) ? formatDatetime(item.updated, 'N/A') : formatDatetime( item.startTime || item.created, diff --git a/src/scss/main.scss b/src/scss/main.scss index 0487c07d94..10a31f8eac 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -78,6 +78,10 @@ body { padding-left: 0; } + &-xs { + font-size: 16px; + } + &-sm { font-size: 16px; From 03871571ffa5923f2eabee16afa495c22a2ae35c Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:32:38 +0300 Subject: [PATCH 007/228] Impl [Monitoring application] Add Model Endpoints metrics (#3280) --- src/App.jsx | 11 + .../HistoryBackLink/historyBackLink.jsx | 8 +- .../MlChart/HistogramChart/HistogramChart.jsx | 2 - src/common/MlChart/MlChart.jsx | 2 + .../histogramChart.scss => mlChart.scss} | 2 - .../ApplicationMetrics/ApplicationMetrics.jsx | 341 ++++++++++++++++++ .../ApplicationMetrics.scss | 125 +++++++ .../DetailsMetrics/DetailsMetrics.jsx | 69 ++-- .../DetailsMetrics/DetailsMetrics.scss | 33 +- .../DetailsMetrics/detailsMetrics.util.jsx | 3 +- .../MonitoringApplications.jsx | 5 +- .../MonitoringApplicationsPage.jsx | 7 +- .../MetricsSelector/MetricsSelector.jsx | 82 +++-- .../MetricsSelector/metricsSelector.scss | 7 +- src/reducers/detailsReducer.js | 4 +- tests/mockServer/data/metrics.json | 6 +- 16 files changed, 612 insertions(+), 95 deletions(-) rename src/common/MlChart/{HistogramChart/histogramChart.scss => mlChart.scss} (88%) create mode 100644 src/components/ApplicationMetrics/ApplicationMetrics.jsx create mode 100644 src/components/ApplicationMetrics/ApplicationMetrics.scss diff --git a/src/App.jsx b/src/App.jsx index c4d80186ab..555d462e92 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -124,6 +124,9 @@ const WorkflowsMonitoring = lazyRetry( ) const Documents = lazyRetry(() => import('./components/Documents/Documents')) const LLMPrompts = lazyRetry(() => import('./components/LLMPrompts/LLMPrompts')) +const ApplicationMetrics = lazyRetry( + () => import('./components/ApplicationMetrics/ApplicationMetrics') +) const MonitoringApplicationsPage = lazyRetry( () => import('./components/MonitoringApplicationsPage/MonitoringApplicationsPage') @@ -337,6 +340,14 @@ const App = () => { } /> ))} + {[ + `projects/:projectName/monitoring-app/:appName/${MODEL_ENDPOINTS_TAB}`, + `projects/:projectName/monitoring-app/:appName/${MODEL_ENDPOINTS_TAB}/:id` + ].map((path, index) => ( + + } /> + + ))} } diff --git a/src/common/HistoryBackLink/historyBackLink.jsx b/src/common/HistoryBackLink/historyBackLink.jsx index de62891317..c48e2358de 100644 --- a/src/common/HistoryBackLink/historyBackLink.jsx +++ b/src/common/HistoryBackLink/historyBackLink.jsx @@ -28,7 +28,7 @@ import HistoryIcon from 'igz-controls/images/history.svg?react' import './historyBackLink.scss' -const HistoryBackLink = ({ itemName, link }) => { +const HistoryBackLink = ({ itemName, link, customText = '', customIcon = null }) => { return (
    @@ -37,9 +37,9 @@ const HistoryBackLink = ({ itemName, link }) => {
    - + {customIcon ? customIcon : }
    - Version history:{' '} + {`${customText || 'Version history'}: `}
    }>{itemName}
    @@ -48,6 +48,8 @@ const HistoryBackLink = ({ itemName, link }) => { } HistoryBackLink.propTypes = { + customIcon: PropTypes.element, + customText: PropTypes.string, itemName: PropTypes.string.isRequired, link: PropTypes.string.isRequired } diff --git a/src/common/MlChart/HistogramChart/HistogramChart.jsx b/src/common/MlChart/HistogramChart/HistogramChart.jsx index a064bdc3d5..7d3c9c1828 100644 --- a/src/common/MlChart/HistogramChart/HistogramChart.jsx +++ b/src/common/MlChart/HistogramChart/HistogramChart.jsx @@ -22,8 +22,6 @@ import PropTypes from 'prop-types' import MlChart from '../MlChart' -import './histogramChart.scss' - const HistogramChart = ({ config, showLoader = true }) => { const chartConfig = useMemo(() => { const pythonInfinity = 'e+308' diff --git a/src/common/MlChart/MlChart.jsx b/src/common/MlChart/MlChart.jsx index 19636499c7..e917a9ef86 100644 --- a/src/common/MlChart/MlChart.jsx +++ b/src/common/MlChart/MlChart.jsx @@ -23,6 +23,8 @@ import { Chart } from 'chart.js/auto' import Loader from '../Loader/Loader' import classnames from 'classnames' +import './mlChart.scss' + const defaultOnChartCreated = () => {} const MlChart = ({ diff --git a/src/common/MlChart/HistogramChart/histogramChart.scss b/src/common/MlChart/mlChart.scss similarity index 88% rename from src/common/MlChart/HistogramChart/histogramChart.scss rename to src/common/MlChart/mlChart.scss index e65e6c17dc..c792ca5be8 100644 --- a/src/common/MlChart/HistogramChart/histogramChart.scss +++ b/src/common/MlChart/mlChart.scss @@ -1,5 +1,3 @@ -@use 'igz-controls/scss/colors'; - .chart-container { display: flex; align-items: center; diff --git a/src/components/ApplicationMetrics/ApplicationMetrics.jsx b/src/components/ApplicationMetrics/ApplicationMetrics.jsx new file mode 100644 index 0000000000..5864f7df63 --- /dev/null +++ b/src/components/ApplicationMetrics/ApplicationMetrics.jsx @@ -0,0 +1,341 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { Link, useNavigate, useParams } from 'react-router-dom' +import { useDispatch, useSelector } from 'react-redux' +import { debounce, isEmpty } from 'lodash' +import { createForm } from 'final-form' +import { Form } from 'react-final-form' +import classNames from 'classnames' + +import HistoryBackLink from '../../common/HistoryBackLink/historyBackLink' +import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' +import Loader from '../../common/Loader/Loader' +import DetailsMetrics from '../DetailsMetrics/DetailsMetrics' +import NoData from '../../common/NoData/NoData' +import { + Button, + FormInput, + FormOnChange, + RoundedIcon, + TextTooltipTemplate, + Tooltip +} from 'igz-controls/components' + +import { fetchModelEndpoints } from '../../reducers/artifactsReducer' +import { + DETAILS_OVERVIEW_TAB, + MODEL_ENDPOINTS_TAB, + MODELS_PAGE, + MONITORING_APP_PAGE, + REQUEST_CANCELED +} from '../../constants' +import { getScssVariableValue } from 'igz-controls/utils/common.util' +import { isRowRendered, useVirtualization } from '../../hooks/useVirtualization.hook' +import { fetchMonitoringApplication } from '../../reducers/monitoringApplicationsReducer' +import { PRIMARY_BUTTON } from 'igz-controls/constants' + +import RefreshIcon from 'igz-controls/images/refresh.svg?react' +import SearchIcon from 'igz-controls/images/search.svg?react' +import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' + +import './ApplicationMetrics.scss' + +export const LIST_ID = 'LIST_ID' +export const LIST_ITEMS_ID = 'LIST_ITEMS_ID' + +const ApplicationMetrics = () => { + const [requestErrorMessage, setRequestErrorMessage] = useState('') + const [selectedModelEndpoint, setSelectedModelEndpoint] = useState({}) + const [modelEndpoints, setModelEndpoints] = useState([]) + const [searchName, setSearchName] = useState('') + const detailsStore = useSelector(store => store.detailsStore) + const artifactsStore = useSelector(store => store.artifactsStore) + const applicationsStore = useSelector(store => store.monitoringApplicationsStore) + const dispatch = useDispatch() + const navigate = useNavigate() + const params = useParams() + const abortControllerRef = useRef() + + const filteredEndpoints = useMemo(() => { + return modelEndpoints.filter(modelEndpoint => { + return !searchName || modelEndpoint.name?.toLowerCase()?.includes(searchName.toLowerCase()) + }) + }, [modelEndpoints, searchName]) + + const listItemHeight = useMemo(() => getScssVariableValue('--listItemHeight'), []) + const searchHeight = useMemo(() => getScssVariableValue('--searchHeight'), []) + + const rowsSizes = useMemo( + () => new Array(filteredEndpoints.length).fill(parseInt(listItemHeight)), + [listItemHeight, filteredEndpoints.length] + ) + const heightData = useMemo( + () => ({ + headerRowHeight: searchHeight, + rowHeight: listItemHeight, + rowHeightExtended: listItemHeight + }), + [listItemHeight, searchHeight] + ) + + const virtualizationConfig = useVirtualization({ + renderTriggerItem: modelEndpoints, + heightData, + rowsSizes, + tableBodyId: LIST_ID, + tableId: LIST_ITEMS_ID + }) + + const formRef = React.useRef( + createForm({ + initialValues: { + MEPSearchName: '' + }, + onSubmit: () => {} + }) + ) + + const fetchModelEndpointsData = useCallback(() => { + abortControllerRef.current = new AbortController() + + dispatch( + fetchModelEndpoints({ + project: params.projectName, + filters: {}, + config: { + ui: { + controller: abortControllerRef.current, + setRequestErrorMessage + } + }, + params: { + latest_only: 'True' + } + }) + ) + .unwrap() + .then(modelEndpoints => { + if (modelEndpoints) { + setModelEndpoints(modelEndpoints) + } + }) + }, [dispatch, params.projectName]) + + const setSearchNameDebounced = useMemo( + () => + debounce(name => { + setSearchName(name) + }, 500), + [setSearchName] + ) + + useEffect(() => { + if ( + applicationsStore.monitoringApplications.applications?.find( + app => app.name === params.appName + ) + ) { + fetchModelEndpointsData() + } else { + dispatch( + fetchMonitoringApplication({ project: params.projectName, functionName: params.appName }) + ) + .unwrap() + .then(app => { + if (!isEmpty(app)) { + fetchModelEndpointsData() + } else { + navigate( + `/projects/${params.projectName}/${MONITORING_APP_PAGE}${window.location.search}`, + { replace: true } + ) + } + }) + .catch(() => { + navigate( + `/projects/${params.projectName}/${MONITORING_APP_PAGE}${window.location.search}`, + { replace: true } + ) + }) + } + + return () => { + abortControllerRef.current?.abort?.(REQUEST_CANCELED) + } + + // navigate triggers this use effect when we select first item in the list if id is not in the URL + // if adding new deps, please double check it by removing next comment + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + applicationsStore.monitoringApplications.applications, + dispatch, + fetchModelEndpointsData, + params.appName, + params.projectName + ]) + + useEffect(() => { + if (params.id && modelEndpoints.length > 0) { + const searchItem = modelEndpoints.find(item => item.metadata?.uid === params.id) + + if (!searchItem) { + navigate( + `/projects/${params.projectName}/${MONITORING_APP_PAGE}/${params.appName}/${MODEL_ENDPOINTS_TAB}/${modelEndpoints[0].metadata.uid}${window.location.search}`, + { replace: true } + ) + } else { + setSelectedModelEndpoint(searchItem) + } + } else if (modelEndpoints.length > 0) { + navigate( + `/projects/${params.projectName}/${MONITORING_APP_PAGE}/${params.appName}/${MODEL_ENDPOINTS_TAB}/${modelEndpoints[0].metadata.uid}${window.location.search}`, + { replace: true } + ) + } else { + setSelectedModelEndpoint({}) + } + }, [dispatch, modelEndpoints, navigate, params.id, params.appName, params.projectName]) + + return ( +
    +
    + +
    +
    +
    +
    + } + /> +
    +
    +
    +
    + {(artifactsStore.modelEndpoints.loading || + applicationsStore.loading || + detailsStore.loadingCounter > 0) && } + {artifactsStore.modelEndpoints.loading || + applicationsStore.loading ? null : modelEndpoints.length === 0 ? ( + + ) : ( + <> +
    +
    {}}> + {() => ( +
    +
    + } + name="MEPSearchName" + placeholder="Search endpoint..." + /> + +
    +
    {`${filteredEndpoints.length} endpoint${filteredEndpoints.length !== 1 ? 's' : ''} found`}
    +
    + )} +
    +
    +
    +
      + {filteredEndpoints.map((modelEndpoint, modelEndpointIndex) => { + return ( + isRowRendered(virtualizationConfig, modelEndpointIndex) && ( +
    • + + } + > + {modelEndpoint.name} + + +
    • + ) + ) + })} +
    +
    +
    +
    +
    +
    +
    + {!isEmpty(selectedModelEndpoint) && ( + ( + + } + > + {selectedModelEndpoint.name} + + + )} + /> + )} +
    +
    +
    + + )} +
    +
    +
    +
    + ) +} + +export default ApplicationMetrics diff --git a/src/components/ApplicationMetrics/ApplicationMetrics.scss b/src/components/ApplicationMetrics/ApplicationMetrics.scss new file mode 100644 index 0000000000..b95c5e6980 --- /dev/null +++ b/src/components/ApplicationMetrics/ApplicationMetrics.scss @@ -0,0 +1,125 @@ +@use 'igz-controls/scss/shadows'; +@use 'igz-controls/scss/colors'; +@use 'igz-controls/scss/borders'; + +$listItemHeight: 52px; +$searchHeight: 75px; + +:root { + --listItemHeight: #{$listItemHeight}; + --searchHeight: #{$searchHeight}; +} + +.application-metrics-container { + height: 100%; + + .content__action-bar-wrapper { + margin-bottom: 10px; + + .action-bar { + gap: 15px; + align-items: center; + } + } + + .list-view { + display: flex; + gap: 20px; + height: calc(100% - 60px); + + .list-view__section { + width: 100%; + height: 100%; + padding: 16px; + background-color: colors.$white; + border: borders.$primaryBorder; + border-radius: 8px; + box-shadow: shadows.$previewBoxShadowInit; + } + + .list-view__section-list { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + width: 270px; + min-width: 270px; + max-width: 270px; + + .list-view__section-list__search { + height: $searchHeight; + + .list-view__section-list__search_endpoints-counter { + color: colors.$topaz; + font-weight: 500; + font-size: 13px; + line-height: 35px; + } + } + + .list-view__section-list__items-wrapper { + position: relative; + width: 100%; + height: 100%; + + .list-view__section-list__items { + position: absolute; + width: 100%; + height: 100%; + overflow-y: auto; + + ul { + margin: 0; + padding: 0; + list-style: none; + + li { + padding: 0 8px; + border-radius: 8px; + cursor: pointer; + user-select: none; + + div { + height: $listItemHeight; + line-height: $listItemHeight; + border-bottom: borders.$primaryBorder; + } + + &:hover, + &.active { + background-color: colors.$ghostWhite; + } + } + + li:last-child { + div { + border-bottom: none; + } + } + } + } + } + } + + .list-view__section-details { + position: relative; + min-width: 700px; + + .list-view__section__metrics-content-wrapper { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 20px; + + .list-view__section__metrics-content { + height: 100%; + padding-right: 20px; + overflow-y: auto; + } + } + } + } +} diff --git a/src/components/DetailsMetrics/DetailsMetrics.jsx b/src/components/DetailsMetrics/DetailsMetrics.jsx index 1d2ac8f42a..b88f8122e1 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.jsx +++ b/src/components/DetailsMetrics/DetailsMetrics.jsx @@ -54,7 +54,7 @@ import MetricsIcon from 'igz-controls/images/metrics-icon.svg?react' import './DetailsMetrics.scss' -const DetailsMetrics = ({ selectedItem }) => { +const DetailsMetrics = ({ applicationNameProp = '', selectedItem, renderTitle = null }) => { const [metrics, setMetrics] = useState([]) const [selectedDate, setSelectedDate] = useState('') const [previousTotalInvocation, setPreviousTotalInvocation] = useState(0) @@ -118,12 +118,13 @@ const DetailsMetrics = ({ selectedItem }) => { dispatch( fetchModelEndpointMetrics({ project: selectedItem.metadata.project, - uid: selectedItem.metadata.uid + uid: selectedItem.metadata.uid, + applicationName: applicationNameProp }) ) .unwrap() .then(() => setMetricOptionsAreLoaded(true)) - }, [dispatch, selectedItem.metadata.project, selectedItem.metadata.uid]) + }, [applicationNameProp, dispatch, selectedItem.metadata.project, selectedItem.metadata.uid]) useEffect(() => { const selectedDate = detailsStore.dates.selectedOptionId @@ -234,32 +235,36 @@ const DetailsMetrics = ({ selectedItem }) => { return (
    -
    - - dispatch( - setSelectedMetricsOptions({ - endpointUid: selectedItem.metadata.uid, - metrics - }) - ) - } - preselectedMetrics={detailsStore.metricsOptions.preselected} - /> - +
    + {renderTitle &&

    {renderTitle()}

    } +
    + + dispatch( + setSelectedMetricsOptions({ + endpointUid: selectedItem.metadata.uid, + metrics + }) + ) + } + preselectedMetrics={detailsStore.metricsOptions.preselected} + /> + +
    {generatedMetrics.length === 0 ? ( !detailsStore.loadingCounter ? ( @@ -278,7 +283,7 @@ const DetailsMetrics = ({ selectedItem }) => { return (
    - {applicationName === ML_RUN_INFRA ? '' : applicationName} + {applicationName === ML_RUN_INFRA || applicationNameProp ? '' : applicationName}
    {applicationMetrics.map(metric => { if (applicationName === ML_RUN_INFRA) { @@ -326,7 +331,9 @@ const DetailsMetrics = ({ selectedItem }) => { } DetailsMetrics.propTypes = { - selectedItem: PropTypes.object, + applicationNameProp: PropTypes.string, + selectedItem: PropTypes.object.isRequired, + renderTitle: PropTypes.func } export default React.memo(DetailsMetrics) diff --git a/src/components/DetailsMetrics/DetailsMetrics.scss b/src/components/DetailsMetrics/DetailsMetrics.scss index c0fcd57790..8bf7e95a2a 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.scss +++ b/src/components/DetailsMetrics/DetailsMetrics.scss @@ -4,22 +4,37 @@ $stickyHeaderHeight: 55px; .metrics-wrapper { - &__custom-filters { + &__header { position: sticky; top: 0; z-index: 2; display: flex; - flex-wrap: wrap; - align-items: center; - justify-content: flex-end; - background-color: colors.$white; + justify-content: space-between; + + &__custom-filters { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: flex-end; + width: 100%; + background-color: colors.$white; - > * { - margin: 0 0 15px 0; + > * { + margin: 0 0 15px 0; + } + + .details-date-picker { + margin-left: 15px; + } } - .details-date-picker { - margin-left: 15px; + &__title { + max-width: 350px; + font-size: 24px; + + a:hover { + text-decoration: underline; + } } } diff --git a/src/components/DetailsMetrics/detailsMetrics.util.jsx b/src/components/DetailsMetrics/detailsMetrics.util.jsx index 6d45323988..aa3ed4ed5b 100644 --- a/src/components/DetailsMetrics/detailsMetrics.util.jsx +++ b/src/components/DetailsMetrics/detailsMetrics.util.jsx @@ -166,8 +166,9 @@ const generateResultMessage = (driftStatus, resultKind) => { return `${capitalize(resultKindMessage)} ${text.toLowerCase().replace('drift', '').trim()}` } -export const generateMetricsItems = metrics => { +export const generateMetricsItems = (metrics, applicationName) => { return chain(metrics) + .filter(metric => !applicationName || metric.app === applicationName || metric.app === ML_RUN_INFRA) // todo remove filter when API will support app param .sortBy(metric => metric.label) .map(metric => { return { diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx index ef8464cb48..d94e33312c 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx @@ -32,6 +32,7 @@ import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicatio import { generateOperatingFunctionsTable } from './monitoringApplications.util' import { createApplicationContent } from '../../../utils/createApplicationContent' import { removeMonitoringApplications } from '../../../reducers/monitoringApplicationsReducer' +import { MODEL_ENDPOINTS_TAB, MONITORING_APP_PAGE } from '../../../constants' import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' @@ -51,11 +52,11 @@ const MonitoringApplications = () => { id: 'open-metrics', label: 'Open metrics', icon: , - onClick: data => navigate(data.name) + onClick: data => navigate(`/projects/${params.projectName}/${MONITORING_APP_PAGE}/${data.name}/${MODEL_ENDPOINTS_TAB}${window.location.search}`) } ] ], - [navigate] + [navigate, params.projectName] ) const operatingFunctionsTable = useMemo( () => generateOperatingFunctionsTable(operatingFunctions), diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index baa93432ce..16d9e60ab9 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import React, { useCallback, useMemo } from 'react' -import { Outlet, useParams, useSearchParams } from 'react-router-dom' +import { Outlet, useNavigate, useParams, useSearchParams } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import ActionBar from '../ActionBar/ActionBar' @@ -27,6 +27,7 @@ import TableTop from '../../elements/TableTop/TableTop' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import MonitoringApplicationCounters from './MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCounters' +import { MODEL_ENDPOINTS_TAB, MONITORING_APP_PAGE } from '../../constants' import { getFiltersConfig } from './MonitoringApplicationsPage.util' import { showErrorNotification } from '../../utils/notifications.util' import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' @@ -38,7 +39,6 @@ import { import { fetchArtifacts } from '../../reducers/artifactsReducer' import { PRIMARY_BUTTON } from 'igz-controls/constants' -import { MONITORING_APP_PAGE } from '../../constants' import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' @@ -47,6 +47,7 @@ import './monitoringApplicationsPage.scss' const MonitoringApplicationsPage = () => { const dispatch = useDispatch() const params = useParams() + const navigate = useNavigate() const monitoringApplicationsStore = useSelector(store => store.monitoringApplicationsStore) const filtersConfig = useMemo(() => getFiltersConfig(), []) const filters = useFiltersFromSearchParams(filtersConfig) @@ -129,7 +130,7 @@ const MonitoringApplicationsPage = () => { label: 'Application metrics', className: 'action-button', hidden: !params.name, - onClick: () => {}, + onClick: () => {navigate(`/projects/${params.projectName}/${MONITORING_APP_PAGE}/${params.name}/${MODEL_ENDPOINTS_TAB}${window.location.search}`)}, icon: } ]} diff --git a/src/elements/MetricsSelector/MetricsSelector.jsx b/src/elements/MetricsSelector/MetricsSelector.jsx index f31d324b01..3b8ec6efd1 100644 --- a/src/elements/MetricsSelector/MetricsSelector.jsx +++ b/src/elements/MetricsSelector/MetricsSelector.jsx @@ -50,6 +50,7 @@ import SearchIcon from 'igz-controls/images/search.svg?react' import './metricsSelector.scss' const MetricsSelector = ({ + applicationName = '', disabled = false, maxSelectionNumber = 20, metrics, @@ -257,43 +258,53 @@ const MetricsSelector = ({
      {({ fields }) => { + const renderMetrics = metricsList => { + return ( +
        + {metricsList.metrics.map(metricItem => { + return ( + = maxSelectionNumber && + !fields.value.includes(metricItem.id) + }} + name={name} + multiple + /> + ) + })}{' '} +
      + ) + } + return ( <> - {filteredMetrics.map(metricsGroup => { - return !isEmpty(metricsGroup.metrics) ? ( - } - iconClassName="metrics-selector-accordion-icon" - openByDefault - > -
      -
      - {metricsGroup.app} -
      -
        - {metricsGroup.metrics.map(metricItem => { - return ( - = maxSelectionNumber && - !fields.value.includes(metricItem.id) - }} - name={name} - multiple - /> - ) - })} -
      -
      -
      - ) : null - })} + {applicationName + ? renderMetrics(filteredMetrics[0] || []) + : filteredMetrics.map(metricsGroup => { + return !isEmpty(metricsGroup.metrics) ? ( + } + iconClassName="metrics-selector-accordion-icon" + openByDefault + > +
      +
      + {metricsGroup.app} +
      +
        + {renderMetrics(metricsGroup)} +
      +
      +
      + ) : null + })} ) }} @@ -325,6 +336,7 @@ const MetricsSelector = ({ } MetricsSelector.propTypes = { + applicationName: PropTypes.string, disabled: PropTypes.bool, maxSelectionNumber: PropTypes.number, metrics: METRICS_SELECTOR_OPTIONS.isRequired, diff --git a/src/elements/MetricsSelector/metricsSelector.scss b/src/elements/MetricsSelector/metricsSelector.scss index dc408e3ea5..55e81c3801 100644 --- a/src/elements/MetricsSelector/metricsSelector.scss +++ b/src/elements/MetricsSelector/metricsSelector.scss @@ -22,8 +22,8 @@ } &_disabled { - border: borders.$disabledBorder; color: colors.$spunPearl; + border: borders.$disabledBorder; cursor: not-allowed; .metrics-selector-header__icon { @@ -79,7 +79,6 @@ .select__item { height: 50px; - padding-left: 35px; label { overflow: hidden; @@ -128,6 +127,10 @@ &.open { height: 100%; } + + .select__item { + padding-left: 35px; + } } &-icon { diff --git a/src/reducers/detailsReducer.js b/src/reducers/detailsReducer.js index 7e2b2e6e76..f8bdf451f4 100644 --- a/src/reducers/detailsReducer.js +++ b/src/reducers/detailsReducer.js @@ -105,11 +105,11 @@ export const fetchJobPods = createAsyncThunk('fetchJobPods', ({ project, uid, ki export const fetchModelEndpointMetrics = createAsyncThunk( 'fetchEndpointMetrics', - ({ project, uid }, thunkAPI) => { + ({ project, uid, applicationName = '' }, thunkAPI) => { return modelEndpointsApi .getModelEndpointMetrics(project, uid) .then(({ data = [] }) => { - const metrics = generateMetricsItems(data) + const metrics = generateMetricsItems(data, applicationName) return { endpointUid: uid, metrics } }) diff --git a/tests/mockServer/data/metrics.json b/tests/mockServer/data/metrics.json index 7b9c00f846..6dc5f883fb 100644 --- a/tests/mockServer/data/metrics.json +++ b/tests/mockServer/data/metrics.json @@ -33,9 +33,9 @@ "project": "default" }, { - "full_name": "default.evidently-app-test.result.hellinger_mean_1", + "full_name": "default.monitorAppV1.result.hellinger_mean_1", "type": "result", - "app": "evidently-app-test", + "app": "monitorAppV1", "name": "hellinger_mean_1", "project": "default" }, @@ -122,7 +122,7 @@ "data": false }, { - "full_name": "default.evidently-app-test.result.hellinger_mean_1", + "full_name": "default.monitorAppV1.result.hellinger_mean_1", "type": "result", "result_kind": 0, "data": "true", From 6fa30ccdd3fccca2ed024239f255f7837cd08c5d Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:57:43 +0300 Subject: [PATCH 008/228] Fix [UI] Missing redirection to the Projects page when MLRun is unhealthy (#3282) --- src/components/ProjectsPage/ProjectsView.jsx | 2 +- src/layout/Page/Page.jsx | 6 +++++- src/reducers/projectReducer.js | 21 +++++++++++--------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/components/ProjectsPage/ProjectsView.jsx b/src/components/ProjectsPage/ProjectsView.jsx index ec2d549d5c..fc9a58923e 100644 --- a/src/components/ProjectsPage/ProjectsView.jsx +++ b/src/components/ProjectsPage/ProjectsView.jsx @@ -77,7 +77,7 @@ const ProjectsView = ({ {(projectStore.loading || projectStore.project.loading || tasksStore.loading) && } {projectStore.mlrunUnhealthy.isUnhealthy && ( - MMLRun seems to be down. Try again in a few minutes. + MLRun seems to be down. Try again in a few minutes. )} {createProject && ( diff --git a/src/layout/Page/Page.jsx b/src/layout/Page/Page.jsx index 1f2b262b4f..41e2f2f9aa 100644 --- a/src/layout/Page/Page.jsx +++ b/src/layout/Page/Page.jsx @@ -66,12 +66,16 @@ const Page = () => { useEffect(() => { if (projectsList.length === 0 && location.pathname !== '/projects') { - dispatch(fetchProjects({ params: { format: 'minimal' } })) + dispatch(fetchProjects({ params: { format: 'minimal' }, showNotification: false })) .unwrap() .then(projects => { isProjectValid(navigate, projects, projectName, dispatch) setProjectFetched(true) }) + .catch(() => { + setProjectFetched(true) + navigate('/projects') + }) } else { setProjectFetched(true) } diff --git a/src/reducers/projectReducer.js b/src/reducers/projectReducer.js index 0fd11ab98e..bce1e7b2c9 100644 --- a/src/reducers/projectReducer.js +++ b/src/reducers/projectReducer.js @@ -261,7 +261,7 @@ export const fetchProjectSummary = createAsyncThunk( ) export const fetchProjects = createAsyncThunk( 'fetchProjects', - ({ params, setRequestErrorMessage = () => {} }, thunkAPI) => { + ({ params, setRequestErrorMessage = () => {}, showNotification = true }, thunkAPI) => { setRequestErrorMessage('') return projectsApi @@ -270,14 +270,17 @@ export const fetchProjects = createAsyncThunk( return parseProjects(response.data.projects) }) .catch(error => { - showErrorNotification( - thunkAPI.dispatch, - error, - 'Failed to fetch projects', - null, - null, - setRequestErrorMessage - ) + if (showNotification) { + showErrorNotification( + thunkAPI.dispatch, + error, + 'Failed to fetch projects', + null, + null, + setRequestErrorMessage + ) + } + return thunkAPI.rejectWithValue(error) }) } From a64fb1c77cff690813386cf98d49d9e070dcc713 Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Tue, 3 Jun 2025 21:59:23 +0200 Subject: [PATCH 009/228] Tests [QA] v1.10.0-rc3 (#3283) --- tests/features/common-tools/common-consts.js | 2 +- tests/features/common-tools/common-tools.js | 81 +++---- tests/features/common-tools/utils.js | 2 +- .../common/actions/action-menu.action.js | 26 +-- tests/features/common/actions/api.actions.js | 99 ++++----- .../common/actions/checkbox.action.js | 31 +-- .../features/common/actions/common.action.js | 207 ++++++++++-------- .../common/actions/date-picker.action.js | 19 +- .../common/actions/dropdown.action.js | 50 +++-- tests/features/common/actions/graph.action.js | 6 +- .../common/actions/input-group.action.js | 127 +++++------ .../actions/input-with-autocomplete.action.js | 24 +- .../actions/number-input-group.action.js | 11 +- .../common/actions/radio-button.action.js | 16 +- .../common/actions/tab-selector.action.js | 11 +- tests/features/common/actions/table.action.js | 160 ++++++++------ .../components/action-menu.component.js | 2 +- .../components/breadcrumbs.component.js | 6 +- .../common/components/checkbox.component.js | 2 +- .../common/components/combo-box.component.js | 2 +- .../components/date-picker.component.js | 2 +- .../common/components/dropdown.component.js | 2 +- .../common/components/graph.component.js | 2 +- .../components/input-group.component.js | 2 +- .../input-with-autocomplete.component.js | 2 +- .../common/components/label.component.js | 2 +- .../number-input-group.component.js | 2 +- .../components/radio-button.component.js | 2 +- .../single-date-picker.component.js | 2 +- .../common/components/table.component.js | 2 +- .../common/components/text-area.component.js | 2 +- tests/features/common/page-objects.js | 2 +- .../page-objects/alerts-monitoring.po.js | 2 +- .../features/common/page-objects/alerts.po.js | 2 +- .../page-objects/commonPagesHeader.po.js | 2 +- .../common/page-objects/documents.po.js | 2 +- .../common/page-objects/feature-store.po.js | 2 +- .../features/common/page-objects/files.po.js | 2 +- .../common/page-objects/info-pane.po.js | 2 +- .../page-objects/interactive-popup.po.js | 5 +- .../page-objects/jobs-and-workflows.po.js | 2 +- .../common/page-objects/jobs-monitoring.po.js | 2 +- .../common/page-objects/ml-functions.po.js | 2 +- .../features/common/page-objects/models.po.js | 2 +- .../common/page-objects/monitoring-app.po.js | 2 +- .../page-objects/project-settings.po.js | 2 +- .../common/page-objects/project.po.js | 46 ++-- .../common/page-objects/projects.po.js | 6 +- .../common/page-objects/side-panel.po.js | 4 +- tests/features/datasets.feature | 1 + tests/features/jobsAndWorkflows.feature | 13 +- tests/features/projectMonitoring.feature | 19 +- tests/features/projectsPage.feature | 5 +- tests/features/step-definitions/steps.js | 4 +- tests/features/support/world.js | 4 +- 55 files changed, 557 insertions(+), 484 deletions(-) diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index 9bb10f8560..ca180a98be 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -module.exports = { +export default { Project: { Create_New_Options: [ 'Batch run', diff --git a/tests/features/common-tools/common-tools.js b/tests/features/common-tools/common-tools.js index 4383c2891f..7346e0f43d 100644 --- a/tests/features/common-tools/common-tools.js +++ b/tests/features/common-tools/common-tools.js @@ -28,19 +28,19 @@ import { deleteAPISchedule } from '../common/actions/api.actions' -module.exports = { - locatorBuilder: function (strings, ...keys) { - return function (...values) { - const dict = values[values.length - 1] || {} - const result = [strings[0]] - keys.forEach(function (key, i) { - const value = Number.isInteger(key) ? values[key] : dict[key] - result.push(value, strings[i + 1]) - }) - return result.join('') - } - }, - generateInputGroup: function ( +export function locatorBuilder(strings, ...keys) { + return function (...values) { + const dict = values[values.length - 1] || {} + const result = [strings[0]] + keys.forEach(function (key, i) { + const value = Number.isInteger(key) ? values[key] : dict[key] + result.push(value, strings[i + 1]) + }) + return result.join('') + } +} + +export function generateInputGroup ( root, label = false, hint = false, @@ -62,8 +62,9 @@ module.exports = { } return structure - }, - generateNumberInputGroup: function ( + } + +export function generateNumberInputGroup ( root, incDecBtn = false, label = false, @@ -91,8 +92,9 @@ module.exports = { } return structure - }, - generateLabelGroup: function (root, label = false, hintButton = false, hint = false) { + } + +export function generateLabelGroup (root, label = false, hintButton = false, hint = false) { const structure = { elements: {} } structure.root = root @@ -108,8 +110,9 @@ module.exports = { } return structure - }, - generateDropdownGroup: function ( + } + +export function generateDropdownGroup ( root, open_button = false, options = false, @@ -129,8 +132,9 @@ module.exports = { structure.optionsInRoot = options_in_root return structure - }, - generateCheckboxGroup: function (root, checkbox, name, icon) { + } + +export function generateCheckboxGroup (root, checkbox, name, icon) { const structure = { root, elements: {} } structure.elements.checkbox = checkbox ? 'svg[class]' : '' @@ -140,8 +144,9 @@ module.exports = { structure.elements.icon = icon ? 'svg:not([class])' : '' return structure - }, - generateTextAreaGroup: function (root, counter = '.form-field__counter') { + } + +export function generateTextAreaGroup (root, counter = '.form-field__counter') { return { root, elements: { @@ -152,8 +157,9 @@ module.exports = { counter } } - }, - parseString: function (string) { + } + +export function parseString (string) { const rulesArray = string.split('\n') const lengthRule = getLength(rulesArray) const validCharactersRule = getRule(rulesArray, 'valid characters') @@ -172,8 +178,9 @@ module.exports = { notStartWith, notConsecutiveCharacters ) - }, - clearBackendAfterTest: function (driver, items) { + } + +export function clearBackendAfterTest (driver, items) { items.forEach(item => { switch (item.type) { case 'project': @@ -194,15 +201,15 @@ module.exports = { return null } }) - }, - setRequestsFailureCondition: async shouldFail => { - try { - const response = await axios.post('http://localhost:30000/set-failure-condition', { - shouldFail - }) - console.log(response.data) - } catch (error) { - console.error(`Error setting failure condition: ${error}`) - } + } + +export async function setRequestsFailureCondition(shouldFail) { + try { + const response = await axios.post('http://localhost:30000/set-failure-condition', { + shouldFail + }) + console.log(response.data) + } catch (error) { + console.error(`Error setting failure condition: ${error}`) } } diff --git a/tests/features/common-tools/utils.js b/tests/features/common-tools/utils.js index 8f8dfb88c1..53b3aeeaf4 100644 --- a/tests/features/common-tools/utils.js +++ b/tests/features/common-tools/utils.js @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -const RandExp = require('randexp') +import RandExp from 'randexp' // const rules = `• Valid characters: A-Z, a-z, 0-9, -, _, .\n // • Must begin and end with: A-Z, a-z, 0-9\n diff --git a/tests/features/common/actions/action-menu.action.js b/tests/features/common/actions/action-menu.action.js index 92d5320159..a3356dcb0c 100644 --- a/tests/features/common/actions/action-menu.action.js +++ b/tests/features/common/actions/action-menu.action.js @@ -26,14 +26,14 @@ async function getOptionValues(driver, options) { }) } -const action = { - openActionMenu: async function(driver, actionMenu) { +export const openActionMenu = async (driver, actionMenu) => { const element = await driver.findElement(actionMenu.open_button) if (element) { element.click() } - }, - selectOptionInActionMenu: async function(driver, actionMenu, option) { + } + +export const selectOptionInActionMenu = async (driver, actionMenu, option) => { const elements = await driver.findElements(actionMenu.options) for (const element of elements) { element.getText().then(txt => { @@ -42,8 +42,9 @@ const action = { } }) } - }, - checkActionMenuOptions: async function(driver, actionMenu, values) { + } + +export const checkActionMenuOptions = async (driver, actionMenu, values) => { const options = await getOptionValues(driver, actionMenu.options) if (options.length === values.length){ @@ -54,8 +55,9 @@ const action = { expect(options.length).equal(values.length, `Actual options in action menu [${options}] don't match with expected values [${values}]`) } - }, - verifyOptionInActionMenuEnabled: async function(driver, actionMenu, option){ + } + +export const verifyOptionInActionMenuEnabled = async (driver, actionMenu, option) => { const elements = await driver.findElements(actionMenu.options) for (const element of elements) { const attributes = await element.getAttribute('class') @@ -66,8 +68,9 @@ const action = { expect(flag).to.equal(false) } } - }, - verifyOptionInActionMenuDisabled: async function(driver, actionMenu, option){ + } + +export const verifyOptionInActionMenuDisabled = async (driver, actionMenu, option) => { const elements = await driver.findElements(actionMenu.options) for (const element of elements) { const attributes = await element.getAttribute('class') @@ -79,6 +82,3 @@ const action = { } } } -} - -module.exports = action diff --git a/tests/features/common/actions/api.actions.js b/tests/features/common/actions/api.actions.js index db7914c241..1769c01669 100644 --- a/tests/features/common/actions/api.actions.js +++ b/tests/features/common/actions/api.actions.js @@ -53,13 +53,12 @@ const newJobTemplate = { } } -const action = { - deleteAPIMLProject: async function( +export const deleteAPIMLProject = async ( driver, mlProjectName, expectedStatusCode, deleteNonEmpty = false - ) { + ) => { await driver.sleep(1000) await mainHttpClient .delete( @@ -75,7 +74,7 @@ const action = { }) .catch(error => { if (error.response?.status === 412) { - action.deleteAPIMLProject( + deleteAPIMLProject( driver, mlProjectName, expectedStatusCode, @@ -83,12 +82,13 @@ const action = { ) } }) - }, - deleteAPIFeatureSet: async function( + } + +export const deleteAPIFeatureSet = async ( projectName, featureSetName, expectedStatusCode - ) { + ) => { await mainHttpClient .delete( `${REACT_APP_MLRUN_API_URL}/projects/${projectName}/feature-sets/${featureSetName}` @@ -96,12 +96,13 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - deleteAPIFeatureVector: async function( + } + +export const deleteAPIFeatureVector = async ( projectName, featureVectorName, expectedStatusCode - ) { + ) => { await mainHttpClient .delete( `${REACT_APP_MLRUN_API_URL}/projects/${projectName}/feature-vectors/${featureVectorName}` @@ -109,12 +110,13 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - deleteAPIFunction: async function( + } + +export const deleteAPIFunction = async ( projectName, functionName, expectedStatusCode - ) { + ) => { await mainHttpClient .delete( `${REACT_APP_MLRUN_API_URL_V2}/projects/${projectName}/functions/${functionName}` @@ -122,12 +124,13 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - deleteAPISchedule: async function( + } + +export const deleteAPISchedule = async ( projectName, scheduleName, expectedStatusCode - ) { + ) => { await mainHttpClient .delete( `${REACT_APP_MLRUN_API_URL}/projects/${projectName}/schedules/${scheduleName}` @@ -135,12 +138,13 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - deleteAPIArtifact: async function( + } + +export const deleteAPIArtifact = async ( projectName, artifactName, expectedStatusCode - ) { + ) => { await mainHttpClient .delete( `${REACT_APP_MLRUN_API_URL}/artifacts?project=${projectName}&name=${artifactName}` @@ -148,8 +152,9 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - createAPIMLProject: async function(mlProjectName, expectedStatusCode) { + } + +export const createAPIMLProject = async (mlProjectName, expectedStatusCode) => { const project_data = { metadata: { name: mlProjectName @@ -164,13 +169,13 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, + } - createAPISchedule: async function( +export const createAPISchedule = async ( mlProjectName, mlScheduleName, expectedStatusCode - ) { + ) => { const data = newJobTemplate data.task.metadata.name = mlScheduleName data.task.metadata.project = mlProjectName @@ -180,14 +185,15 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - createAPIFunction: async function( + } + +export const createAPIFunction = async ( mlProjectName, mlFunctionKind, mlFunctionTag, mlFunctionName, expectedStatusCode - ) { + ) => { const data = { kind: mlFunctionKind, metadata: { @@ -216,12 +222,13 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - createAPIFeatureSet: async function( + } + +export const createAPIFeatureSet = async ( mlProjectName, mlFeatureSetName, expectedStatusCode - ) { + ) => { const data = { kind: 'FeatureSet', metadata: { @@ -244,12 +251,13 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - createAPIFeatureVector: async function( + } + +export const createAPIFeatureVector = async ( mlProjectName, mlFeatureVectorName, expectedStatusCode - ) { + ) => { const data = { kind: 'FeatureVector', metadata: { @@ -270,19 +278,16 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - createAPIArtifact: async function( + } + +export const createAPIArtifact = async ( mlProjectName, mlArtifactName, mlArtifactTag, mlArtifactType, expectedStatusCode - ) { + ) => { const uid = uuidv4() - //TODO: description ML-4583 - // const data = { - // description: '', - // } const data = { kind: mlArtifactType === 'file' ? '' : mlArtifactType, @@ -332,14 +337,10 @@ const action = { .then(res => { expect(res.status).equal(expectedStatusCode) }) - }, - getProjects: () => { - return mainHttpClient - .get(`${REACT_APP_MLRUN_API_URL}/projects`) - .then(res => { - return res.data.projects - }) } -} -module.exports = action +export const getProjects = async () => { + const res = await mainHttpClient.get(`${REACT_APP_MLRUN_API_URL}/projects`) + + return res.data.projects + } diff --git a/tests/features/common/actions/checkbox.action.js b/tests/features/common/actions/checkbox.action.js index aceab8a507..35346dfe55 100644 --- a/tests/features/common/actions/checkbox.action.js +++ b/tests/features/common/actions/checkbox.action.js @@ -19,41 +19,42 @@ such restriction. */ import { expect } from 'chai' -const action = { - isCheckboxChecked: async function(driver, checkbox) { +export const isCheckboxChecked = async (driver, checkbox) => { const checkboxElement = await driver.findElement(checkbox['checkbox']) const classes = await checkboxElement.getAttribute('class') expect(classes.includes('unchecked')).equal(false) - }, - isCheckboxUnchecked: async function(driver, checkbox) { + } + +export const isCheckboxUnchecked = async (driver, checkbox) => { const checkboxElement = await driver.findElement(checkbox['checkbox']) const classes = await checkboxElement.getAttribute('class') expect(classes.includes('unchecked')).equal(true) - }, - checkCheckbox: async function(driver, checkbox) { + } + +export const checkCheckbox = async (driver, checkbox) => { const checkboxElement = await driver.findElement(checkbox['checkbox']) const classes = await checkboxElement.getAttribute('class') if (classes.includes('unchecked')) { await checkboxElement.click() } - }, - uncheckCheckbox: async function(driver, checkbox) { + } + +export const uncheckCheckbox = async (driver, checkbox) => { const checkboxElement = await driver.findElement(checkbox['checkbox']) const classes = await checkboxElement.getAttribute('class') if (!classes.includes('unchecked')) { await checkboxElement.click() } - }, - verifyCheckboxEnabled: async function(driver, component) { + } + +export const verifyCheckboxEnabled = async (driver, component) => { const element = await driver.findElement(component) const flag = await element.getAttribute('class') expect(flag).equal('checkbox') - }, - verifyCheckboxDisabled: async function(driver, component) { + } + +export const verifyCheckboxDisabled = async (driver, component) => { const element = await driver.findElement(component) const flag = await element.getAttribute('class') expect(flag).equal('checkbox checkbox_disabled') } -} - -module.exports = action diff --git a/tests/features/common/actions/common.action.js b/tests/features/common/actions/common.action.js index a9b2dd96d8..b076d146f8 100644 --- a/tests/features/common/actions/common.action.js +++ b/tests/features/common/actions/common.action.js @@ -21,16 +21,10 @@ import { timeout } from '../../../config' import { until } from 'selenium-webdriver' import { expect } from 'chai' import { access, constants } from 'fs' -const path = require('path') -const os = require('os') +import path from 'path' +import os from 'os' -async function scrollToWebElement(driver, element) { - await driver.executeScript('arguments[0].scrollIntoView()', element) - await driver.sleep(250) -} - -const action = { - generatePath: async function(file, downloadsFolder){ +export const generatePath = async (file, downloadsFolder) => { const homeDirectory = os.homedir() // Define the path to the Downloads folder @@ -38,41 +32,50 @@ const action = { // Specify the full path to the file return path.join(downloadsFolderPath, file) - }, - determineFileAccess: async function(finalPath, file){ + } + +export const determineFileAccess = async (finalPath, file) => { access(finalPath, constants.F_OK, (err) => { const result = err ? `${file} doesn't exist` : true expect(result).equal(true) }) - }, - navigateToPage: async function(driver, baseURL) { + } + +export const navigateToPage = async (driver, baseURL) => { await driver.get(baseURL) await driver.sleep(1000) - }, - navigateForward: async function(driver) { + } + +export const navigateForward = async (driver) => { await driver.navigate().forward() - }, - navigateBack: async function(driver) { + } + +export const navigateBack = async (driver) => { await driver.navigate().back() - }, - refreshPage: async function(driver) { + } + +export const refreshPage = async (driver) => { await driver.navigate().refresh() - }, - waitPageLoad: async function(driver, loader) { + } + +export const waitPageLoad = async (driver, loader) => { await driver.wait(async function(driver) { const found = await driver.findElements(loader) return found.length === 0 }) - }, - waiteUntilComponent: async function(driver, component) { + } + +export const waiteUntilComponent = async (driver, component) => { await driver.wait(until.elementLocated(component), timeout) - }, - clickOnComponent: async function(driver, component) { + } + +export const clickOnComponent = async (driver, component) => { const element = await driver.findElement(component) await driver.sleep(250) await element.click() - }, - clickNearComponent: async function(driver, component) { + } + +export const clickNearComponent = async (driver, component) => { const element = await driver.findElement(component) const coordinates = await element.getRect() const actions = driver.actions({ async: true }) @@ -80,8 +83,9 @@ const action = { .move({ x: parseInt(coordinates.x) + 1, y: parseInt(coordinates.y) + 1 }) .click() .perform() - }, - hoverComponent: async function(driver, component, scroll = true) { + } + +export const hoverComponent = async (driver, component, scroll = true) => { const baseComponent = component.root ? component.root : component const element = await driver.findElement(baseComponent) if (scroll) { @@ -93,66 +97,78 @@ const action = { .move({ x: parseInt(coordinates.x), y: parseInt(coordinates.y) }) .perform() await driver.sleep(250) - }, - verifyClassDisabled: async function (driver, component) { + } + +export const verifyClassDisabled = async (driver, component) => { const inputField = await driver.findElement(component) const attributes = await inputField.getAttribute('class') const flag = attributes.includes('form-field__wrapper-disabled') expect(flag).equal(true) - }, - verifyElementDisabled: async function(driver, component) { + } + +export const verifyElementDisabled = async (driver, component) => { const element = await driver.findElement(component) const flag = await element.getAttribute('disabled') expect(flag).equal('true') - }, - verifyElementEnabled: async function(driver, component) { + } + +export const verifyElementEnabled = async (driver, component) => { const element = await driver.findElement(component) const flag = await element.getAttribute('disabled') expect(flag).equal(null) - }, - verifyElementActive: async function(driver, component) { + } + +export const verifyElementActive = async (driver, component) => { const element = await driver.findElement(component) const flag = await element.getAttribute('class') expect(flag.includes('active')).equal(true) - }, - verifyElementNotActive: async function(driver, component) { + } + +export const verifyElementNotActive = async (driver, component) => { const element = await driver.findElement(component) const flag = await element.getAttribute('class') expect(flag.includes('false')).equal(true) - }, - componentIsPresent: async function(driver, component) { + } + +export const componentIsPresent = async (driver, component) => { const _component = component.root ?? component const elements = await driver.findElements(_component) expect(elements.length).above(0) - }, - componentIsNotPresent: async function(driver, component) { + } + +export const componentIsNotPresent = async (driver, component) => { const _component = component.root ?? component const elements = await driver.findElements(_component) expect(elements.length).equal(0) - }, - componentIsVisible: async function(driver, component) { + } + +export const componentIsVisible = async (driver, component) => { const _component = component.root ?? component const element = await driver.findElement(_component) const displayed = await element.isDisplayed() expect(displayed).equal(true) - }, - componentIsNotVisible: async function(driver, component) { + } + +export const componentIsNotVisible = async (driver, component) => { const _component = component.root ?? component const element = await driver.findElement(_component) await driver.sleep(250) const displayed = await element.isDisplayed() expect(displayed).equal(false) - }, - typeIntoInputField: async function(driver, component, value) { + } + +export const typeIntoInputField = async (driver, component, value) => { const element = await driver.findElement(component) return element.sendKeys(value) - }, - verifyTypedText: async function(driver, component, value) { + } + +export const verifyTypedText = async (driver, component, value) => { const element = await driver.findElement(component) const txt = await element.getAttribute('value') expect(txt).equal(value) - }, - verifyText: async function(driver, component, value) { + } + +export const verifyText = async (driver, component, value) => { const element = await driver.findElement(component) const txt = await element.getText('value') const arr = txt.split() @@ -168,94 +184,106 @@ const action = { `should be expected "${value}" but actual value "${txt}"` ) } - }, - verifyTextRegExp: async function(driver, component, regexp) { + } + +export const verifyTextRegExp = async (driver, component, regexp) => { const element = await driver.findElement(component) const txt = await element.getText('value') expect(true).equal(regexp.test(txt)) - }, - isComponentContainsAttributeValue: async function( + } + +export const isComponentContainsAttributeValue = async ( driver, component, attribute, value - ) { + ) => { const element = await driver.findElement(component) return (await element.getAttribute(attribute)) === value - }, - isComponentContainsClass: async function( + } + +export const isComponentContainsClass = async ( driver, component, className - ) { + ) => { const element = await driver.findElement(component) const classes = await element.getAttribute('class') expect(classes.includes(className)).equal(true) - }, - verifyComponentContainsAttributeValue: async function( + } + +export const verifyComponentContainsAttributeValue = async ( driver, component, attribute, value - ) { + ) => { const element = await driver.findElement(component) const attributes = await element.getAttribute(attribute) expect(attributes.includes(value)).equal( true, `Attribute "${value}" does not present in "${attribute}" values list "${attributes}"` ) - }, - verifyComponentNotContainsAttributeValue: async function( + } + +export const verifyComponentNotContainsAttributeValue = async ( driver, component, attribute, value - ) { + ) => { const element = await driver.findElement(component) const attributes = await element.getAttribute(attribute) expect(attributes.includes(value)).equal( false, `Attribute "${value}" does present in "${attribute}" values list "${attributes}"` ) - }, - collapseAccordionSection: async function(driver, collapseComponent) { + } + +export const collapseAccordionSection = async (driver, collapseComponent) => { const element = await driver.findElement(collapseComponent) const attributes = await element.getAttribute('class') const flag = attributes.includes('open') if (flag) { await element.click() } - }, - expandAccordionSection: async function(driver, collapseComponent) { + } + +export const expandAccordionSection = async (driver, collapseComponent) => { const element = await driver.findElement(collapseComponent) const attributes = await element.getAttribute('class') const flag = attributes.includes('open') if (!flag) { await element.click() } - }, - isAccordionSectionExpanded: async function(driver, collapseComponent) { + } + +export const isAccordionSectionExpanded = async (driver, collapseComponent) => { const element = await driver.findElement(collapseComponent) const attributes = await element.getAttribute('class') const flag = attributes.includes('open') expect(flag).equal(true) - }, - isAccordionSectionCollapsed: async function(driver, collapseComponent) { + } + +export const isAccordionSectionCollapsed = async (driver, collapseComponent) => { const element = await driver.findElement(collapseComponent) const attributes = await element.getAttribute('class') const flag = attributes.includes('open') expect(flag).equal(false) - }, - getElementText: async function(driver, component) { + } + +export const getElementText = async (driver, component) => { const element = await driver.findElement(component) return await element.getText('value') - }, - scrollToElement: async function(driver, component) { + } + +export const scrollToElement = async (driver, component) => { const element = await driver.findElement(component) await driver.executeScript('arguments[0].scrollIntoView()', element) await driver.sleep(250) - }, - checkComponentHintTextWithHover:async function (driver, component, hintComponent, text) { + } + +export const checkComponentHintTextWithHover = async (driver, component, hintComponent, text) => { const hintButton = await driver.findElement(component) const coordinates = await hintButton.getRect() const actions = driver.actions({ async: true }) @@ -267,13 +295,14 @@ const action = { const hintText = await hint.getText() expect(hintText).equal(text) - }, - putToTestContextElementValue: async function(driver, testContext, element, pageValue) { - const pageElement = await driver.findElement(element) + } +export const putToTestContextElementValue = async (driver, testContext, element, pageValue) => { + const pageElement = await driver.findElement(element) testContext[pageValue] = await pageElement.getText() - }, - scrollToWebElement -} - -module.exports = action + } + +export const scrollToWebElement = async (driver, element) => { + await driver.executeScript('arguments[0].scrollIntoView()', element) + await driver.sleep(250) + } diff --git a/tests/features/common/actions/date-picker.action.js b/tests/features/common/actions/date-picker.action.js index d589cbc741..5b0e75d5ed 100644 --- a/tests/features/common/actions/date-picker.action.js +++ b/tests/features/common/actions/date-picker.action.js @@ -87,8 +87,7 @@ async function setPickerTime(driver, dateTimePicker, datetimePoint) { await timeInput.sendKeys(timeString) } -const action = { - verifyTimeFilterBand: async function(driver, dropdown, diff) { +export const verifyTimeFilterBand = async (driver, dropdown, diff) => { const selectedBand = await driver.findElement(dropdown.open_button) const datetimePointsText = await selectedBand.getAttribute('value') const datetimePoints = datetimePointsText.split('-') @@ -102,13 +101,14 @@ const action = { result = datetimeDiff - diff === 0 } expect(result).to.equal(true) - }, - pickUpCustomDatetimeRange: async function( + } + +export const pickUpCustomDatetimeRange = async ( driver, datetimePicker, fromDatetime, toDatetime - ) { + ) => { await selectMonthYear(driver, datetimePicker.fromDatePicker, fromDatetime) await selectCalendarDay(driver, datetimePicker.fromDatePicker, fromDatetime) await setPickerTime(driver, datetimePicker.fromDatePicker, fromDatetime) @@ -116,11 +116,10 @@ const action = { await selectMonthYear(driver, datetimePicker.toDatePicker, toDatetime) await selectCalendarDay(driver, datetimePicker.toDatePicker, toDatetime) await setPickerTime(driver, datetimePicker.toDatePicker, toDatetime) - }, - applyDatetimePickerRange: async function(driver, datetimePicker) { + } + +export const applyDatetimePickerRange = async (driver, datetimePicker) => { const applyButton = await driver.findElement(datetimePicker.applyButton) await applyButton.click() } -} - -module.exports = action + \ No newline at end of file diff --git a/tests/features/common/actions/dropdown.action.js b/tests/features/common/actions/dropdown.action.js index 3b3c36a2ee..5fadbb95a8 100644 --- a/tests/features/common/actions/dropdown.action.js +++ b/tests/features/common/actions/dropdown.action.js @@ -21,15 +21,13 @@ import { expect } from 'chai' import { differenceWith, isEqual } from 'lodash' import { clickNearComponent, scrollToWebElement } from './common.action' -async function getOptionValues(driver, options) { - return await driver.findElements(options).then(function(elements) { +export const getOptionValues = async (driver, options) => { + return await driver.findElements(options).then(function(elements) { return Promise.all(elements.map(element => element.getText())) - }) -} + }) + } -const action = { - getOptionValues: getOptionValues, - openDropdown: async function(driver, dropdown, scroll = true) { +export const openDropdown = async (driver, dropdown, scroll = true) => { const element = await driver.findElement(dropdown.open_button) if (scroll) { await scrollToWebElement(driver, element) @@ -38,13 +36,15 @@ const action = { await element.click() } await driver.sleep(1500) - }, - collapseDropdown: async function(driver, dropdown) { + } + +export const collapseDropdown = async (driver, dropdown) => { // const element = await driver.findElement(dropdown.root) await clickNearComponent(dropdown.root) await driver.sleep(100) - }, - selectOptionInDropdown: async function(driver, dropdown, option) { + } + +export const selectOptionInDropdown = async (driver, dropdown, option) => { const selectedElement = await driver.findElement(dropdown.open_button) const selectedText = await selectedElement.getText() if (selectedText !== option) { @@ -62,8 +62,9 @@ const action = { selectedElement.click() await driver.sleep(500) } - }, - selectOptionInDropdownWithoutCheck: async function(driver, dropdown, option) { + } + +export const selectOptionInDropdownWithoutCheck = async (driver, dropdown, option) => { const elements = await driver.findElements(dropdown.options) for (const element of elements) { const txt = await element.getText() @@ -73,23 +74,27 @@ const action = { break } } - }, - checkDropdownSelectedOption: async function(driver, dropdown, option) { + } + +export const checkDropdownSelectedOption = async (driver, dropdown, option) => { const element = await driver.findElement(dropdown.open_button) const txt = await element.getText() expect(txt).equal(option) - }, - checkDropdownSelectedOptionWithAttribute: async function(driver, dropdown, option) { + } + +export const checkDropdownSelectedOptionWithAttribute = async (driver, dropdown, option) => { const element = await driver.findElement(dropdown.open_button) const attributeTxt = await element.getAttribute('value') expect(attributeTxt).equal(option) - }, - checkDropdownOptions: async function(driver, dropdown, values) { + } + +export const checkDropdownOptions = async (driver, dropdown, values) => { const options = await getOptionValues(driver, dropdown.options) const diff = differenceWith(options, values, isEqual) expect(diff.length).equal(0, `Options difference: "${diff}"`) - }, - checkDropdownContainsOptions: async function(driver, dropdown, values) { + } + +export const checkDropdownContainsOptions = async (driver, dropdown, values) => { const options = await getOptionValues(driver, dropdown.options) let notPresent = [] for (let option of values) { @@ -108,6 +113,3 @@ const action = { '\n' ) } -} - -module.exports = action diff --git a/tests/features/common/actions/graph.action.js b/tests/features/common/actions/graph.action.js index 9312e01b7f..f544320c4f 100644 --- a/tests/features/common/actions/graph.action.js +++ b/tests/features/common/actions/graph.action.js @@ -39,8 +39,7 @@ function diffMapper(array0, array1, deviation) { return tmpDiff } -const action = { - checkNodesConnectionsNPandas: async function(driver, graphComponent) { +export const checkNodesConnectionsNPandas = async (driver, graphComponent) => { const nodesGeometry = await getNamedRowsGeometry( driver, graphComponent.nodesTable @@ -133,6 +132,3 @@ const action = { expect(numjs.sum(endMarks.slice([i]))).equal(true, 'Arrow not ended') } } -} - -module.exports = action diff --git a/tests/features/common/actions/input-group.action.js b/tests/features/common/actions/input-group.action.js index 6ac71c701b..47d6266b30 100644 --- a/tests/features/common/actions/input-group.action.js +++ b/tests/features/common/actions/input-group.action.js @@ -21,37 +21,44 @@ import { expect } from 'chai' import { Key } from 'selenium-webdriver' import { parseString } from '../../common-tools/common-tools' -async function verifyInputInvalid(driver, inputGroup) { - const inputField = await driver.findElement(inputGroup.inputField) +async function verifyFormInputInvalid(driver, inputGroup) { + const inputField = await driver.findElement(inputGroup.root) + await driver.sleep(500) const flag = await inputField.getAttribute('class') - await driver.sleep(500) - expect(flag.includes('invalid')).equal(true) + expect(flag.includes('form-field__wrapper-invalid')).equal(true) } -async function verifyFormInputInvalid(driver, inputGroup) { +async function verifyFormInputValid(driver, inputGroup) { const inputField = await driver.findElement(inputGroup.root) - await driver.sleep(500) const flag = await inputField.getAttribute('class') - expect(flag.includes('form-field__wrapper-invalid')).equal(true) + expect(flag.includes('form-field__wrapper-invalid')).equal(false) } -async function verifyInputValid(driver, inputGroup) { +async function getInputPlaceholder(driver, inputGroup) { + const inputField = await driver.findElement(inputGroup.inputField) + + return inputField.getAttribute('placeholder') +} + + +export const verifyInputInvalid = async (driver, inputGroup) => { const inputField = await driver.findElement(inputGroup.inputField) const flag = await inputField.getAttribute('class') - expect(flag.includes('invalid')).equal(false) + await driver.sleep(500) + expect(flag.includes('invalid')).equal(true) } -async function verifyFormInputValid(driver, inputGroup) { - const inputField = await driver.findElement(inputGroup.root) +export const verifyInputValid = async (driver, inputGroup) => { + const inputField = await driver.findElement(inputGroup.inputField) const flag = await inputField.getAttribute('class') - expect(flag.includes('form-field__wrapper-invalid')).equal(false) + expect(flag.includes('invalid')).equal(false) } -async function clearManually(inputField) { +export const clearManually = async (inputField) => { const existValue = await inputField.getAttribute('value') for (let i = 0; i <= existValue.length; i++) { @@ -59,47 +66,33 @@ async function clearManually(inputField) { } } -async function getInputValue(driver, inputGroup) { +export const getInputValue = async (driver, inputGroup) => { const inputField = await driver.findElement(inputGroup.inputField) return inputField.getAttribute('value') } -async function getInputPlaceholder(driver, inputGroup) { - const inputField = await driver.findElement(inputGroup.inputField) - - return inputField.getAttribute('placeholder') -} - -async function getInputValueWithoutInputgroup(driver, input) { +export const getInputValueWithoutInputgroup = async (driver, input) => { const inputField = await driver.findElement(input) return inputField.getAttribute('value') } -async function typeValue(driver, inputGroup, value) { +export const typeValue = async (driver, inputGroup, value) => { const inputField = await driver.findElement(inputGroup.inputField) await clearManually(inputField) return inputField.sendKeys(value) } -async function typeValueWithoutInputgroup(driver, input, value) { +export const typeValueWithoutInputgroup = async (driver, input, value) => { const inputField = await driver.findElement(input) await clearManually(inputField) return inputField.sendKeys(value) } -const action = { - clearManually, - getInputValue, - getInputValueWithoutInputgroup, - typeValue, - typeValueWithoutInputgroup, - verifyInputValid, - verifyInputInvalid, - checkHintText: async function (driver, inputGroup, hintComponent, text) { +export const checkHintText = async (driver, inputGroup, hintComponent, text) => { const hintButton = await driver.findElement(inputGroup.hintButton) await hintButton.click() await driver.sleep(250) @@ -107,8 +100,9 @@ const action = { const hintText = await hint.getText() expect(hintText).equal(text) - }, - checkHintTextWithHover:async function (driver, inputGroup, hintComponent, text) { + } + +export const checkHintTextWithHover = async (driver, inputGroup, hintComponent, text) => { const hintButton = await driver.findElement(inputGroup.hintButton) const coordinates = await hintButton.getRect() const actions = driver.actions({ async: true }) @@ -120,15 +114,16 @@ const action = { const hintText = await hint.getText() expect(hintText).equal(text) - }, - checkInputAccordingHintText: async function ( + } + +export const checkInputAccordingHintText = async ( driver, attach, inputGroup, hintComponent, isForm = false, isLabel = false - ) { + ) => { if (!isLabel){ const hintButton = await driver.findElement(inputGroup.hintButton) @@ -168,8 +163,9 @@ const action = { await clearManually(input) } - }, - checkWarningHintText: async function (driver, inputGroup, hintComponent, text) { + } + +export const checkWarningHintText = async (driver, inputGroup, hintComponent, text) => { const hintButton = await driver.findElement(inputGroup.warningHint) await driver.sleep(250) await hintButton.click() @@ -179,8 +175,9 @@ const action = { const hintText = await hint.getText() expect(hintText).equal(text) - }, - checkWarningHintTextWithHover: async function (driver, inputGroup, hintComponent, text) { + } + +export const checkWarningHintTextWithHover = async (driver, inputGroup, hintComponent, text) => { const hintButton = await driver.findElement(inputGroup.warningHint) await driver.sleep(250) const coordinates = await hintButton.getRect() @@ -194,56 +191,65 @@ const action = { const hintText = await hint.getText() expect(hintText).equal(text) - }, - checkWarningText: async function (driver, hintComponent, text) { + } + +export const checkWarningText = async (driver, hintComponent, text) => { const hint = await driver.findElement(hintComponent) await driver.sleep(250) const hintText = await hint.getText() expect(hintText).equal(text) - }, - verifyTypedValue: async function (driver, inputGroup, value) { + } + +export const verifyTypedValue = async (driver, inputGroup, value) => { const txt = await getInputValue(driver, inputGroup) expect(txt).equal(value) - }, - verifyPlaceholder: async function (driver, inputGroup, value) { + } + +export const verifyPlaceholder = async (driver, inputGroup, value) => { const txt = await getInputPlaceholder(driver, inputGroup) expect(txt).equal(value) - }, - verifyTypedValueWithoutInputgroup: async function (driver, input, value) { + } + +export const verifyTypedValueWithoutInputgroup = async (driver, input, value) => { const txt = await getInputValueWithoutInputgroup(driver, input) expect(txt).equal(value) - }, - verifyInputDisabled: async function (driver, inputGroup) { + } + +export const verifyInputDisabled = async (driver, inputGroup) => { const inputField = await driver.findElement(inputGroup.inputField) const flag = await inputField.getAttribute('disabled') expect(flag).equal('true') - }, - verifyInputClassDisabled: async function (driver, inputGroup) { + } + +export const verifyInputClassDisabled = async (driver, inputGroup) => { const inputField = await driver.findElement(inputGroup.root) const attributes = await inputField.getAttribute('class') const flag = attributes.includes('form-field__wrapper-disabled') expect(flag).equal(true) - }, - verifyInputClassEnabled: async function (driver, inputGroup) { + } + +export const verifyInputClassEnabled = async (driver, inputGroup) => { const inputField = await driver.findElement(inputGroup.inputField) const attributes = await inputField.getAttribute('class') const flag = attributes.includes('form-field__wrapper-disabled') expect(flag).equal(false) - }, - verifyInputEnabled: async function (driver, inputGroup) { + } + +export const verifyInputEnabled = async (driver, inputGroup) => { const inputField = await driver.findElement(inputGroup.inputField) const flag = await inputField.getAttribute('disabled') expect(flag).equal(null) - }, - verifyTextAreaCounter: async function (driver, textAreaGroup) { + } + +export const verifyTextAreaCounter = async (driver, textAreaGroup) => { const textAreaField = await driver.findElement(textAreaGroup.inputField) const textAreaText = await textAreaField.getText() const textAreaCounter = await driver.findElement(textAreaGroup.counter) @@ -252,6 +258,3 @@ const action = { expect(+counterValue.split(' ')[0]).equal(maxLength - textAreaText.length) } -} - -module.exports = action diff --git a/tests/features/common/actions/input-with-autocomplete.action.js b/tests/features/common/actions/input-with-autocomplete.action.js index c3be98a834..5a20fe1318 100644 --- a/tests/features/common/actions/input-with-autocomplete.action.js +++ b/tests/features/common/actions/input-with-autocomplete.action.js @@ -20,38 +20,37 @@ such restriction. import { expect } from 'chai' import { Key } from 'selenium-webdriver' -async function clearManually(inputField) { +export const clearManually = async (inputField) => { const existValue = await inputField.getAttribute('value') for (let i = 0; i <= existValue.length; i++) { await inputField.sendKeys(Key.BACK_SPACE, Key.DELETE) } } -async function getOptionValues(driver, options) { +export const getOptionValues = async (driver, options) => { return await driver.findElements(options).then(function(elements) { return Promise.all(elements.map(element => element.getText())) }) } -const action = { - clearManually, - getOptionValues: getOptionValues, - typeSearchableValue: async function(driver, inputGroup, value) { +export const typeSearchableValue = async (driver, inputGroup, value) => { const inputField = await driver.findElement(inputGroup.inputField) await clearManually(inputField) return await inputField.sendKeys(value) - }, - verifyTypedValue: async function(driver, inputGroup, value) { + } + +export const verifyTypedValue = async (driver, inputGroup, value) => { const inputField = await driver.findElement(inputGroup.inputField) const txt = await inputField.getAttribute('value') expect(txt).equal(value) - }, - isContainsSubstringInSuggestedOptions: async function( + } + +export const isContainsSubstringInSuggestedOptions = async ( driver, inputGroup, value, caseSensitive = false - ) { + ) => { let arr = await getOptionValues(driver, inputGroup.options) let tmpValue = value @@ -66,6 +65,3 @@ const action = { `Searcheble string "${tmpValue}" do not find in all values of: [${arr}]` ) } -} - -module.exports = action diff --git a/tests/features/common/actions/number-input-group.action.js b/tests/features/common/actions/number-input-group.action.js index 507ea3fa13..dbd61be189 100644 --- a/tests/features/common/actions/number-input-group.action.js +++ b/tests/features/common/actions/number-input-group.action.js @@ -17,21 +17,18 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -const action = { - incrementValue: async function(driver, inputGroup, value) { +export const incrementValue = async (driver, inputGroup, value) => { const inc_btn = await driver.findElement(inputGroup.inc_btn) for (let i = 0; i < value; i++) { await inc_btn.click() await driver.sleep(100) } - }, - decrementValue: async function(driver, inputGroup, value) { + } + +export const decrementValue = async (driver, inputGroup, value) => { const dec_btn = await driver.findElement(inputGroup.dec_btn) for (let i = 0; i < value; i++) { await dec_btn.click() await driver.sleep(100) } } -} - -module.exports = action diff --git a/tests/features/common/actions/radio-button.action.js b/tests/features/common/actions/radio-button.action.js index c7e7a67db1..fd78b55738 100644 --- a/tests/features/common/actions/radio-button.action.js +++ b/tests/features/common/actions/radio-button.action.js @@ -19,18 +19,19 @@ such restriction. */ import { expect } from 'chai' -const action = { - isRadioButtonSelected: async function(driver, radiobutton) { +export const isRadioButtonSelected = async (driver, radiobutton) => { const element = await driver.findElement(radiobutton['radiobutton']) const selected = await element.isSelected() expect(selected).equal(true) - }, - isRadioButtonUnselected: async function(driver, radiobutton) { + } + +export const isRadioButtonUnselected = async (driver, radiobutton) => { const element = await driver.findElement(radiobutton['radiobutton']) const selected = await element.isSelected() expect(selected).equal(false) - }, - selectRadiobutton: async function(driver, radiobutton) { + } + +export const selectRadiobutton = async (driver, radiobutton) => { const element = await driver.findElement(radiobutton['radiobutton']) const elementName = await driver.findElement(radiobutton['name']) const selected = await element.isSelected() @@ -38,6 +39,3 @@ const action = { await elementName.click() } } -} - -module.exports = action diff --git a/tests/features/common/actions/tab-selector.action.js b/tests/features/common/actions/tab-selector.action.js index fbeeaad2b1..01b55dda85 100644 --- a/tests/features/common/actions/tab-selector.action.js +++ b/tests/features/common/actions/tab-selector.action.js @@ -19,8 +19,7 @@ such restriction. */ import { expect } from 'chai' -const action = { - isTabActive: async function(driver, component, indx) { +export const isTabActive = async (driver, component, indx) => { const element1 = await driver.findElement(component.rowRoot(indx)) const element2 = await driver.findElement( component.tableFields['key'](indx) @@ -34,8 +33,9 @@ const action = { attributes2.includes('tabs-slider__tab_active')|| attributes2.includes('content-menu__tab_active') expect(flag).equal(true) - }, - isRowActive: async function(driver, component, indx) { + } + +export const isRowActive = async (driver, component, indx) => { const element = await driver.findElement(component.rowRoot(indx)) const attributes = await element.getAttribute('class') const flag = attributes.includes('row_active') @@ -46,6 +46,3 @@ const action = { expect(flag).equal(false) } } -} - -module.exports = action diff --git a/tests/features/common/actions/table.action.js b/tests/features/common/actions/table.action.js index 508ddb11cd..05d0003159 100644 --- a/tests/features/common/actions/table.action.js +++ b/tests/features/common/actions/table.action.js @@ -25,28 +25,27 @@ import { selectOptionInDropdownWithoutCheck } from './dropdown.action' import { getElementText, hoverComponent } from './common.action' - import { DataFrame } from 'pandas-js' -async function getColumnValues(driver, table, columnName) { +async function getColumnValuesAttribute(driver, table, columnName) { return await driver .findElements(table.tableColumns[columnName]) .then(function(elements) { - return Promise.all(elements.map(element => element.getText())) + return Promise.all(elements.map(element => element.getAttribute('value'))) }) } -async function getColumnValuesAttribute(driver, table, columnName) { +export const getColumnValues = async (driver, table, columnName) => { return await driver .findElements(table.tableColumns[columnName]) .then(function(elements) { - return Promise.all(elements.map(element => element.getAttribute('value'))) + return Promise.all(elements.map(element => element.getText())) }) } -async function getTableRows(driver, table) { +export const getTableRows = async (driver, table) => { const arr = await driver .findElements(table.tableColumns[table.tableCulumnNames[0]]) .then(function(elements) { @@ -56,23 +55,22 @@ async function getTableRows(driver, table) { return await arr.length } -const action = { - getColumnValues: getColumnValues, - getTableRows: getTableRows, - isContainsValueInColumn: async function(driver, table, columnName, value) { +export const isContainsValueInColumn = async (driver, table, columnName, value) => { const arr = await getColumnValues(driver, table, columnName) expect(arr.includes(value)).equal(true, `Column values [${arr}] is not equal with "${value}" `) - }, - isNotContainsValueInColumn: async function(driver, table, columnName, value) { + } + +export const isNotContainsValueInColumn = async (driver, table, columnName, value) => { const arr = await getColumnValues(driver, table, columnName) expect(arr.includes(value)).equal(false) - }, - isContainsSubstringInColumnCells: async function( + } + +export const isContainsSubstringInColumnCells = async ( driver, table, columnName, value - ) { + ) => { const arr = await getColumnValues(driver, table, columnName) const subString = value.replace('=', '\n:\n') expect(arr.length > 0).equal(true) @@ -80,39 +78,42 @@ const action = { true, `Value "${subString}" does not includes in all values: [${arr}]` ) - }, - isContainsSubstringInColumnAttributeCells: async function( + } + +export const isContainsSubstringInColumnAttributeCells = async ( driver, table, columnName, value - ) { + ) => { const arr = await getColumnValuesAttribute(driver, table, columnName) expect(arr.length > 0).equal(true) expect(arr.every(item => item.includes(value))).equal( true, `Value "${value}" does not includes in all values: [${arr}]` ) - }, - isContainsSubstringInColumnAttributeListCells: async function( + } + +export const isContainsSubstringInColumnAttributeListCells = async ( driver, table, columnName, value - ) { + ) => { const arr = await getColumnValuesAttribute(driver, table, columnName) expect(arr.length > 0).to.equal(true) expect(arr.every(item => value.includes(item))).to.equal( true, `Value "${value}" does not includes in all values: [${arr}]` ) - }, - isContainsSubstringInColumnDropdownCells: async function( + } + +export const isContainsSubstringInColumnDropdownCells = async ( driver, table, column, value - ) { + ) => { const subString = value.replace('=', '\n:\n') const rows = await getTableRows(driver, table) let flag = true @@ -135,14 +136,15 @@ const action = { } expect(flag).equal(true) - }, - isContainsSubstringInColumnDropdownCellsOverlay: async function( + } + +export const isContainsSubstringInColumnDropdownCellsOverlay = async ( driver, table, overlay, column, value - ) { + ) => { const subString = value.replace('=', '\n:\n') const rows = await getTableRows(driver, table) let flag = true @@ -165,13 +167,14 @@ const action = { } expect(flag).equal(true) - }, - isContainsSubstringInColumnTooltipCells: async function( + } + +export const isContainsSubstringInColumnTooltipCells = async ( driver, table, column, value - ) { + ) => { const rows = await getTableRows(driver, table) expect(rows).not.equal(0) @@ -189,14 +192,15 @@ const action = { } expect(arr.some(item => item.includes(value))).equal(true) - }, - isDatetimeCelsValueInRange: async function( + } + +export const isDatetimeCelsValueInRange = async ( driver, table, columnName, fromDateTime, toDateTime - ) { + ) => { const arr = await getColumnValues(driver, table, columnName) const minDate = new Date(fromDateTime) @@ -216,13 +220,14 @@ const action = { true, `values "${arr}" is not in range: (${fromDateTime}..${toDateTime})` ) - }, - findRowIndexesByColumnValue: async function( + } + +export const findRowIndexesByColumnValue = async ( driver, table, columnName, value - ) { + ) => { const arr = await getColumnValues(driver, table, columnName) const indexes = [] @@ -232,13 +237,14 @@ const action = { } } return indexes - }, - findRowIndexesByColumnValueExpand: async function( + } + +export const findRowIndexesByColumnValueExpand = async ( driver, table, columnName, value - ) { + ) => { const columnValues = await getColumnValues(driver, table, columnName) return columnValues.reduce((acc, currentValue, index) => { @@ -248,13 +254,14 @@ const action = { return acc }, []) - }, - findRowIndexesByColumnValueAttribute: async function( + } + +export const findRowIndexesByColumnValueAttribute = async ( driver, table, columnName, value - ) { + ) => { const arr = await getColumnValuesAttribute(driver, table, columnName) const indexes = [] @@ -264,13 +271,14 @@ const action = { } } return indexes - }, - findRowIndexesByColumnTooltipsValue: async function( + } + +export const findRowIndexesByColumnTooltipsValue = async ( driver, table, columnName, value - ) { + ) => { const indexes = [] const rowsNumber = await getTableRows(driver, table) for (let row = rowsNumber; row >= 1; row--) { @@ -298,8 +306,9 @@ const action = { } return indexes.reverse() - }, - openActionMenuByIndex: async function(driver, table, index) { + } + +export const openActionMenuByIndex = async (driver, table, index) => { const elements = await driver.findElements( table.tableFields['action_menu'](index) ) @@ -314,16 +323,18 @@ const action = { return table.tableFields['action_menu'](index) } } - }, - getCellByIndexColumn: async function(driver, table, index, column) { + } + +export const getCellByIndexColumn = async (driver, table, index, column) => { return await table.tableFields[column](index) - }, - isTableColumnSorted: async function( + } + +export const isTableColumnSorted = async ( driver, table, columnName, order = 'asc' - ) { + ) => { const columnArray = await getColumnValues(driver, table, columnName) let sortedArr = [] if (order === 'asc') { @@ -334,8 +345,9 @@ const action = { } expect(sortedArr).equal(columnArray) - }, - checkTableColumnValues: async function(driver, table, columnName, values) { + } + +export const checkTableColumnValues = async (driver, table, columnName, values) => { const arr = await getColumnValues(driver, table, columnName) if (arr.length === 0) { throw new Error('Array is empty, nothing to compare') @@ -352,8 +364,9 @@ const action = { } return true - }, - getAllCellsWithAttribute: async function(driver, table, attribute) { + } + +export const getAllCellsWithAttribute = async (driver, table, attribute) => { const result = [] for (const column of table.tableCulumnNames) { @@ -376,8 +389,9 @@ const action = { } return result - }, - getRowsGeometry: async function(driver, table) { + } + +export const getRowsGeometry = async (driver, table) => { const rowsNumber = await getTableRows(driver, table) const result = [] @@ -389,8 +403,9 @@ const action = { } return result - }, - getFieldsGeometry: async function(driver, table, column, attribute) { + } + +export const getFieldsGeometry = async (driver, table, column, attribute) => { const rowsNumber = await getTableRows(driver, table) const result = [] @@ -401,8 +416,9 @@ const action = { } return result - }, - getNamedRowsGeometry: async function(driver, table, name = 'name') { + } + +export const getNamedRowsGeometry = async (driver, table, name = 'name') => { const rowsNumber = await getTableRows(driver, table) const result = [] @@ -418,8 +434,9 @@ const action = { } return new DataFrame(result) - }, - getNamedFieldsGeometry: async function(driver, table, column) { + } + +export const getNamedFieldsGeometry = async (driver, table, column) => { const rowsNumber = await getTableRows(driver, table) const result = [] @@ -430,15 +447,16 @@ const action = { } return new DataFrame(result) - }, - putToTestContextCellParameters: async function( + } + +export const putToTestContextCellParameters = async ( driver, testContext, table, index, column, attribute - ) { + ) => { const cellElement = await driver.findElement( table.tableFields[column](index) ) @@ -447,8 +465,9 @@ const action = { if (attribute) { testContext[attribute] = await cellElement.getAttribute(attribute) } - }, - checkCellHintText: async function (driver, table, hintComponent, hintValue, index) { + } + +export const checkCellHintText = async (driver, table, hintComponent, hintValue, index) => { await hoverComponent(driver, table.tableFields['hintButton'](index)) await driver.sleep(250) const hint = await driver.findElement(hintComponent) @@ -456,6 +475,3 @@ const action = { expect(text).equal(hintValue) } -} - -module.exports = action diff --git a/tests/features/common/components/action-menu.component.js b/tests/features/common/components/action-menu.component.js index 216c03f3e2..5ee76e95f5 100644 --- a/tests/features/common/components/action-menu.component.js +++ b/tests/features/common/components/action-menu.component.js @@ -19,7 +19,7 @@ such restriction. */ import { By } from 'selenium-webdriver' -module.exports = function(menuStructure) { +export default function(menuStructure) { return { root: By.css(menuStructure.root), open_button: By.css( diff --git a/tests/features/common/components/breadcrumbs.component.js b/tests/features/common/components/breadcrumbs.component.js index 744c5354f0..7eb022d2a2 100644 --- a/tests/features/common/components/breadcrumbs.component.js +++ b/tests/features/common/components/breadcrumbs.component.js @@ -17,10 +17,10 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -const { By } = require('selenium-webdriver') -const inputWithAutocomplete = require('./input-with-autocomplete.component') +import { By } from 'selenium-webdriver' +import inputWithAutocomplete from './input-with-autocomplete.component' -module.exports = { +export default { root: By.css('nav.breadcrumbs'), projectsPageLabel: By.css('.breadcrumbs__item:nth-of-type(1)'), projectLabel: By.css('.breadcrumbs__item:nth-of-type(3)'), diff --git a/tests/features/common/components/checkbox.component.js b/tests/features/common/components/checkbox.component.js index 1bea023501..f0b45fa00f 100644 --- a/tests/features/common/components/checkbox.component.js +++ b/tests/features/common/components/checkbox.component.js @@ -19,7 +19,7 @@ such restriction. */ import { By } from 'selenium-webdriver' -module.exports = function(checkboxStructure) { +export default function(checkboxStructure) { const element = {} element.root = By.css(checkboxStructure.root) element.checkbox = By.css( diff --git a/tests/features/common/components/combo-box.component.js b/tests/features/common/components/combo-box.component.js index 746398fc69..b05f7e2df7 100644 --- a/tests/features/common/components/combo-box.component.js +++ b/tests/features/common/components/combo-box.component.js @@ -21,7 +21,7 @@ import { By } from 'selenium-webdriver' import dropdownComponent from './dropdown.component' import { generateDropdownGroup } from '../../common-tools/common-tools' -module.exports = function(comboBoxRoot, newClassLocator = false) { +export default function(comboBoxRoot, newClassLocator = false) { const element = {} element.root = By.css(comboBoxRoot) diff --git a/tests/features/common/components/date-picker.component.js b/tests/features/common/components/date-picker.component.js index 90ca9a3cb0..cda827ef7c 100644 --- a/tests/features/common/components/date-picker.component.js +++ b/tests/features/common/components/date-picker.component.js @@ -22,7 +22,7 @@ import { locatorBuilder } from '../../common-tools/common-tools' import { cloneDeep } from 'lodash' -module.exports = function(datepickerStructure) { +export default function(datepickerStructure) { const datepickerRoot = locatorBuilder`${0} ${1}` const options = locatorBuilder`${0} ${1}` diff --git a/tests/features/common/components/dropdown.component.js b/tests/features/common/components/dropdown.component.js index 1864a47adb..a74a1741b8 100644 --- a/tests/features/common/components/dropdown.component.js +++ b/tests/features/common/components/dropdown.component.js @@ -20,7 +20,7 @@ such restriction. import { By } from 'selenium-webdriver' import { locatorBuilder } from '../../common-tools/common-tools' -module.exports = function(dropdownStructure) { +export default function(dropdownStructure) { const root = dropdownStructure.optionsInRoot ? dropdownStructure.root : '#overlay_container' diff --git a/tests/features/common/components/graph.component.js b/tests/features/common/components/graph.component.js index 1feff94192..909961591f 100644 --- a/tests/features/common/components/graph.component.js +++ b/tests/features/common/components/graph.component.js @@ -20,7 +20,7 @@ such restriction. import { By } from 'selenium-webdriver' import { locatorBuilder } from '../../common-tools/common-tools' -module.exports = function(graphStructure) { +export default function(graphStructure) { const options = locatorBuilder`${0} ${1}` const nodesTable = { ...graphStructure.elements.workflowGraphNodesTable.structure diff --git a/tests/features/common/components/input-group.component.js b/tests/features/common/components/input-group.component.js index c724f16a16..9b80bf555e 100644 --- a/tests/features/common/components/input-group.component.js +++ b/tests/features/common/components/input-group.component.js @@ -19,7 +19,7 @@ such restriction. */ import { By } from 'selenium-webdriver' -module.exports = function(inputStructure) { +export default function(inputStructure) { const element = {} element.root = By.css(inputStructure.root) element.inputField = By.css( diff --git a/tests/features/common/components/input-with-autocomplete.component.js b/tests/features/common/components/input-with-autocomplete.component.js index 776c6e7700..ec9493438a 100644 --- a/tests/features/common/components/input-with-autocomplete.component.js +++ b/tests/features/common/components/input-with-autocomplete.component.js @@ -20,7 +20,7 @@ such restriction. import { By } from 'selenium-webdriver' import { locatorBuilder } from '../../common-tools/common-tools' -module.exports = function(inputStructure) { +export default function(inputStructure) { const options = locatorBuilder`${0} ${1} ${2}` const option = locatorBuilder`${0} ${1}:nth-of-type(${2}) ${3}` diff --git a/tests/features/common/components/label.component.js b/tests/features/common/components/label.component.js index 69073805a7..816900ab25 100644 --- a/tests/features/common/components/label.component.js +++ b/tests/features/common/components/label.component.js @@ -19,7 +19,7 @@ such restriction. */ import { By } from 'selenium-webdriver' -module.exports = function(labelStructure) { +export default function(labelStructure) { const element = {} element.root = By.css(labelStructure.root) element.label = By.css( diff --git a/tests/features/common/components/number-input-group.component.js b/tests/features/common/components/number-input-group.component.js index 7a5b4d311d..87323aabc0 100644 --- a/tests/features/common/components/number-input-group.component.js +++ b/tests/features/common/components/number-input-group.component.js @@ -19,7 +19,7 @@ such restriction. */ import { By } from 'selenium-webdriver' -module.exports = function(inputStructure) { +export default function(inputStructure) { const element = {} element.root = By.css(inputStructure.root) element.inputField = By.css( diff --git a/tests/features/common/components/radio-button.component.js b/tests/features/common/components/radio-button.component.js index a3c41a3e3f..235c02bd50 100644 --- a/tests/features/common/components/radio-button.component.js +++ b/tests/features/common/components/radio-button.component.js @@ -19,7 +19,7 @@ such restriction. */ import { By } from 'selenium-webdriver' -module.exports = function(radiobuttonStructure) { +export default function(radiobuttonStructure) { const element = {} element.root = By.css(radiobuttonStructure.root) element.radiobutton = By.css( diff --git a/tests/features/common/components/single-date-picker.component.js b/tests/features/common/components/single-date-picker.component.js index 3174abab4e..4571711dba 100644 --- a/tests/features/common/components/single-date-picker.component.js +++ b/tests/features/common/components/single-date-picker.component.js @@ -22,7 +22,7 @@ import { locatorBuilder } from '../../common-tools/common-tools' import { cloneDeep } from 'lodash' -module.exports = function(datepickerStructure) { +export default function(datepickerStructure) { const datepickerRoot = locatorBuilder`${0} ${1}` const options = locatorBuilder`${0} ${1}` diff --git a/tests/features/common/components/table.component.js b/tests/features/common/components/table.component.js index 50f99e85be..ec99f2905a 100644 --- a/tests/features/common/components/table.component.js +++ b/tests/features/common/components/table.component.js @@ -51,7 +51,7 @@ import { locatorBuilder } from '../../common-tools/common-tools' * } * @returns - js object which allow access to table describle page components */ -module.exports = function(tableStructure) { +export default function(tableStructure) { const table = tableStructure const sortersBuilder = locatorBuilder`${0} ${1} ${2}` const columnBuilder = locatorBuilder`${0} ${1} ${2} ${3}` diff --git a/tests/features/common/components/text-area.component.js b/tests/features/common/components/text-area.component.js index 297e604589..c3f78737ec 100644 --- a/tests/features/common/components/text-area.component.js +++ b/tests/features/common/components/text-area.component.js @@ -19,7 +19,7 @@ such restriction. */ import { By } from 'selenium-webdriver' -module.exports = function (textAreaStructure) { +export default (textAreaStructure) => { const element = {} element.root = By.css(textAreaStructure.root) element.inputField = By.css(`${textAreaStructure.root} ${textAreaStructure.elements.input}`) diff --git a/tests/features/common/page-objects.js b/tests/features/common/page-objects.js index 2692cc7549..110e36557c 100644 --- a/tests/features/common/page-objects.js +++ b/tests/features/common/page-objects.js @@ -35,7 +35,7 @@ import documents from './page-objects/documents.po' import alerts from './page-objects/alerts.po' import monitoringApp from './page-objects/monitoring-app.po' -module.exports = { +export default { Add_To_Feature_Vector_Popup: interactivePopup['addToFeatureVectorPopup'], Add_To_Feature_Vector_Tab: featureStore['addToFeatureVector'], Add_Tag_Popup: interactivePopup['addTagPopup'], diff --git a/tests/features/common/page-objects/alerts-monitoring.po.js b/tests/features/common/page-objects/alerts-monitoring.po.js index 8be7b6a0f2..0c8a08444c 100644 --- a/tests/features/common/page-objects/alerts-monitoring.po.js +++ b/tests/features/common/page-objects/alerts-monitoring.po.js @@ -169,7 +169,7 @@ const dateTimePickerCalendars = { const commonErrorMessage = By.css('[data-testid="no-data"] h3') -module.exports = { +export default { alertsMonitoring: { Table_FilterBy_Button: By.css('[data-testid="filter-menu-btn-tooltip-wrapper"]'), Refresh_Button: By.css('[data-testid="refresh"] [data-testid="refresh-tooltip-wrapper"]'), diff --git a/tests/features/common/page-objects/alerts.po.js b/tests/features/common/page-objects/alerts.po.js index f8b4f24fd7..4b277d6360 100644 --- a/tests/features/common/page-objects/alerts.po.js +++ b/tests/features/common/page-objects/alerts.po.js @@ -169,7 +169,7 @@ const dateTimePickerCalendars = { const commonErrorMessage = By.css('[data-testid="no-data"] h3') -module.exports = { +export default { alerts: { Table_FilterBy_Button: By.css('[data-testid="filter-menu-btn-tooltip-wrapper"]'), Refresh_Button: By.css('[data-testid="refresh"] [data-testid="refresh-tooltip-wrapper"]'), diff --git a/tests/features/common/page-objects/commonPagesHeader.po.js b/tests/features/common/page-objects/commonPagesHeader.po.js index 55b8480907..3a4c3b0aef 100644 --- a/tests/features/common/page-objects/commonPagesHeader.po.js +++ b/tests/features/common/page-objects/commonPagesHeader.po.js @@ -35,7 +35,7 @@ const generalInfoQuickLinks = { } } -module.exports = { +export default { loader: By.css('.loader-wrapper .loader'), See_On_Github: By.css('header.header a[alt="MLRUN on Gihub"]'), See_On_Slack: By.css('header.header a[alt="MLRUN on Slack"]'), diff --git a/tests/features/common/page-objects/documents.po.js b/tests/features/common/page-objects/documents.po.js index d618689ec4..675ce44021 100644 --- a/tests/features/common/page-objects/documents.po.js +++ b/tests/features/common/page-objects/documents.po.js @@ -83,7 +83,7 @@ const documentsTable = { } } -module.exports = { +export default { documents: { Table_Name_Filter_Input: inputGroup( generateInputGroup( diff --git a/tests/features/common/page-objects/feature-store.po.js b/tests/features/common/page-objects/feature-store.po.js index 74cc647f39..d4f6cd9b7f 100644 --- a/tests/features/common/page-objects/feature-store.po.js +++ b/tests/features/common/page-objects/feature-store.po.js @@ -378,7 +378,7 @@ const commonTableTreeFilterDropdown = dropdownComponent( ) ) -module.exports = { +export default { featureSetsTab: { Table_FilterBy_Button: tableFilterByButton, Table_Refresh_Button: tableRefreshButton, diff --git a/tests/features/common/page-objects/files.po.js b/tests/features/common/page-objects/files.po.js index 149f1a2ec8..41fdbe3693 100644 --- a/tests/features/common/page-objects/files.po.js +++ b/tests/features/common/page-objects/files.po.js @@ -94,7 +94,7 @@ const filesTable = { } } -module.exports = { +export default { filesTab: { Table_Name_Filter_Input: inputGroup( generateInputGroup( diff --git a/tests/features/common/page-objects/info-pane.po.js b/tests/features/common/page-objects/info-pane.po.js index c6e55c9d42..3fa4609baf 100644 --- a/tests/features/common/page-objects/info-pane.po.js +++ b/tests/features/common/page-objects/info-pane.po.js @@ -589,7 +589,7 @@ const commonVersionTagInput = inputGroup( const commonVersionTagInputFullView = By.css('.table__item_big .details-item__input-wrapper input') const commonLabelsApplyButton = By.css('.item-info__details-wrapper .details-item .details-item__data-chips .details-item__apply-btn-wrapper') -module.exports = { +export default { featureSetsInfoPane: { Header: header, Updated: updated, diff --git a/tests/features/common/page-objects/interactive-popup.po.js b/tests/features/common/page-objects/interactive-popup.po.js index 213a3bc0cd..3e38b435fc 100644 --- a/tests/features/common/page-objects/interactive-popup.po.js +++ b/tests/features/common/page-objects/interactive-popup.po.js @@ -37,8 +37,7 @@ import { generateCheckboxGroup } from '../../common-tools/common-tools' import inputWithAutocomplete from '../components/input-with-autocomplete.component' - -const { By } = require('selenium-webdriver') +import { By } from 'selenium-webdriver' const memberOverviewLabelsTable = { root: '.settings__members', @@ -717,7 +716,7 @@ const infoPaneOverviewSourcesHeaders = { } } -module.exports = { +export default { createNewProject: { Title: commonTitle, Name_Input: inputGroup( diff --git a/tests/features/common/page-objects/jobs-and-workflows.po.js b/tests/features/common/page-objects/jobs-and-workflows.po.js index d0e8ce1207..422496f6df 100644 --- a/tests/features/common/page-objects/jobs-and-workflows.po.js +++ b/tests/features/common/page-objects/jobs-and-workflows.po.js @@ -460,7 +460,7 @@ const commonCustomRangeFilter = dropdownComponent( ) ) -module.exports = { +export default { JobsMonitorTab: { Jobs_Tab_Selector: jobsTabSelector, Date_Picker_Filter_Dropdown: commonDatePickerFilter, diff --git a/tests/features/common/page-objects/jobs-monitoring.po.js b/tests/features/common/page-objects/jobs-monitoring.po.js index 014aed9ab5..4d7a6b2731 100644 --- a/tests/features/common/page-objects/jobs-monitoring.po.js +++ b/tests/features/common/page-objects/jobs-monitoring.po.js @@ -278,7 +278,7 @@ const dateTimePickerCalendars = { const commonRefreshButton = By.css('[data-testid="refresh"]') const commonErrorMessage = By.css('[data-testid="no-data"] h3') -module.exports = { +export default { crossJobsMonitorTab: { Cross_Jobs_Tab_Selector: commonTable(tabSelector), Table_FilterBy_Button: By.css('[data-testid="filter-menu-btn-tooltip-wrapper"]'), diff --git a/tests/features/common/page-objects/ml-functions.po.js b/tests/features/common/page-objects/ml-functions.po.js index 11cdd7a382..edba565146 100644 --- a/tests/features/common/page-objects/ml-functions.po.js +++ b/tests/features/common/page-objects/ml-functions.po.js @@ -86,7 +86,7 @@ const functionsTable = { } } -module.exports = { +export default { mlFunctions: { Table_Name_Filter_Input: inputGroup( generateInputGroup( diff --git a/tests/features/common/page-objects/models.po.js b/tests/features/common/page-objects/models.po.js index c20bd21112..d298177acd 100644 --- a/tests/features/common/page-objects/models.po.js +++ b/tests/features/common/page-objects/models.po.js @@ -257,7 +257,7 @@ const tableNameFilterInput = inputGroup( ) ) -module.exports = { +export default { modelsTab: { Delete_Artifact_Popup: By.css('[data-testid="pop-up-dialog"]'), Models_Tab_Selector: commonTable(tabSelector), diff --git a/tests/features/common/page-objects/monitoring-app.po.js b/tests/features/common/page-objects/monitoring-app.po.js index bf8e83658d..87391e4e96 100644 --- a/tests/features/common/page-objects/monitoring-app.po.js +++ b/tests/features/common/page-objects/monitoring-app.po.js @@ -113,7 +113,7 @@ const dateTimePickerCalendars = { } // datepicker end -module.exports = { +export default { monitoringApp: { Refresh_Button: By.css('[data-testid="refresh"] [data-testid="refresh-tooltip-wrapper"]'), Date_Picker_Filter_Dropdown: commonDatePickerFilter, diff --git a/tests/features/common/page-objects/project-settings.po.js b/tests/features/common/page-objects/project-settings.po.js index 31c68c8bab..87fb7ade51 100644 --- a/tests/features/common/page-objects/project-settings.po.js +++ b/tests/features/common/page-objects/project-settings.po.js @@ -123,7 +123,7 @@ const secretsTable = { } } -module.exports = { +export default { generalTab: { Project_Settings_Tab_Selector: commonTable(tabSelector), Source_URL_Input: inputGroup( diff --git a/tests/features/common/page-objects/project.po.js b/tests/features/common/page-objects/project.po.js index 22cab8706f..8c91a06d9b 100644 --- a/tests/features/common/page-objects/project.po.js +++ b/tests/features/common/page-objects/project.po.js @@ -47,7 +47,7 @@ const actionMenuStructure = { } const projectDashboardRealtimeFunctionsTable = { - root: '.main-info__statistics-section .d-flex:nth-of-type(2) .project-data-card .project-data-card__table', + root: '.main-info__statistics-section .d-flex:nth-of-type(2) .project-data-card', header: { root: '.project-data-card__table-header', sorters: { @@ -56,19 +56,19 @@ const projectDashboardRealtimeFunctionsTable = { } }, body: { - root: '.project-data-card__table-body', + root: '.section-table__table-body', row: { - root: '.project-data-card__table-row', + root: '.section-table__table-row', fields: { - name: '.project-data-card__table-cell:nth-of-type(1) .data-ellipsis', - status: '.project-data-card__table-cell:nth-of-type(2) .data-ellipsis' + name: '.table-cell_big .data-ellipsis', + status: '.status-cell .data-ellipsis' } } } } const projectJobsAndWorkflows = { - root: '.main-info__statistics-section:nth-of-type(4) .project-data-card:nth-of-type(1)', + root: '.main-info__statistics-section:nth-of-type(4) .d-flex:nth-of-type(1) .project-data-card', header: { root: '.project-data-card__table-header', sorters: { @@ -80,16 +80,16 @@ const projectJobsAndWorkflows = { } }, body: { - root: '.project-data-card__table-body', + root: '.section-table__table-body', row: { - root: '.project-data-card__table-row', + root: '.section-table__table-row', fields: { - name: '.project-data-card__table-cell:nth-of-type(1) .link', - type: '.project-data-card__table-cell:nth-of-type(2) .data-ellipsis', - status: '.project-data-card__table-cell:nth-of-type(2) .data-ellipsis', + name: '.table-cell_big:nth-of-type(1) .data-ellipsis', + type: '.table-cell_small .data-ellipsis', + status: '.status-cell .data-ellipsis', started_at: - '.project-data-card__table-cell:nth-of-type(2) .data-ellipsis', - duration: '.project-data-card__table-cell:nth-of-type(2) .data-ellipsis' + '.table-cell_big:nth-of-type(4) .data-ellipsis', + duration: '.table-cell_medium:nth-of-type(5) .data-ellipsis' } } } @@ -282,7 +282,7 @@ const shardLagsTable = { } } -module.exports = { +export default { project: { Create_New: createNewObject, Refresh_Button: By.css('.main-info__toolbar [data-testid="refresh"]'), @@ -304,13 +304,17 @@ module.exports = { Artifacts_Stats_Title: By.css('.main-info__statistics-section_left .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(1) .stats-card__title span'), Artifacts_Stats_Tip: By.css('.stats-card:nth-of-type(3) .stats-card__row:nth-of-type(1) [data-testid="tip"]'), Artifacts_Stats_Counter: By.css('.stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="monitoring-Artifacts"] .stats__counter'), - ConsumerGroups_Stats_Title: By.css('.main-info__statistics-section_right .stats-card:nth-of-type(1) .stats-card__row:nth-of-type(1) .stats-card__title span'), - ConsumerGroups_Stats_Counter: By.css('.stats-card:nth-of-type(1) .stats-card__row:nth-of-type(2) [data-testid="monitoring-Consumer groups"] .stats__counter'), - Alerts_Stats_Title: By.css('.main-info__statistics-section_right .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(1) .stats-card__title span'), - Alerts_Stats_Total_Number: By.css('.main-info__statistics-section_right .stats-card:nth-of-type(2) [data-testid="alerts_total_counter"] .stats__counter'), - Alerts_Stats_Endpoint_Number: By.css('.main-info__statistics-section_right .stats-card:nth-of-type(2) [data-testid="alerts_endpoint_counter"] .stats__counter'), - Alerts_Stats_Jobs_Number: By.css('.main-info__statistics-section_right .stats-card:nth-of-type(2) [data-testid="alerts_jobs_counter"] .stats__counter'), - Alerts_Stats_Application_Number: By.css('.main-info__statistics-section_right .stats-card:nth-of-type(2) [data-testid="alerts_application_counter stats__counter-large"] .stats__counter'), + ConsumerGroups_Stats_Title: By.css('.main-info__statistics-section:nth-of-type(4) .d-flex:nth-of-type(2) .project-data-card__header .project-data-card__statistics-item:nth-of-type(4) .project-data-card__statistics-label'), + ConsumerGroups_Stats_Counter: By.css('.main-info__statistics-section:nth-of-type(4) .d-flex:nth-of-type(2) .project-data-card__header .project-data-card__statistics-item:nth-of-type(4) .project-data-card__statistics-value'), + Alerts_Stats_Title: By.css('.main-info__statistics-section_right .stats-card__title span'), + Alerts_Stats_Total_Title: By.css('.main-info__statistics-section_right [data-testid="alerts_total_counter"] span'), + Alerts_Stats_Total_Number: By.css('.main-info__statistics-section_right [data-testid="alerts_total_counter"] .stats__counter'), + Alerts_Stats_Endpoint_Number: By.css('.main-info__statistics-section_right [data-testid="alerts_endpoint_counter"] .stats__counter'), + Alerts_Stats_Endpoint_Title: By.css('.main-info__statistics-section_right [data-testid="alerts_endpoint_counter"] .stats__subtitle'), + Alerts_Stats_Jobs_Number: By.css('.main-info__statistics-section_right [data-testid="alerts_jobs_counter"] .stats__counter'), + Alerts_Stats_Jobs_Title: By.css('.main-info__statistics-section_right [data-testid="alerts_jobs_counter"] .stats__subtitle'), + Alerts_Stats_Application_Number: By.css('.main-info__statistics-section_right [data-testid="alerts_application_counter stats__counter-large"] .stats__counter'), + Alerts_Stats_Application_Title: By.css('.main-info__statistics-section_right [data-testid="alerts_application_counter stats__counter-large"] .stats__subtitle'), Jobs_Info_Card_Statistics: commonTable(generalInfoJobsCardStat), Real_Time_Functions_Card_Statistics: commonTable( generalInfoRealTimeFunctionsCardStat diff --git a/tests/features/common/page-objects/projects.po.js b/tests/features/common/page-objects/projects.po.js index 7e261373ac..7f780fc86b 100644 --- a/tests/features/common/page-objects/projects.po.js +++ b/tests/features/common/page-objects/projects.po.js @@ -101,7 +101,7 @@ const ProjectsTableSelector = { } } -module.exports = { +export default { Retrieving_Projects_Message: By.css('[data-testid=no-data]'), No_Archived_Projects_Message: By.css('.no-filtered-data'), New_Project_Button: By.css( @@ -115,7 +115,7 @@ module.exports = { '.projects__wrapper .projects-content-header .projects-content-header-item [data-testid="active"]' ), Archive_Projects_Button: By.css( - '.projects__wrapper .projects-content-header .projects-content-header-item [data-testid=archived] a' + '.projects__wrapper .projects-content-header .projects-content-header-item [data-testid=archived]' ), Projects_Sorter: By.css('.projects-content-header-item .sort .split-btn__button:nth-of-type(1)'), Projects_Sort_Dropdown: dropdownComponent( @@ -274,7 +274,7 @@ module.exports = { '.stats-card:nth-of-type(4) [data-testid="alerts_application_counter stats__counter-large"] .stats__counter' ), Total_Application_Counter_Title: By.css( - '.stats-card:nth-of-type(4) [data-testid="alerts_application_counter"] .stats__subtitle' + '.stats-card:nth-of-type(4) [data-testid="alerts_application_counter stats__counter-large"] .stats__subtitle' ), Total_Alerts_Title: By.css( '.stats-card:nth-of-type(4) .stats-card__col > div > div > span' diff --git a/tests/features/common/page-objects/side-panel.po.js b/tests/features/common/page-objects/side-panel.po.js index 5205c1b429..37f485fbf8 100644 --- a/tests/features/common/page-objects/side-panel.po.js +++ b/tests/features/common/page-objects/side-panel.po.js @@ -36,7 +36,7 @@ import { generateCheckboxGroup, generateTextAreaGroup } from '../../common-tools/common-tools' -const { By } = require('selenium-webdriver') +import { By } from 'selenium-webdriver' const actionMenuStructure = { root: '.table__cell-actions', @@ -734,7 +734,7 @@ const commonAccessKeyInput = inputGroup( ) ) -module.exports = { +export default { newFeatureSet: { Cross_Close_Button: commonCrossCloseButton, Feature_Set_Name_Input: inputGroup( diff --git a/tests/features/datasets.feature b/tests/features/datasets.feature index 1527a07436..d1e932e1e1 100644 --- a/tests/features/datasets.feature +++ b/tests/features/datasets.feature @@ -157,6 +157,7 @@ Feature: Datasets Page Then click on "show_all_versions" option on "Datasets" wizard in "Datasets_Table" table with "test-dataset" value in "name" column with scroll "false" And wait load page When click on cell with row index 1 in "uid" column in "Datasets_Table" table on "Datasets" wizard + And wait load page Then check "v1" value in "tag" column in "Overview_Table" table on "Datasets_Info_Pane" wizard Then click on "Edit_btn_table_view" element on "Datasets_Info_Pane" wizard And wait load page diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index 30ead4cb8a..4e78b93ea3 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -209,6 +209,7 @@ Feature: Jobs and workflows Then verify "Jobs_Monitor_Table" element visibility on "Jobs_Monitor_Tab" wizard When pick up "Custom range" from "10/01/2021 00:00" to "11/30/2021 00:00" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard And wait load page + And wait load page Then verify from "10/01/2021 00:00" to "11/30/2021 00:00" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard And wait load page Then verify "Jobs_Monitor_Table" element visibility on "Jobs_Monitor_Tab" wizard @@ -226,13 +227,18 @@ Feature: Jobs and workflows And hover "MLRun_Logo" component on "commonPagesHeader" wizard And wait load page When pick up "Custom range" from "03/31/2014 10:30" to "03/21/2015 19:15" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard + And wait load page Then verify from "03/31/2014 10:30" to "03/21/2015 19:15" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard When pick up "Custom range" from "03/31/2044 10:30" to "03/21/2015 19:15" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard + And wait load page Then verify error message in "Date_Time_Picker" on "Jobs_Monitor_Tab" wizard with value "Date_Time_Picker"."Error_Message" Then click on "Table_Refresh_Button" element on "Jobs_Monitor_Tab" wizard When pick up "Custom range" from "03/31/2030 10:30" to "03/31/2030 10:31" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard + And wait load page Then verify from "03/31/2030 10:30" to "03/31/2030 10:31" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard When pick up "Custom range" from "03/31/2025 10:31" to "03/21/2025 10:30" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard + And wait load page + And wait load page Then verify error message in "Date_Time_Picker" on "Jobs_Monitor_Tab" wizard with value "Date_Time_Picker"."Error_Message" @MLJW @@ -1192,6 +1198,8 @@ Feature: Jobs and workflows And wait load page Then verify "Monitor Jobs" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard When pick up "Custom range" from "09/01/2021 18:00" to "09/03/2021 18:00" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard + And wait load page + And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitor_Tab" wizard Then select "Error" option in "Status_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard @@ -1207,6 +1215,7 @@ Feature: Jobs and workflows And wait load page Then verify options in action menu on "Jobs_Monitor_Tab" wizard in "Jobs_Monitor_Table" table with "Running" value in "status" column should contains "Jobs_And_Workflows"."Running_Job_Action_Menu_Options" When pick up "Custom range" from "08/28/2021 18:00" to "09/01/2021 18:00" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard + And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitor_Tab" wizard Then select "Running" option in "Status_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard @@ -1642,7 +1651,7 @@ Feature: Jobs and workflows And wait load page Then verify redirection from "projects/default/jobs/monitor-jobs/aggregate-test/864f4da42773494eb94dce1c8834feb6/resultsINVALID?dates=anyTime&savedParams=P2JlUGFnZT0xJmZlUGFnZT0xJmRhdGVzPWFueVRpbWU%3D&bePage=1&fePage=1" to "projects/default/jobs/monitor-jobs/aggregate-test/864f4da42773494eb94dce1c8834feb6/overview?dates=anyTime&savedParams=P2JlUGFnZT0xJmZlUGFnZT0xJmRhdGVzPWFueVRpbWU%3D&bePage=1&fePage=1" And wait load page - Then verify redirection from "projects/default/jobs/monitor-jobs/aggregate-test/INVALID/overview?dates=anyTime&savedParams=P2JlUGFnZT0xJmZlUGFnZT0xJmRhdGVzPWFueVRpbWU%3D&bePage=1&fePage=1" to "projects/default/jobs/monitor-jobs/aggregate-test/INVALID/overview?dates=anyTime&savedParams=P2JlUGFnZT0xJmZlUGFnZT0xJmRhdGVzPWFueVRpbWU%3D&bePage=1&fePage=1" + Then verify redirection from "projects/default/jobs/monitor-jobs/aggregate-test/INVALID/overview?dates=anyTime&savedParams=P2JlUGFnZT0xJmZlUGFnZT0xJmRhdGVzPWFueVRpbWU%3D&bePage=1&fePage=1" to "projects/default/jobs/monitor-jobs/aggregate-test?dates=anyTime&savedParams=P2JlUGFnZT0xJmZlUGFnZT0xJmRhdGVzPWFueVRpbWU%3D&bePage=1&fePage=1" And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard @@ -2116,6 +2125,7 @@ Feature: Jobs and workflows Then select "Hub" tab in "Function_Selection_Tabs" on "Modal_Wizard_Form" wizard And wait load page And click on row root with value "auto-trainer" in "name" column in "Functions_Table" table on "Modal_Wizard_Form" wizard + And wait load page Then "Function_Title" element on "Modal_Wizard_Form" should contains "auto-trainer" value Then verify "Next_Button" element on "Modal_Wizard_Form" wizard is enabled And click on "Step_4_Button" element on "commonPagesHeader" wizard @@ -2794,6 +2804,7 @@ Feature: Jobs and workflows And wait load page Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Job erann-test (...e19ea57) was aborted" value And wait load page + And wait load page Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard Then verify "Table_Refresh_Button" element visibility on "Jobs_Monitor_Tab" wizard diff --git a/tests/features/projectMonitoring.feature b/tests/features/projectMonitoring.feature index 5ccba9ae2a..91afe20084 100644 --- a/tests/features/projectMonitoring.feature +++ b/tests/features/projectMonitoring.feature @@ -29,11 +29,21 @@ Feature: Project Monitoring Page Then verify "Artifacts_Stats_Tip" element on "Project" wizard should display hover hint "Label_Hint"."Artifacts_Stats_Tip" Then verify "Artifacts_Stats_Counter" element visibility on "Project" wizard Then verify "Alerts_Stats_Title" element visibility on "Project" wizard + Then "Alerts_Stats_Title" element on "Project" should contains "Alerts" value + Then verify "Alerts_Stats_Total_Title" element visibility on "Project" wizard + Then "Alerts_Stats_Total_Title" element on "Project" should contains "Total" value Then verify "Alerts_Stats_Total_Number" element visibility on "Project" wizard + Then verify "Alerts_Stats_Endpoint_Title" element visibility on "Project" wizard + Then "Alerts_Stats_Endpoint_Title" element on "Project" should contains "Endpoint" value Then verify "Alerts_Stats_Endpoint_Number" element visibility on "Project" wizard + Then verify "Alerts_Stats_Jobs_Title" element visibility on "Project" wizard + Then "Alerts_Stats_Jobs_Title" element on "Project" should contains "Jobs" value Then verify "Alerts_Stats_Jobs_Number" element visibility on "Project" wizard + Then verify "Alerts_Stats_Application_Title" element visibility on "Project" wizard + Then "Alerts_Stats_Application_Title" element on "Project" should contains "Application" value Then verify "Alerts_Stats_Application_Number" element visibility on "Project" wizard Then verify "ConsumerGroups_Stats_Title" element visibility on "Project" wizard + Then "ConsumerGroups_Stats_Title" element on "Project" should contains "Consumer groups" value Then verify "ConsumerGroups_Stats_Counter" element visibility on "Project" wizard Then verify "Jobs_Info_Card_Statistics" element visibility on "Project" wizard Then verify "Real_Time_Functions_Card_Statistics" element visibility on "Project" wizard @@ -64,7 +74,6 @@ Feature: Project Monitoring Page Then verify "Documents_Button" element visibility on "commonPagesHeader" wizard Then verify "Artifacts_Button" element visibility on "commonPagesHeader" wizard Then verify "Models_Button" element visibility on "commonPagesHeader" wizard - Then verify "Monitoring_App_Button" element visibility on "commonPagesHeader" wizard Then verify "Jobs_And_Workflows_Button" element visibility on "commonPagesHeader" wizard Then verify "ML_Functions_Button" element visibility on "commonPagesHeader" wizard Then verify "Real_Time_Functions_Button" element visibility on "commonPagesHeader" wizard @@ -90,8 +99,6 @@ Feature: Project Monitoring Page Then verify "Artifacts_Icon" element visibility on "commonPagesHeader" wizard Then verify "Models_Button" element invisibility on "commonPagesHeader" wizard Then verify "Models_Icon" element visibility on "commonPagesHeader" wizard - Then verify "Monitoring_App_Button" element invisibility on "commonPagesHeader" wizard - Then verify "Monitoring_App_Icon" element visibility on "commonPagesHeader" wizard Then verify "Jobs_And_Workflows_Button" element invisibility on "commonPagesHeader" wizard Then verify "Jobs_And_Workflows_Icon" element visibility on "commonPagesHeader" wizard Then verify "ML_Functions_Button" element invisibility on "commonPagesHeader" wizard @@ -150,6 +157,8 @@ Feature: Project Monitoring Page When turn on demo mode with query params "false" And wait load page And wait load page + Then verify "Monitoring_App_Button" element visibility on "commonPagesHeader" wizard + Then verify "Monitoring_App_Icon" element visibility on "commonPagesHeader" wizard Then verify "LLM_Prompts_Button" element visibility on "commonPagesHeader" wizard Then verify "LLM_Prompts_Icon" element visibility on "commonPagesHeader" wizard @@ -798,6 +807,7 @@ Feature: Project Monitoring Page And wait load page Then click on "ConsumerGroups_Stats_Counter" element on "Project" wizard And wait load page + And wait load page Then "Title" element on "Consumer_Groups" should contains "Consumer groups (v3io stream)" value Then "Description" element on "Consumer_Groups" should contains "This report displays the project's consumer groups for Iguazio v3io streams" value Then verify "Arrow_Back" element visibility on "Consumer_Groups" wizard @@ -805,6 +815,7 @@ Feature: Project Monitoring Page Then verify "Consumer_Groups_Table" element visibility on "Consumer_Groups" wizard Then click on "Arrow_Back" element on "Consumer_Groups" wizard And wait load page + And wait load page Then verify breadcrumbs "project" label should be equal "default" value Then verify "Create_New" element visibility on "Project" wizard Then verify "Refresh_Button" element visibility on "Project" wizard @@ -824,6 +835,7 @@ Feature: Project Monitoring Page And wait load page Then click on "ConsumerGroups_Stats_Counter" element on "Project" wizard And wait load page + And wait load page Then verify "Search_Input" element visibility on "Consumer_Groups" wizard Then verify "Consumer_Groups_Table" element visibility on "Consumer_Groups" wizard Then type value "C" to "Search_Input" field on "Consumer_Groups" wizard @@ -849,6 +861,7 @@ Feature: Project Monitoring Page And wait load page Then click on "ConsumerGroups_Stats_Counter" element on "Project" wizard And wait load page + And wait load page And save to context "consumer_group_name" column and "href" attribute on 1 row from "Consumer_Groups_Table" table on "Consumer_Groups" wizard And click on cell with row index 1 in "consumer_group_name" column in "Consumer_Groups_Table" table on "Consumer_Groups" wizard And wait load page diff --git a/tests/features/projectsPage.feature b/tests/features/projectsPage.feature index 663a6bd9a3..753ea893a9 100644 --- a/tests/features/projectsPage.feature +++ b/tests/features/projectsPage.feature @@ -5,7 +5,6 @@ Feature: Projects Page @MLPr @passive @smoke - #TODO: last two steps are unstable on small screen extensions because scroll change the screen coordinates, it needs another solution Scenario: MLPr001 - Check all mandatory components Given open url And wait load page @@ -252,10 +251,14 @@ Feature: Projects Page Then check "automation-test-name7" value in "name" column in "Projects_Table" table on "Projects" wizard Then select "Unarchive" option in action menu on "Projects" wizard in "Projects_Table" table at row with "automation-test-name7" value in "name" column And wait load page + Then select "Unarchive" option in action menu on "Projects" wizard in "Projects_Table" table at row with "hedi-proj" value in "name" column And wait load page Then "No_Archived_Projects_Message" element on "Projects" should contains "No archived projects." value Then click on "Active_Projects_Button" element on "Projects" wizard Then check "automation-test-name7" value in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then check "hedi-proj" value in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page @MLPr @passive diff --git a/tests/features/step-definitions/steps.js b/tests/features/step-definitions/steps.js index fd47318b1d..4ba1c93160 100644 --- a/tests/features/step-definitions/steps.js +++ b/tests/features/step-definitions/steps.js @@ -821,14 +821,14 @@ When( pageObjects[wizardName][dropdownName], optionValue ) - await this.driver.sleep(200) + await this.driver.sleep(1000) await pickUpCustomDatetimeRange( this.driver, pageObjects[wizardName][datetimePicker], fromDatetime, toDatetime ) - await this.driver.sleep(200) + await this.driver.sleep(1000) await applyDatetimePickerRange( this.driver, pageObjects[wizardName][datetimePicker] diff --git a/tests/features/support/world.js b/tests/features/support/world.js index 75a0fbad11..af6f2827db 100644 --- a/tests/features/support/world.js +++ b/tests/features/support/world.js @@ -23,8 +23,8 @@ import firefox from 'selenium-webdriver/firefox' import { setWorldConstructor, setDefaultTimeout } from '@cucumber/cucumber' import { timeout, browser, headless, screen_size } from '../../config' -require('chromedriver') -require('geckodriver') +import 'chromedriver' +import 'geckodriver' class World { constructor({ attach, log, parameters }) { From ea77aa5528138d49f9f7c5a262b318ce45f1f42f Mon Sep 17 00:00:00 2001 From: adi-gini Date: Thu, 12 Jun 2025 11:52:49 +0300 Subject: [PATCH 010/228] =?UTF-8?q?Impl=20[Workflows]=20Add=20"Terminate"?= =?UTF-8?q?=20Button=20to=20Monitor=20Workflow=20=E2=80=93=20Main=20and=20?= =?UTF-8?q?Details=20(#3285)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/api/workflow-api.js | 3 + .../monitorWorkflows.util.jsx | 22 ++++- src/components/Workflow/Workflow.jsx | 75 ++++++++++----- src/components/Workflow/workflow.scss | 13 +++ src/components/Workflow/workflow.util.js | 92 +++++++++++++++++++ .../WorkflowsTable/WorkflowsTable.jsx | 55 ++++++++++- src/reducers/projectReducer.js | 10 +- src/scss/main.scss | 2 +- 9 files changed, 238 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index b7a489f518..e81320a051 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.0.4", + "iguazio.dashboard-react-controls": "3.1.0", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", diff --git a/src/api/workflow-api.js b/src/api/workflow-api.js index 0d5db970a6..846a67971a 100644 --- a/src/api/workflow-api.js +++ b/src/api/workflow-api.js @@ -111,6 +111,9 @@ const workflowsApi = { }, rerunWorkflow: (project, workflowId) => { return mainHttpClient.post(`projects/${project}/pipelines/${workflowId}/retry`) + }, + terminateWorkflow: (project, workflowId) => { + return mainHttpClient.post(`/projects/${project}/pipelines/${workflowId}/terminate`) } } diff --git a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx index 93dabd6609..e9b57c2b2e 100644 --- a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx +++ b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx @@ -22,6 +22,7 @@ import { debounce } from 'lodash' import { FUNCTIONS_PAGE, + FUNCTION_RUNNING_STATE, GROUP_BY_NONE, GROUP_BY_WORKFLOW, JOBS_PAGE, @@ -46,7 +47,8 @@ import { isEveryObjectValueEmpty } from '../../../utils/isEveryObjectValueEmpty' import MonitorIcon from 'igz-controls/images/monitor-icon.svg?react' import Run from 'igz-controls/images/run.svg?react' -import Cancel from 'igz-controls/images/close.svg?react' +import Cancel from 'igz-controls/images/cancel.svg?react' +import Close from 'igz-controls/images/close.svg?react' import Yaml from 'igz-controls/images/yaml.svg?react' import Delete from 'igz-controls/images/delete.svg?react' import Rerun from 'igz-controls/images/rerun.svg?react' @@ -85,6 +87,8 @@ export const generateActionsMenu = ( abortable_function_kinds, handleConfirmAbortJob, handleConfirmDeleteJob, + handleConfirmTerminateWorkflow, + accessibleProjectsMap, toggleConvertedYaml, handleRerun, rerunIsDisabled @@ -115,7 +119,7 @@ export const generateActionsMenu = ( }, { label: 'Abort', - icon: , + icon: , onClick: handleConfirmAbortJob, tooltip: jobKindIsAbortable ? jobIsAborting @@ -155,9 +159,17 @@ export const generateActionsMenu = ( icon: , label: 'Retry', onClick: () => handleRerun(job), - tooltip: - [PENDING_STATE, UNKNOWN_STATE].includes(job?.state?.value) && - 'Retry is unavailable while workflow status is pending, refresh the display to check for updates.' + tooltip: [PENDING_STATE, UNKNOWN_STATE].includes(job?.state?.value) + ? 'Retry is unavailable while workflow status is pending, refresh the display to check for updates.' + : '' + }, + { + label: 'Terminate', + icon: , + className: 'danger', + onClick: handleConfirmTerminateWorkflow, + hidden: !accessibleProjectsMap[job?.project], + disabled: job?.state?.value !== FUNCTION_RUNNING_STATE } ] ] diff --git a/src/components/Workflow/Workflow.jsx b/src/components/Workflow/Workflow.jsx index 449f498a65..6e775f1e43 100644 --- a/src/components/Workflow/Workflow.jsx +++ b/src/components/Workflow/Workflow.jsx @@ -20,7 +20,7 @@ such restriction. import React, { useEffect, useState, useMemo } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import { forEach, isEmpty } from 'lodash' +import { forEach, isEmpty, lowerCase } from 'lodash' import { useNavigate, useParams } from 'react-router-dom' import Details from '../Details/Details' @@ -28,13 +28,14 @@ import JobsFunctionsTableRow from './JobsFunctionsTableRow/JobsFunctionsTableRow import MlReactFlow from '../../common/ReactFlow/MlReactFlow' import Table from '../Table/Table' import TableTop from '../../elements/TableTop/TableTop' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Button, Tooltip, TextTooltipTemplate } from 'igz-controls/components' import { getLayoutedElements, getWorkflowSourceHandle } from '../../common/ReactFlow/mlReactFlow.util' import { + fetchMissingProjectPermission, getWorkflowDetailsLink, getWorkflowMonitoringDetailsLink, isWorkflowStepCondition, @@ -43,6 +44,7 @@ import { } from './workflow.util' import { DEFAULT_EDGE, + FUNCTION_RUNNING_STATE, GREY_NODE, JOB_KIND_JOB, JOBS_PAGE, @@ -60,7 +62,9 @@ import { createJobsWorkflowContent } from '../../utils/createJobsContent' import { getCloseDetailsLink } from '../../utils/link-helper.util' import { useMode } from '../../hooks/mode.hook' import { useSortTable } from '../../hooks/useSortTable.hook' +import { useDispatch, useSelector } from 'react-redux' +import Cancel from 'igz-controls/images/cancel.svg?react' import ListView from 'igz-controls/images/listview.svg?react' import Pipelines from 'igz-controls/images/pipelines.svg?react' @@ -70,6 +74,7 @@ const Workflow = ({ actionsMenu, backLink, handleCancel, + handleConfirmTerminateWorkflow, itemIsSelected, pageData, selectedFunction = {}, @@ -84,6 +89,13 @@ const Workflow = ({ const params = useParams() const navigate = useNavigate() const { isStagingMode } = useMode() + const projectName = params.workflowProjectName || params.projectName + const dispatch = useDispatch() + const accessibleProjectsMap = useSelector(state => state.projectStore.accessibleProjectsMap) + + useEffect(() => { + fetchMissingProjectPermission(projectName, accessibleProjectsMap, dispatch) + }, [dispatch, projectName, accessibleProjectsMap]) const graphViewClassNames = classnames( 'graph-view', @@ -218,31 +230,43 @@ const Workflow = ({ return (
      -
      - - } - > - - + + +
      + {accessibleProjectsMap[projectName] && ( +
      @@ -296,6 +320,7 @@ Workflow.propTypes = { actionsMenu: ACTIONS_MENU.isRequired, backLink: PropTypes.string.isRequired, handleCancel: PropTypes.func.isRequired, + handleConfirmTerminateWorkflow: PropTypes.func, itemIsSelected: PropTypes.bool.isRequired, pageData: PropTypes.object.isRequired, selectedFunction: PropTypes.object, diff --git a/src/components/Workflow/workflow.scss b/src/components/Workflow/workflow.scss index a83c2c7a9c..3985ad0e26 100644 --- a/src/components/Workflow/workflow.scss +++ b/src/components/Workflow/workflow.scss @@ -6,6 +6,19 @@ flex-direction: column; width: 100%; + .workflow__actions { + &-container { + align-items: center; + flex-direction: row; + gap: 2px; + display: flex; + } + svg { + padding: 0; + height: 14px; + width: 14px; + } + } .workflow-content { flex-direction: column; diff --git a/src/components/Workflow/workflow.util.js b/src/components/Workflow/workflow.util.js index 34becccec6..c84758bd02 100644 --- a/src/components/Workflow/workflow.util.js +++ b/src/components/Workflow/workflow.util.js @@ -20,6 +20,17 @@ such restriction. import { cloneDeep, forEach, isEmpty, set } from 'lodash' import { page } from '../Jobs/jobs.util' +import { + pollTask, + BG_TASK_FAILED, + BG_TASK_SUCCEEDED, + isBackgroundTaskRunning +} from '../../utils/poll.util' +import tasksApi from '../../api/tasks-api' +import projectsIguazioApi from '../../api/projects-iguazio-api' +import { setNotification } from '../../reducers/notificationReducer' +import { setAccessibleProjectsMap } from '../../reducers/projectReducer' +import workflowsApi from '../../api/workflow-api' import { DETAILS_OVERVIEW_TAB, JOBS_MONITORING_PAGE, @@ -241,3 +252,84 @@ export const parseWorkflow = workflow => { return newWorkflow } + +export const handleTerminateWorkflow = async (job, dispatch) => { + try { + const response = await workflowsApi.terminateWorkflow(job.project, job.id) + const { data } = response + + if (!isBackgroundTaskRunning(response)) { + dispatch( + setNotification({ + status: 400, + id: Math.random(), + message: `Failed to start termination for workflow "${job.name}"` + }) + ) + return + } + + const taskId = data.metadata.name + + const pollMethod = () => tasksApi.getProjectBackgroundTask(job.project, taskId) + + const isDone = task => { + const state = task?.data?.status?.state + return [BG_TASK_SUCCEEDED, BG_TASK_FAILED].includes(state) + } + + const finalResult = await pollTask(pollMethod, isDone) + const finalState = finalResult?.data?.status?.state + + const success = finalState === BG_TASK_SUCCEEDED + + dispatch( + setNotification({ + status: success ? 200 : 400, + id: Math.random(), + message: `Workflow "${job.name}" ${success ? 'terminated successfully' : 'failed to terminate'}` + }) + ) + } catch { + dispatch( + setNotification({ + status: 400, + id: Math.random(), + message: `Workflow "${job.name} failed to terminate` + }) + ) + } +} + +export const fetchMissingProjectsPermissions = async (projectNames, currentMap, dispatch) => { + const uniqueProjects = [...new Set(projectNames)] + const missingProjects = uniqueProjects.filter(projectName => !(projectName in currentMap)) + if (missingProjects.length === 0) return + + const newMap = Object.fromEntries( + await Promise.all( + missingProjects.map(async projectName => { + try { + await projectsIguazioApi.getProjectOwnerVisibility(projectName) + return [projectName, true] + } catch { + return [projectName, false] + } + }) + ) + ) + + const mergedMap = { ...currentMap, ...newMap } + dispatch(setAccessibleProjectsMap(mergedMap)) +} + +export const fetchMissingProjectPermission = async (projectName, currentMap, dispatch) => { + if (projectName in currentMap) return + + try { + await projectsIguazioApi.getProjectOwnerVisibility(projectName) + dispatch(setAccessibleProjectsMap({ [projectName]: true })) + } catch { + dispatch(setAccessibleProjectsMap({ [projectName]: false })) + } +} diff --git a/src/elements/WorkflowsTable/WorkflowsTable.jsx b/src/elements/WorkflowsTable/WorkflowsTable.jsx index 44e36ae564..8dfcc4e741 100644 --- a/src/elements/WorkflowsTable/WorkflowsTable.jsx +++ b/src/elements/WorkflowsTable/WorkflowsTable.jsx @@ -62,7 +62,11 @@ import { getJobLogs } from '../../utils/getJobLogs.util' import { getNoDataMessage } from '../../utils/getNoDataMessage' import { isDetailsTabExists } from '../../utils/link-helper.util' import { isRowRendered, useVirtualization } from '../../hooks/useVirtualization.hook' -import { isWorkflowStepExecutable } from '../../components/Workflow/workflow.util' +import { + isWorkflowStepExecutable, + handleTerminateWorkflow, + fetchMissingProjectsPermissions +} from '../../components/Workflow/workflow.util' import { openPopUp, getScssVariableValue } from 'igz-controls/utils/common.util' import { parseFunction } from '../../utils/parseFunction' import { parseJob } from '../../utils/parseJob' @@ -106,6 +110,19 @@ const WorkflowsTable = React.forwardRef( const location = useLocation() const fetchJobFunctionsPromiseRef = useRef() let fetchFunctionLogsTimeout = useRef(null) + const accessibleProjectsMap = useSelector(state => state.projectStore.accessibleProjectsMap) + const [permissionsLoading, setPermissionsLoading] = useState(false) + + useEffect(() => { + const projectNames = workflowsStore.workflows.data.map(workflow => workflow.project) + setPermissionsLoading(true) + projectNames && + fetchMissingProjectsPermissions(projectNames, accessibleProjectsMap, dispatch).finally( + () => { + setPermissionsLoading(false) + } + ) + }, [dispatch, workflowsStore.workflows.data, accessibleProjectsMap]) const monitorWorkflowsRowHeight = useMemo( () => getScssVariableValue('--monitorWorkflowsRowHeight'), @@ -372,6 +389,13 @@ const WorkflowsTable = React.forwardRef( [onAbortJob, setConfirmData] ) + const onTerminateWorkflow = useCallback( + job => { + handleTerminateWorkflow(job, dispatch) + }, + [dispatch] + ) + const onDeleteJob = useCallback( job => { handleDeleteJob(false, job, refreshWorkflow, null, filters, dispatch).then(() => { @@ -406,6 +430,26 @@ const WorkflowsTable = React.forwardRef( [onDeleteJob, setConfirmData] ) + const handleConfirmTerminateWorkflow = useCallback( + job => { + setConfirmData({ + item: job, + header: 'Terminate workflow', + message: `Are you sure you want to terminate the workflow "${job.name}" (stop its execution)? Workflows termination cannot be undone.`, + btnConfirmLabel: 'Terminate', + btnConfirmType: DANGER_BUTTON, + rejectHandler: () => { + setConfirmData(null) + }, + confirmHandler: () => { + onTerminateWorkflow(job) + setConfirmData(null) + } + }) + }, + [onTerminateWorkflow, setConfirmData] + ) + const handleRerun = useCallback( workflow => { dispatch(rerunWorkflow({ project: workflow.project, workflowId: workflow.id })) @@ -416,7 +460,7 @@ const WorkflowsTable = React.forwardRef( setNotification({ status: 200, id: Math.random(), - message: 'Workflow ran successfully.' + message: 'Workflow run successfully.' }) ) }) @@ -439,6 +483,8 @@ const WorkflowsTable = React.forwardRef( appStore.frontendSpec.abortable_function_kinds, handleConfirmAbortJob, handleConfirmDeleteJob, + handleConfirmTerminateWorkflow, + accessibleProjectsMap, toggleConvertedYaml, handleRerun, rerunIsDisabled @@ -450,6 +496,8 @@ const WorkflowsTable = React.forwardRef( handleMonitoring, handleConfirmAbortJob, handleConfirmDeleteJob, + handleConfirmTerminateWorkflow, + accessibleProjectsMap, toggleConvertedYaml, handleRerun, rerunIsDisabled @@ -710,7 +758,7 @@ const WorkflowsTable = React.forwardRef( return ( <> - {workflowsStore.workflows.loading && } + {(workflowsStore.workflows.loading || permissionsLoading) && } {workflowsStore.workflows.loading ? null : (!workflowsStore.workflows.loading && !params.workflowId && workflowsStore.workflows.data.length === 0) || @@ -732,6 +780,7 @@ const WorkflowsTable = React.forwardRef( actionsMenu={actionsMenu} backLink={backLink} handleCancel={handleCancel} + handleConfirmTerminateWorkflow={handleConfirmTerminateWorkflow} itemIsSelected={itemIsSelected} pageData={pageData} selectedFunction={selectedFunction} diff --git a/src/reducers/projectReducer.js b/src/reducers/projectReducer.js index bce1e7b2c9..5aa109650f 100644 --- a/src/reducers/projectReducer.js +++ b/src/reducers/projectReducer.js @@ -50,6 +50,7 @@ const initialState = { isUnhealthy: false, retrying: false }, + accessibleProjectsMap: {}, project: { data: null, error: null, @@ -377,6 +378,12 @@ const projectStoreSlice = createSlice({ }, setProjectTotalAlerts(state, action) { state.projectTotalAlerts = { ...action.payload } + }, + setAccessibleProjectsMap(state, action) { + state.accessibleProjectsMap = { + ...state.accessibleProjectsMap, + ...action.payload + } } }, extraReducers: builder => { @@ -579,7 +586,8 @@ export const { setMlrunIsUnhealthy, setMlrunUnhealthyRetrying, setJobsMonitoringData, - setProjectTotalAlerts + setProjectTotalAlerts, + setAccessibleProjectsMap } = projectStoreSlice.actions export default projectStoreSlice.reducer diff --git a/src/scss/main.scss b/src/scss/main.scss index 10a31f8eac..d851e8c047 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -251,7 +251,7 @@ body { padding: 15px 24px 10px; background-color: colors.$white; - @include mixins.jobsFlex; + //@include mixins.jobsFlex; @media screen and (min-width: 1300px) { padding: 15px 64px 15px; From a25860ea2a48601910febf0c4e996d27fac4d67b Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:04:38 +0300 Subject: [PATCH 011/228] Impl [Monitoring application] small UI changes (#3286) --- .../MonitoringApplication.jsx | 3 ++- .../MonitoringApplication.util.jsx | 20 +++++++++++-------- .../monitoringApplicationCounters.util.jsx | 3 +-- src/elements/SectionTable/SectionTable.jsx | 8 ++++++-- src/reducers/monitoringApplicationsReducer.js | 2 +- src/utils/createApplicationContent.jsx | 10 ++-------- src/utils/createArtifactsContent.jsx | 2 +- 7 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx index 2dfa54aa50..5576c4c66e 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx @@ -194,6 +194,7 @@ const MonitoringApplication = () => {
      Results +
      {resultsTable.body.length === 0 ? ( @@ -204,7 +205,7 @@ const MonitoringApplication = () => {
      Metrics - +
      {metricsTable.body.length === 0 ? ( diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx index 06aed80dd0..a280025c41 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx @@ -23,6 +23,7 @@ import { capitalize, isNumber } from 'lodash' import { parseChipsData } from '../../../../utils/convertChipsData' import { formatDatetime } from '../../../../utils' import { METRIC_TYPE, RESULT_TYPE } from '../../../../constants' +import { getDriftStatusData } from '../../../../utils/createArtifactsContent' export const generateArtifactsTableContent = (artifacts = []) => { const tableHeaders = [ @@ -30,8 +31,8 @@ export const generateArtifactsTableContent = (artifacts = []) => { value: 'Name', className: 'table-cell_big' }, - { value: 'Type', className: 'table-cell_medium' }, - { value: 'Labels', className: 'table-cell_medium' }, + { value: 'Type', className: 'table-cell_small' }, + { value: 'Labels', className: 'table-cell_big' }, { value: 'Producer', className: 'table-cell_small' }, { value: 'Owner', className: 'table-cell_small' }, { value: 'Updated', className: 'table-cell_medium' }, @@ -46,11 +47,11 @@ export const generateArtifactsTableContent = (artifacts = []) => { }, artifactType: { value: artifact.kind || 'artifact', - className: 'table-cell_medium' + className: 'table-cell_small' }, labels: { value: parseChipsData(artifact.labels), - className: 'table-cell_medium' + className: 'table-cell_big' }, producer: { value: artifact.producer.name, @@ -84,7 +85,7 @@ export const generateResultsTableContent = (metrics = []) => { className: 'table-cell_medium' }, { value: 'Kind', className: 'table-cell_medium' }, - { value: 'Value (latest result)', className: 'table-cell_medium' }, + { value: 'Value (latest)', className: 'table-cell_medium' }, { value: 'Time (latest result)', className: 'table-cell_medium' }, { value: 'Status', className: 'table-cell_small' } ] @@ -92,6 +93,8 @@ export const generateResultsTableContent = (metrics = []) => { const tableBody = metrics .filter(metric => metric.type === RESULT_TYPE) .map(result => { + const driftStatusData = getDriftStatusData(result.status) + return { name: { value: capitalize(result.name), @@ -110,8 +113,9 @@ export const generateResultsTableContent = (metrics = []) => { className: 'table-cell_medium' }, status: { - value: result.status, - className: 'table-cell_small' + value: driftStatusData.value, + className: 'table-cell_small', + tooltip: driftStatusData.tooltip } } }) @@ -128,7 +132,7 @@ export const generateMetricsTableContent = (metrics = []) => { value: 'Name', className: 'table-cell_medium' }, - { value: 'Value (latest result)', className: 'table-cell_medium' }, + { value: 'Value (latest)', className: 'table-cell_medium' }, { value: 'Time (latest result)', className: 'table-cell_medium' } ] diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index a3ed39f4f0..bb7df14f95 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -78,7 +78,7 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => }, { id: 'runningFrequency', - title: 'Running frequency', + title: 'Running interval', counterData: [ { title: `Every ${formatMinutesToString(monitoringApplications.applications?.[0]?.base_period)}` @@ -91,7 +91,6 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => { id: 'appStatus', title: 'App Status', - tip: 'Some tip', counterData: [ { id: 'appStatus', diff --git a/src/elements/SectionTable/SectionTable.jsx b/src/elements/SectionTable/SectionTable.jsx index c990de8e30..61287154c3 100644 --- a/src/elements/SectionTable/SectionTable.jsx +++ b/src/elements/SectionTable/SectionTable.jsx @@ -113,14 +113,18 @@ const SectionTable = ({ params, table }) => { ) }) ) : ( - }> + }> {body[key].value} )} ) : ( <> - }> + + } + > {body[key].value} {body[key].status && ( diff --git a/src/reducers/monitoringApplicationsReducer.js b/src/reducers/monitoringApplicationsReducer.js index 820cf8e91e..7d99044189 100644 --- a/src/reducers/monitoringApplicationsReducer.js +++ b/src/reducers/monitoringApplicationsReducer.js @@ -63,7 +63,7 @@ const initialState = { time: '2025-05-07T09:07:14+00:00', name: 'some_result', kind: 'data-drift', - status: 'Detection', + status: '2', value: 0.95 }, { diff --git a/src/utils/createApplicationContent.jsx b/src/utils/createApplicationContent.jsx index ce145446f0..6530e3f71d 100644 --- a/src/utils/createApplicationContent.jsx +++ b/src/utils/createApplicationContent.jsx @@ -72,7 +72,7 @@ export const createApplicationContent = application => { headerId: 'possibleDetections', headerLabel: 'Possible detections', value: application.stats.potential_detections, - className: 'table-cell-1' + className: 'table-cell-2' }, { id: `class.${identifierUnique}`, @@ -81,13 +81,7 @@ export const createApplicationContent = application => { value: application.application_class, className: 'table-cell-2' }, - { - id: `startedAt.${identifierUnique}`, - headerId: 'startedAt', - headerLabel: 'Started at', - value: formatDatetime(application.started_at, 'N/A'), - className: 'table-cell-2' - }, + { id: `updated.${identifierUnique}`, headerId: 'updated', diff --git a/src/utils/createArtifactsContent.jsx b/src/utils/createArtifactsContent.jsx index 96c76bd266..5b2251cc94 100644 --- a/src/utils/createArtifactsContent.jsx +++ b/src/utils/createArtifactsContent.jsx @@ -391,7 +391,7 @@ export const createDocumentsRowData = (artifact, project, isAllVersions) => { } } -const getDriftStatusData = driftStatus => { +export const getDriftStatusData = driftStatus => { switch (String(driftStatus)) { case '0': case 'NO_DRIFT': From be3e9e0cddd602822de823748a8c6f18321b5dd7 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Tue, 17 Jun 2025 17:38:04 +0300 Subject: [PATCH 012/228] Impl [UI] Move Table components to DRC (#3284) --- src/App.jsx | 2 +- src/common/ActionsMenu/ActionsMenu.jsx | 191 ----- src/common/ActionsMenu/actionsMenu.scss | 60 -- src/common/BlockerSpy/BlockerSpy.jsx | 39 -- src/common/Chip/Chip.jsx | 201 ------ src/common/Chip/Chip.stories.js | 288 -------- src/common/Chip/chip.scss | 80 --- src/common/ChipCell/ChipCell.jsx | 244 ------- src/common/ChipCell/ChipCellView.jsx | 148 ---- .../ChipCell/ChipTooltip/ChipTooltip.jsx | 61 -- .../HiddenChipsBlock/HiddenChipsBlock.jsx | 106 --- src/common/ChipCell/SizeChips.js | 34 - src/common/ChipCell/chipCell.scss | 53 -- src/common/ChipForm/ChipForm.jsx | 290 -------- src/common/ChipForm/chipForm.scss | 66 -- src/common/ChipInput/ChipInput.jsx | 7 +- .../CopyToClipboard/CopyToClipboard.jsx | 85 --- src/common/DatePicker/DatePickerView.jsx | 10 +- src/common/ErrorMessage/ErrorMessage.jsx | 55 -- src/common/ErrorMessage/ErrorMessage.test.js | 61 -- src/common/ErrorMessage/errorMessage.scss | 30 - src/common/Input/Input.jsx | 2 +- src/common/LoadButton/LoadButton.jsx | 48 -- src/common/LoadButton/LoadButton.stories.js | 56 -- src/common/LoadButton/loadButton.scss | 80 --- src/common/Loader/Loader.jsx | 47 -- .../Loader/LoaderForSuspenseFallback.jsx | 38 - src/common/Loader/loader.scss | 59 -- src/common/MlChart/MlChart.jsx | 3 +- src/common/Notifications/Notification.jsx | 2 +- .../ProjectDetailsHeader.jsx | 2 +- src/common/RangeInput/RangeInput.jsx | 2 +- src/common/Search/Search.jsx | 2 +- src/common/Select/Select.jsx | 3 +- src/common/TabsSlider/TabsSlider.jsx | 239 ------- src/common/TargetPath/targetPath.util.js | 2 +- src/common/TimePicker/TimePicker.jsx | 2 +- src/components/ActionBar/ActionBar.jsx | 2 +- .../AddToFeatureVectorPage.jsx | 4 +- .../AddToFeatureVectorView.jsx | 4 +- src/components/Alerts/Alerts.jsx | 2 +- src/components/Alerts/alerts.util.js | 2 +- .../ApplicationMetrics/ApplicationMetrics.jsx | 4 +- .../ArtifactInfoSources.jsx | 3 +- src/components/Artifacts/Artifacts.jsx | 31 +- src/components/Artifacts/ArtifactsTable.jsx | 7 +- src/components/Artifacts/ArtifactsView.jsx | 2 +- .../ArtifactsPreview/ArtifactsPreview.jsx | 2 +- .../ConsumerGroup/ConsumerGroup.jsx | 9 +- .../ConsumerGroups/ConsumerGroups.jsx | 2 +- .../ConsumerGroupsWrapper.jsx | 4 +- src/components/Datasets/datasets.util.jsx | 8 +- src/components/Details/Details.jsx | 337 +++------ .../Details/DetailsHeader/DetailsHeader.jsx | 460 ++++++------ .../DetailsPromptTemplate.jsx | 4 +- .../DetailsPromptTemplate/PromptTab.jsx | 2 +- .../DetailsTabsContent/DetailsTabsContent.jsx | 18 +- src/components/Details/details.scss | 376 ---------- src/components/Details/details.util.js | 17 +- .../DetailsArtifacts/DetailsArtifacts.jsx | 7 +- .../detailsArtifacts.util.jsx | 6 +- .../detailsDriftAnalysis.util.js | 2 +- .../DetailsDrillDownAlert.jsx | 6 +- .../detailsFeaturesAnalysis.util.jsx | 2 +- src/components/DetailsInfo/DetailsInfo.jsx | 12 +- .../DetailsInfo/DetailsInfoView.jsx | 14 +- .../DetailsInfo/detailsInfo.util.jsx | 7 +- .../DetailsInputs/DetailsInputs.jsx | 3 +- .../DetailsInputs/detailsInputs.util.jsx | 3 +- src/components/DetailsLogs/Logs.jsx | 3 +- .../DetailsMetadata/DetailsMetadata.jsx | 3 +- src/components/DetailsPods/DetailsPods.jsx | 3 +- .../DetailsRequestedFeatures.jsx | 6 +- .../DetailsResults/DetailsResults.jsx | 2 +- .../detailsStatistics.util.jsx | 2 +- .../ConfigSource/ConfigSource.jsx | 3 +- src/components/Documents/documents.util.jsx | 15 +- .../FeatureSetsPanel/FeatureSetsPanel.jsx | 2 +- .../FeatureSetsPanelTableRow.jsx | 5 +- .../FeatureSetsPanelTargetStoreView.jsx | 9 +- .../FeatureSetsPanelTitleView.jsx | 2 +- .../FeatureSetsPanel/FeatureSetsPanelView.jsx | 3 +- .../ScheduleFeatureSet/ScheduleFeatureSet.jsx | 6 +- .../ScheduleFeatureSetView.jsx | 3 +- .../FeatureSetsPanel/UrlPath.utils.js | 2 +- .../FeatureStore/FeatureSets/FeatureSets.jsx | 4 +- .../FeatureSets/FeatureSetsView.jsx | 4 +- .../FeatureSets/featureSets.util.jsx | 2 +- src/components/FeatureStore/FeatureStore.jsx | 3 +- .../FeatureVectors/FeatureVectors.jsx | 6 +- .../FeatureVectors/FeatureVectorsView.jsx | 2 +- .../FeatureStore/Features/FeaturesView.jsx | 10 +- .../FeatureStore/featureStore.util.js | 4 +- src/components/Files/files.util.jsx | 11 +- src/components/FilterMenu/FilterMenu.jsx | 4 +- src/components/FunctionsPage/Functions.jsx | 6 +- .../FunctionsPage/FunctionsView.jsx | 5 +- .../FunctionsPage/functions.util.jsx | 4 +- .../FunctionsPageOld/FunctionsOld.jsx | 4 +- .../FunctionsPageOld/FunctionsViewOld.jsx | 6 +- .../FunctionsPageOld/functionsOld.util.jsx | 4 +- .../FunctionsPanel/FunctionsPanelView.jsx | 4 +- src/components/JobWizard/JobWizard.jsx | 7 +- src/components/JobWizard/JobWizard.util.js | 2 +- .../JobWizardRunDetails.jsx | 2 +- src/components/Jobs/Jobs.jsx | 3 +- src/components/Jobs/jobs.util.js | 9 +- src/components/LLMPrompts/llmPrompts.util.jsx | 11 +- .../ModelEndpoints/ModelEndpoints.jsx | 2 +- .../ModelEndpoints/modelEndpoints.util.jsx | 4 +- .../ModelsPage/Models/models.util.jsx | 13 +- src/components/ModelsPage/ModelsPage.jsx | 2 +- .../RealTimePipelines/RealTimePipelines.jsx | 2 +- .../realTimePipelines.util.js | 2 +- .../MEPsWithDetections.jsx | 2 +- .../MonitoringApplication.jsx | 9 +- .../MonitoringApplication.util.jsx | 4 +- .../MonitoringApplicationCard.jsx | 3 +- .../MonitoringApplications.jsx | 10 +- .../monitoringApplications.util.js | 3 +- .../MonitoringApplicationsPage.jsx | 21 +- src/components/Pipeline/Pipeline.jsx | 3 +- src/components/Project/ProjectMonitor.jsx | 4 +- src/components/Project/ProjectMonitorView.jsx | 3 +- .../ProjectOverview/ProjectOverview.jsx | 3 +- src/components/Project/project.utils.jsx | 2 +- .../ProjectSettings/ProjectSettings.jsx | 12 +- .../ProjectsJobsMonitoring.jsx | 3 +- .../CreateProjectDialog.jsx | 19 +- src/components/ProjectsPage/Projects.jsx | 4 +- src/components/ProjectsPage/ProjectsView.jsx | 3 +- src/components/ProjectsPage/projects.util.jsx | 4 +- .../RegisterArtifactModal.jsx | 4 +- .../SheduleWizard/ScheduleWizard.jsx | 11 +- src/components/Table/Table.jsx | 131 ++-- src/components/Table/TableHead.jsx | 95 --- src/components/Table/TableView.jsx | 151 ---- src/components/Table/table.scss | 283 -------- .../JobsFunctionsTableRow.jsx | 4 +- src/components/Workflow/Workflow.jsx | 2 +- src/components/Workflow/workflow.util.js | 16 +- src/constants.js | 12 - .../ActionMenuItem/ActionsMenuItem.jsx | 83 --- .../ActionMenuItem/actionsMenuItem.scss | 66 -- .../AddArtifactTagPopUp.jsx | 7 +- src/elements/AlertsTable/AlertsTable.jsx | 2 +- .../AlertsTableRow/AlertsTableRow.jsx | 6 +- .../ApplicationTableRow.jsx | 13 +- .../ArtifactsTableRow/ArtifactsTableRow.jsx | 7 +- .../ChangeOwnerPopUp/ChangeOwnerPopUp.jsx | 6 +- .../ConsumerGroupShardLagTableRow.jsx | 6 +- .../ConsumerGroupTableRow.jsx | 7 +- .../CreateFeatureVectorPopUp.jsx | 2 +- .../CreateJobCardTemplate.jsx | 2 +- .../DeployModelPopUp/DeployModelPopUp.jsx | 4 +- .../DetailsInfoItem/DetailsInfoItem.jsx | 24 +- .../DetailsInfoItemChip.jsx | 18 +- .../ArtifactPopUp/ArtifactPopUp.jsx | 2 +- src/elements/DetailsPopUp/DetailsPopUp.jsx | 3 +- .../FeatureSetPopUp/FeatureSetPopUp.jsx | 2 +- .../FeatureVectorPopUp/FeatureVectorPopUp.jsx | 2 +- .../FunctionPopUp/FunctionPopUp.jsx | 2 +- .../DetailsPopUp/JobPopUp/JobPopUp.jsx | 2 +- .../EnvironmentVariablesView.jsx | 3 +- .../FeatureStoreTableRow.jsx | 13 +- .../FeaturesTablePanel/FeaturesTablePanel.jsx | 4 +- .../FunctionCardTemplate.jsx | 2 +- .../FunctionPanelTopologyModelTableView.jsx | 3 +- .../FunctionsPanelCode/FunctionsPanelCode.jsx | 2 +- .../FunctionsPanelCodeView.jsx | 2 +- .../FunctionsPanelGeneralView.jsx | 2 +- .../FunctionsPanelParametersView.jsx | 3 +- .../FunctionsTableRow/FunctionsTableRow.jsx | 7 +- .../FunctionsTableRowOld.jsx | 11 +- .../JobsMonitoringStatsCard.jsx | 3 +- src/elements/JobsTable/JobsTable.jsx | 4 +- src/elements/JobsTableRow/JobsTableRow.jsx | 7 +- src/elements/MembersPopUp/MembersPopUp.jsx | 2 +- .../PartitionFields/PartitionFields.jsx | 2 +- src/elements/PreviewModal/PreviewModal.jsx | 2 +- src/elements/ProjectCard/ProjectCardView.jsx | 6 +- .../ProjectDataCard/ProjectDataCard.jsx | 3 +- .../ProjectFunctions/ProjectFunctions.jsx | 2 + src/elements/ProjectJobs/projectJobs.utils.js | 8 +- .../ProjectSettingsGeneral.jsx | 10 +- .../ProjectSettingsMembers.jsx | 2 +- .../ProjectSettingsSecrets.jsx | 5 +- .../ProjectStatisticsCounter.jsx | 3 +- .../ProjectSummaryCard/ProjectSummaryCard.jsx | 3 +- .../ProjectTable/ProjectTable.jsx} | 0 .../AlertsCounters.jsx | 2 +- .../JobsCounters.jsx | 3 +- .../ScheduledJobsCounters.jsx | 2 +- .../WorkflowsCounters.jsx | 3 +- src/elements/ReadOnlyChips/ReadOnlyChips.jsx | 6 +- .../RealTimePipelinesTableRow.jsx | 7 +- .../RegisterArtifactModalForm.jsx | 2 +- .../RegisterModelModal/RegisterModelModal.jsx | 6 +- .../ScheduledJobsTable/ScheduledJobsTable.jsx | 6 +- src/elements/SectionTable/SectionTable.jsx | 4 +- src/elements/TableCell/TableCell.jsx | 226 ------ src/elements/TableLinkCell/TableLinkCell.jsx | 151 ---- src/elements/TableLinkCell/tableLinkCell.scss | 66 -- src/elements/TableTypeCell/TableTypeCell.jsx | 96 --- .../VolumesTable/VolumesTableView.jsx | 5 +- .../WorkflowsTable/WorkflowsTable.jsx | 6 +- src/hooks/useDetailsHeader.hook.jsx | 272 ++++++++ src/hooks/useJobsPageData.js | 2 +- src/hooks/useVirtualization.hook.js | 2 +- src/layout/Page/Page.jsx | 2 +- src/reducers/detailsReducer.js | 55 +- src/reducers/featureStoreReducer.js | 2 +- src/reducers/functionReducer.js | 2 +- src/reducers/jobReducer.js | 2 +- src/reducers/notificationReducer.js | 46 -- src/reducers/projectReducer.js | 2 +- src/scss/main.scss | 653 ------------------ src/store/toolkitStore.js | 5 +- src/types.js | 76 -- src/utils/artifacts.util.js | 10 +- src/utils/copyToClipboard.js | 4 +- src/utils/createAlertsContent.jsx | 2 +- src/utils/createApplicationContent.jsx | 2 +- src/utils/createArtifactsContent.jsx | 24 +- src/utils/createFeatureStoreContent.jsx | 14 +- src/utils/createFunctionsRowData.js | 8 +- src/utils/createJobsContent.js | 28 +- src/utils/createRealTimePipelinesContent.js | 6 +- src/utils/cutChips.js | 38 - src/utils/datetime.js | 93 --- src/utils/filter.util.js | 56 -- src/utils/getArtifactPreview.jsx | 3 +- src/utils/getChipLabelAndValue.js | 30 - src/utils/getChipOptions.js | 68 -- src/utils/getFunctionLogs.js | 2 +- src/utils/getUniqueIdentifier.js | 17 +- src/utils/handleDeleteArtifact.js | 4 +- src/utils/helper.js | 5 - src/utils/index.js | 2 - src/utils/{jobs.util.js => jobs.util.jsx} | 49 +- src/utils/largeResponseCatchHandler.js | 2 +- src/utils/link-helper.util.js | 19 +- src/utils/notifications.util.js | 46 -- src/utils/object.js | 2 +- src/utils/roundFloats.js | 31 - src/utils/tableRows.util.js | 2 +- 246 files changed, 1171 insertions(+), 6580 deletions(-) delete mode 100644 src/common/ActionsMenu/ActionsMenu.jsx delete mode 100644 src/common/ActionsMenu/actionsMenu.scss delete mode 100644 src/common/BlockerSpy/BlockerSpy.jsx delete mode 100644 src/common/Chip/Chip.jsx delete mode 100644 src/common/Chip/Chip.stories.js delete mode 100644 src/common/Chip/chip.scss delete mode 100644 src/common/ChipCell/ChipCell.jsx delete mode 100644 src/common/ChipCell/ChipCellView.jsx delete mode 100644 src/common/ChipCell/ChipTooltip/ChipTooltip.jsx delete mode 100644 src/common/ChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx delete mode 100644 src/common/ChipCell/SizeChips.js delete mode 100644 src/common/ChipCell/chipCell.scss delete mode 100644 src/common/ChipForm/ChipForm.jsx delete mode 100644 src/common/ChipForm/chipForm.scss delete mode 100644 src/common/CopyToClipboard/CopyToClipboard.jsx delete mode 100644 src/common/ErrorMessage/ErrorMessage.jsx delete mode 100644 src/common/ErrorMessage/ErrorMessage.test.js delete mode 100644 src/common/ErrorMessage/errorMessage.scss delete mode 100644 src/common/LoadButton/LoadButton.jsx delete mode 100644 src/common/LoadButton/LoadButton.stories.js delete mode 100644 src/common/LoadButton/loadButton.scss delete mode 100644 src/common/Loader/Loader.jsx delete mode 100644 src/common/Loader/LoaderForSuspenseFallback.jsx delete mode 100644 src/common/Loader/loader.scss delete mode 100644 src/common/TabsSlider/TabsSlider.jsx delete mode 100644 src/components/Details/details.scss delete mode 100644 src/components/Table/TableHead.jsx delete mode 100644 src/components/Table/TableView.jsx delete mode 100644 src/components/Table/table.scss delete mode 100644 src/elements/ActionMenuItem/ActionsMenuItem.jsx delete mode 100644 src/elements/ActionMenuItem/actionsMenuItem.scss rename src/{common/TabsSlider/tabsSlider.scss => elements/ProjectTable/ProjectTable.jsx} (100%) delete mode 100644 src/elements/TableCell/TableCell.jsx delete mode 100644 src/elements/TableLinkCell/TableLinkCell.jsx delete mode 100644 src/elements/TableLinkCell/tableLinkCell.scss delete mode 100644 src/elements/TableTypeCell/TableTypeCell.jsx create mode 100644 src/hooks/useDetailsHeader.hook.jsx delete mode 100644 src/reducers/notificationReducer.js delete mode 100644 src/utils/cutChips.js delete mode 100755 src/utils/datetime.js delete mode 100644 src/utils/filter.util.js delete mode 100644 src/utils/getChipLabelAndValue.js delete mode 100644 src/utils/getChipOptions.js rename src/utils/{jobs.util.js => jobs.util.jsx} (80%) delete mode 100644 src/utils/notifications.util.js delete mode 100644 src/utils/roundFloats.js diff --git a/src/App.jsx b/src/App.jsx index 555d462e92..25858deefa 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -33,8 +33,8 @@ import 'prismjs/components/prism-yaml.min.js' import 'prismjs/components/prism-json.min.js' import 'prismjs/components/prism-python.min.js' +import { LoaderForSuspenseFallback } from 'igz-controls/components' import Header from './layout/Header/Header' -import LoaderForSuspenseFallback from './common/Loader/LoaderForSuspenseFallback' import Notifications from './common/Notifications/Notifications' import localStorageService from './utils/localStorageService' diff --git a/src/common/ActionsMenu/ActionsMenu.jsx b/src/common/ActionsMenu/ActionsMenu.jsx deleted file mode 100644 index 320ae74d35..0000000000 --- a/src/common/ActionsMenu/ActionsMenu.jsx +++ /dev/null @@ -1,191 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useCallback, useEffect, useRef, useState } from 'react' -import PropTypes from 'prop-types' -import { isEmpty } from 'lodash' -import classnames from 'classnames' - -import ActionsMenuItem from '../../elements/ActionMenuItem/ActionsMenuItem' -import { PopUpDialog, RoundedIcon } from 'igz-controls/components' - -import { ACTIONS_MENU } from '../../types' - -import ActionMenuIcon from 'igz-controls/images/elipsis.svg?react' - -import './actionsMenu.scss' - -const ActionsMenu = ({ - dataItem = {}, - menu, - menuPosition = '', - time = 100, - withQuickActions = false -}) => { - const [actionMenu, setActionMenu] = useState(menu) - const [isIconDisplayed, setIsIconDisplayed] = useState(false) - const [isShowMenu, setIsShowMenu] = useState(false) - const actionMenuRef = useRef() - const actionMenuBtnRef = useRef() - const dropDownMenuRef = useRef() - const mainActionsWrapperRef = useRef() - - let idTimeout = null - - const actionMenuClassNames = classnames( - 'actions-menu__container', - withQuickActions && 'actions-menu__container_extended', - isShowMenu && 'actions-menu__container-active' - ) - - const clickHandler = useCallback( - event => { - if (!event.target.closest('.actions-menu-button')) { - setIsShowMenu(false) - } - }, - [setIsShowMenu] - ) - - const scrollHandler = useCallback( - event => { - if (!event.target.closest('.actions-menu__body')) { - setIsShowMenu(false) - } - }, - [setIsShowMenu] - ) - - const onMouseOut = () => { - if (isShowMenu) { - idTimeout = setTimeout(() => { - setIsShowMenu(false) - }, time) - } - } - - const handleMouseOver = event => { - if (mainActionsWrapperRef.current?.contains(event.target)) { - setIsShowMenu(false) - } - - if (idTimeout) clearTimeout(idTimeout) - } - - useEffect(() => { - if (!isEmpty(dataItem)) { - setActionMenu(typeof menu === 'function' ? menu(dataItem, menuPosition) : menu) - } - }, [dataItem, menu, menuPosition]) - - useEffect(() => { - setIsIconDisplayed(actionMenu[0]?.some(menuItem => menuItem.icon)) - }, [actionMenu]) - - useEffect(() => { - window.addEventListener('click', clickHandler) - window.addEventListener('scroll', scrollHandler, true) - - return () => { - window.removeEventListener('click', clickHandler) - window.removeEventListener('scroll', scrollHandler, true) - } - }, [clickHandler, scrollHandler]) - - return ( -
      - {withQuickActions && ( -
      - {actionMenu[1].map( - mainAction => - !mainAction.hidden && ( - mainAction.onClick(dataItem)} - tooltipText={mainAction.label} - key={mainAction.label} - > - {mainAction.icon} - - ) - )} -
      - )} - {actionMenu[0].length > 0 && ( -
      - { - setIsShowMenu(prevValue => !prevValue) - }} - ref={actionMenuBtnRef} - tooltipText="More actions" - > - - - {isShowMenu && ( - -
        - {actionMenu[0].map( - (menuItem, idx) => - !menuItem.hidden && ( - - ) - )} -
      -
      - )} -
      - )} -
      - ) -} - -ActionsMenu.propTypes = { - dataItem: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - menu: ACTIONS_MENU.isRequired, - menuPosition: PropTypes.string, - time: PropTypes.number, - withQuickActions: PropTypes.bool -} - -export default ActionsMenu diff --git a/src/common/ActionsMenu/actionsMenu.scss b/src/common/ActionsMenu/actionsMenu.scss deleted file mode 100644 index 067f576d6b..0000000000 --- a/src/common/ActionsMenu/actionsMenu.scss +++ /dev/null @@ -1,60 +0,0 @@ -@use 'igz-controls/scss/colors'; - -.actions-menu { - position: relative; - - &__container { - position: relative; - display: none; - - &_extended { - position: absolute; - right: 0; - display: none; - align-items: center; - justify-content: center; - background-color: colors.$ghostWhite; - height: 100%; - - &:before { - content: ''; - width: 30px; - height: 100%; - position: absolute; - display: block; - left: -30px; - background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(245, 247, 255, 1) 100%); - } - - .actions-menu { - padding: 0 5px 0 0; - } - } - - &-active { - display: flex; - } - } - - &__main-actions-wrapper { - display: flex; - align-items: center; - justify-content: center; - } - - &__body { - min-width: 150px; - max-width: 250px; - - .pop-up-dialog { - width: 100%; - padding: 0; - } - } - - &__list { - list-style-type: none; - margin: 0; - padding: 0; - } -} diff --git a/src/common/BlockerSpy/BlockerSpy.jsx b/src/common/BlockerSpy/BlockerSpy.jsx deleted file mode 100644 index db1028d710..0000000000 --- a/src/common/BlockerSpy/BlockerSpy.jsx +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useEffect } from 'react' -import PropTypes from 'prop-types' -import { useBlocker } from 'react-router-dom' - -const BlockerSpy = ({ setBlocker, shouldBlock }) => { - const blocker = useBlocker(shouldBlock) - - useEffect(() => { - setBlocker(blocker) - }, [setBlocker, blocker]) - - return <> -} - -BlockerSpy.propTypes = { - setBlocker: PropTypes.func.isRequired, - shouldBlock: PropTypes.func.isRequired -} - -export default BlockerSpy diff --git a/src/common/Chip/Chip.jsx b/src/common/Chip/Chip.jsx deleted file mode 100644 index d8a62dd96a..0000000000 --- a/src/common/Chip/Chip.jsx +++ /dev/null @@ -1,201 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useCallback, useEffect, useLayoutEffect, useState } from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import { useSelector } from 'react-redux' -import { isEmpty } from 'lodash' - -import ChipForm from '../ChipForm/ChipForm' - -import Close from 'igz-controls/images/close.svg?react' - -import { getChipLabelAndValue } from '../../utils/getChipLabelAndValue' -import { CHIP, CHIP_OPTIONS } from '../../types' - -import './chip.scss' - -const Chip = React.forwardRef( - ( - { - chip, - chipIndex = null, - chipOptions, - className, - editConfig = {}, - handleEditChip = () => {}, - handleIsEdit = () => {}, - handleRemoveChip = () => {}, - hiddenChips = false, - isDeleteMode = false, - isEditMode = false, - onClick = null, - setChipsSizes = () => {}, - setEditConfig = () => {}, - setValidation = null, - shortChip = false, - showChips, - textOverflowEllipsis = false - }, - { chipsCellRef, hiddenChipsCounterRef } - ) => { - const [validationRules, setValidationRules] = useState([]) - const frontendSpec = useSelector(store => store.appStore.frontendSpec) - const chipRef = React.useRef() - const { chipLabel, chipValue } = getChipLabelAndValue(chip) - const { background, boldValue, borderColor, density, font, borderRadius } = chipOptions - - const chipClassNames = classnames( - 'chip', - 'chip__content', - (textOverflowEllipsis || isEditMode) && 'data-ellipsis', - shortChip && 'chip_short', - hiddenChips && 'chip_hidden', - density && `chip-density_${density}`, - borderRadius && `chip-border_${borderRadius}`, - background && `chip-background_${background}`, - borderColor && `chip-border_${borderColor}`, - font && `chip-font_${font}`, - isEditMode && 'editable', - (showChips || isEditMode) && 'chip_visible', - className - ) - const chipLabelClassNames = classnames( - 'chip__label', - (textOverflowEllipsis || isEditMode) && 'data-ellipsis', - !isEmpty(validationRules) && 'chip__label_invalid' - ) - const chipValueClassNames = classnames( - 'chip__value', - (textOverflowEllipsis || isEditMode) && 'data-ellipsis', - boldValue && 'chip-value_bold' - ) - - const checkValidation = useCallback( - chipKey => { - if (frontendSpec.internal_labels.includes(chipKey)) { - setValidationRules([ - { name: 'internal label', label: 'System-defined labels cannot be modified.' } - ]) - - return setValidation && setValidation(false) - } - - setValidationRules([]) - setValidation && setValidation(true) - }, - [frontendSpec.internal_labels, setValidation] - ) - - useEffect(() => { - if (setValidation) { - checkValidation(chip.value.match(/^(?|.+?):\s?(?|.+?)$/)?.groups?.key) - } - }, [checkValidation, chip, setValidation]) - - useLayoutEffect(() => { - if (chipRef.current && setChipsSizes) { - const { marginLeft, marginRight } = getComputedStyle(chipRef.current) - - setChipsSizes(state => ({ - ...state, - [chipIndex]: - (chipRef.current?.getBoundingClientRect?.()?.width ?? 0) + - parseFloat(marginLeft) + - parseFloat(marginRight) - })) - } - }, [chipIndex, setChipsSizes]) - - if (!chip.value.match(/^\+ [\d]+/g)) { - return isEditMode && chipIndex === editConfig.chipIndex ? ( - |.+?):\s?(?|.+?)$/)?.groups} - validationRules={validationRules} - checkValidation={checkValidation} - /> - ) : ( -
      handleIsEdit(event, chipIndex)} - > - {chipLabel &&
      {chipLabel}
      } - {chipValue && ( - <> -
      {chip.delimiter ?? ':'}
      -
      {chipValue}
      - - )} - {(isEditMode || isDeleteMode) && ( - - )} -
      - ) - } - - return ( - - {chip.value} - - ) - } -) - -Chip.displayName = 'Chip' - -Chip.propTypes = { - chip: CHIP.isRequired, - chipIndex: PropTypes.number, - chipOptions: CHIP_OPTIONS.isRequired, - className: PropTypes.string, - editConfig: PropTypes.object, - handleEditChip: PropTypes.func, - handleIsEdit: PropTypes.func, - handleRemoveChip: PropTypes.func, - hiddenChips: PropTypes.bool, - isDeleteMode: PropTypes.bool, - isEditMode: PropTypes.bool, - onClick: PropTypes.func, - setChipsSizes: PropTypes.func, - setEditConfig: PropTypes.func, - setValidation: PropTypes.func, - shortChip: PropTypes.bool, - showChips: PropTypes.bool.isRequired, - textOverflowEllipsis: PropTypes.bool -} - -export default React.memo(Chip) diff --git a/src/common/Chip/Chip.stories.js b/src/common/Chip/Chip.stories.js deleted file mode 100644 index f28e0c1c38..0000000000 --- a/src/common/Chip/Chip.stories.js +++ /dev/null @@ -1,288 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' - -import Chip from './Chip' - -export default { - title: 'Example/Chip', - component: Chip -} - -const commonArgs = { - chip: { value: 'Key: Value' }, - chipOptions: { - background: 'purple', - boldValue: false, - borderRadius: 'primary', - borderColor: 'transparent', - density: 'dense', - font: 'purple' - } -} - -const Template = args => - -export const LabelChip = Template.bind({}) -LabelChip.args = { - ...commonArgs, - chipOptions: { - background: 'purple', - boldValue: false, - borderRadius: 'primary', - borderColor: 'transparent', - density: 'dense', - font: 'purple' - } -} - -export const MetricsChip = Template.bind({}) -MetricsChip.args = { - ...commonArgs, - chipOptions: { - background: 'grey', - boldValue: false, - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'primary' - } -} - -export const ParametersChip = Template.bind({}) -ParametersChip.args = { - ...commonArgs, - chipOptions: { - background: 'orange', - boldValue: false, - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'orange' - } -} - -export const GreenChip = Template.bind({}) -GreenChip.args = { - ...commonArgs, - chipOptions: { - background: 'green', - boldValue: false, - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'green' - } -} - -export const DensePurpleChip = Template.bind({}) -DensePurpleChip.args = { - ...commonArgs, - chipOptions: { - background: 'purple', - boldValue: true, - borderRadius: 'primary', - borderColor: 'purple', - density: 'dense', - font: 'purple' - } -} - -export const DenseGreyChip = Template.bind({}) -DenseGreyChip.args = { - ...commonArgs, - chipOptions: { - background: 'grey', - boldValue: true, - borderColor: 'grey', - borderRadius: 'primary', - density: 'dense', - font: 'primary' - } -} - -export const DenseOrangeChip = Template.bind({}) -DenseOrangeChip.args = { - ...commonArgs, - chipOptions: { - background: 'orange', - boldValue: true, - borderColor: 'orange', - borderRadius: 'primary', - density: 'dense', - font: 'orange' - } -} - -export const DenseGreenChip = Template.bind({}) -DenseGreenChip.args = { - ...commonArgs, - chipOptions: { - background: 'green', - boldValue: true, - borderColor: 'green', - borderRadius: 'primary', - density: 'dense', - font: 'green' - } -} - -export const DenseAmethystChip = Template.bind({}) -DenseAmethystChip.args = { - ...commonArgs, - chipOptions: { - background: 'amethyst', - boldValue: false, - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'white' - } -} - -export const DenseJavaChip = Template.bind({}) -DenseJavaChip.args = { - ...commonArgs, - chipOptions: { - background: 'java', - boldValue: false, - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'white' - } -} - -export const DenseSorbusChip = Template.bind({}) -DenseSorbusChip.args = { - ...commonArgs, - chipOptions: { - background: 'sorbus', - boldValue: false, - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'white' - } -} - -export const LabelChipNormal = Template.bind({}) -LabelChipNormal.args = { - ...commonArgs, - chipOptions: { - background: 'none', - boldValue: false, - borderRadius: 'secondary', - borderColor: 'purple', - density: 'normal', - font: 'purple' - } -} - -export const MetricsChipNormal = Template.bind({}) -MetricsChipNormal.args = { - ...commonArgs, - chipOptions: { - background: 'none', - boldValue: false, - borderColor: 'grey', - borderRadius: 'secondary', - density: 'normal', - font: 'primary' - } -} - -export const ParametersChipNormal = Template.bind({}) -ParametersChipNormal.args = { - ...commonArgs, - chipOptions: { - background: 'none', - boldValue: false, - borderColor: 'orange', - borderRadius: 'secondary', - density: 'normal', - font: 'orange' - } -} - -export const GreenChipNormal = Template.bind({}) -GreenChipNormal.args = { - ...commonArgs, - chipOptions: { - background: 'none', - boldValue: false, - borderColor: 'green', - borderRadius: 'secondary', - density: 'normal', - font: 'green' - } -} - -export const LabelChipMedium = Template.bind({}) -LabelChipMedium.args = { - ...commonArgs, - chipOptions: { - background: 'purple', - boldValue: true, - borderRadius: 'secondary', - borderColor: 'purple', - density: 'medium', - font: 'purple' - } -} - -export const MetricsChipMedium = Template.bind({}) -MetricsChipMedium.args = { - ...commonArgs, - chipOptions: { - background: 'grey', - boldValue: true, - borderColor: 'grey', - borderRadius: 'secondary', - density: 'medium', - font: 'primary' - } -} - -export const ParametersChipMedium = Template.bind({}) -ParametersChipMedium.args = { - ...commonArgs, - chipOptions: { - background: 'orange', - boldValue: true, - borderColor: 'orange', - borderRadius: 'secondary', - density: 'medium', - font: 'orange' - } -} - -export const GreenChipMedium = Template.bind({}) -GreenChipMedium.args = { - ...commonArgs, - chipOptions: { - background: 'green', - boldValue: true, - borderColor: 'green', - borderRadius: 'secondary', - density: 'medium', - font: 'green' - } -} diff --git a/src/common/Chip/chip.scss b/src/common/Chip/chip.scss deleted file mode 100644 index bd6ea09937..0000000000 --- a/src/common/Chip/chip.scss +++ /dev/null @@ -1,80 +0,0 @@ -@use 'igz-controls/scss/variables'; -@use 'igz-controls/scss/colors'; -@use 'igz-controls/scss/borders'; -@use 'igz-controls/scss/mixins'; - -.chip { - position: relative; - margin: 2px 8px 2px 0; - padding: 4px 8px; - font-size: 14px; - line-height: 16px; - visibility: hidden; - cursor: default; - - &_visible { - visibility: visible; - } - - &__content { - display: flex; - align-items: center; - } - - &__delimiter { - display: flex; - align-items: center; - margin: 0 4px; - } - - &__label { - &_invalid { - color: colors.$amaranth; - } - } - - &__value { - min-width: 10px; - } - - &.editable { - cursor: pointer; - } - - &.chips_button { - padding: 8px 7px; - } - - .item-icon-close { - display: flex; - align-items: center; - justify-content: center; - margin-left: 5px; - padding: 0; - - svg { - transform: scale(0.7); - } - } - - &-background { - @include mixins.chipBackground(false); - } - - &-border { - @include mixins.chipBorder(); - } - - &-density { - @include mixins.chipDensity(false, false); - } - - &-font { - @include mixins.chipsFont(Chip); - } - - &-value_bold { - font-weight: 700; - font-size: 15px; - } -} diff --git a/src/common/ChipCell/ChipCell.jsx b/src/common/ChipCell/ChipCell.jsx deleted file mode 100644 index 9c613c1ef4..0000000000 --- a/src/common/ChipCell/ChipCell.jsx +++ /dev/null @@ -1,244 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useState, useCallback, useMemo } from 'react' -import PropTypes from 'prop-types' - -import ChipCellView from './ChipCellView' - -import { CHIP_OPTIONS } from '../../types' -import { CLICK, TAB, TAB_SHIFT } from 'igz-controls/constants' -import { cutChips } from '../../utils/cutChips' -import { useChipCell } from 'igz-controls/hooks' - -const ChipCell = ({ - addChip = () => {}, - chipOptions = { - background: 'purple', - boldValue: false, - borderRadius: 'primary', - borderColor: 'transparent', - density: 'dense', - font: 'purple' - }, - className, - delimiter = null, - editChip = () => {}, - elements = [], - isEditMode = false, - onClick = () => {}, - removeChip = () => {}, - shortChips = false, - setValidation = null, - visibleChipsMaxLength = null -}) => { - const { - chipsCellRef, - chipsWrapperRef, - handleShowElements, - hiddenChipsCounterRef, - hiddenChipsPopUpRef, - setChipsSizes, - setShowHiddenChips, - showChips, - showHiddenChips, - visibleChipsCount - } = useChipCell(isEditMode, visibleChipsMaxLength) - const [editConfig, setEditConfig] = useState({ - chipIndex: null, - isEdit: false, - isKeyFocused: true, - isValueFocused: false, - isNewChip: false - }) - - let chips = useMemo(() => { - return (isEditMode && !visibleChipsMaxLength) || visibleChipsMaxLength === 'all' - ? { - visibleChips: elements.map(chip => ({ - value: chip, - delimiter - })) - } - : cutChips( - elements, - visibleChipsMaxLength ? visibleChipsMaxLength : visibleChipsCount, - delimiter - ) - }, [delimiter, elements, isEditMode, visibleChipsCount, visibleChipsMaxLength]) - - const handleAddNewChip = useCallback( - (event, chip) => { - event.preventDefault() - - if (!editConfig.isEdit && !editConfig.chipIndex) { - addChip(chip, elements) - } - - if (showHiddenChips) { - setShowHiddenChips(false) - } - - setEditConfig({ - chipIndex: elements.length, - isEdit: true, - isKeyFocused: true, - isValueFocused: false, - isNewChip: true - }) - }, - [ - editConfig.isEdit, - editConfig.chipIndex, - showHiddenChips, - elements, - addChip, - setShowHiddenChips - ] - ) - - const handleRemoveChip = useCallback( - (event, chipIndex) => { - event.stopPropagation() - - const newChips = elements.filter((value, index) => index !== chipIndex) - - removeChip(newChips) - }, - [elements, removeChip] - ) - - const handleEditChip = useCallback( - (event, chip, nameEvent) => { - event.preventDefault() - const isChipNotEmpty = !!(chip.key && chip.value && chip.key?.trim() && chip.value?.trim()) - - if (isChipNotEmpty) { - const newChips = [...elements] - newChips[editConfig.chipIndex] = `${chip.key}: ${chip.value}` - - editChip(newChips) - } - - if (nameEvent === CLICK) { - if (editConfig.isNewChip && !isChipNotEmpty) { - handleRemoveChip(event, editConfig.chipIndex) - } - - setEditConfig({ - chipIndex: null, - isEdit: false, - isKeyFocused: true, - isValueFocused: false, - isNewChip: false - }) - } else if (nameEvent === TAB) { - if (editConfig.isNewChip && !isChipNotEmpty) { - handleRemoveChip(event, editConfig.chipIndex) - } - - setEditConfig(prevState => { - const isNextChipIndexExists = prevState.chipIndex + 1 > elements.length - 1 - - return { - chipIndex: isNextChipIndexExists ? null : prevState.chipIndex + 1, - isEdit: !isNextChipIndexExists, - isKeyFocused: true, - isValueFocused: false, - isNewChip: false - } - }) - } else if (nameEvent === TAB_SHIFT) { - if (editConfig.isNewChip && !isChipNotEmpty) { - handleRemoveChip(event, editConfig.chipIndex) - } - - setEditConfig(prevState => { - const isPrevChipIndexExists = prevState.chipIndex - 1 < 0 - - return { - chipIndex: isPrevChipIndexExists ? null : prevState.chipIndex - 1, - isEdit: !isPrevChipIndexExists, - isKeyFocused: isPrevChipIndexExists, - isValueFocused: !isPrevChipIndexExists, - isNewChip: false - } - }) - } - }, - [elements, editConfig.chipIndex, editConfig.isNewChip, editChip, handleRemoveChip] - ) - - const handleIsEdit = useCallback( - (event, index) => { - if (isEditMode) { - event.stopPropagation() - - setEditConfig({ - chipIndex: index, - isEdit: true, - isKeyFocused: true, - isValueFocused: false - }) - } - - onClick && onClick() - }, - [isEditMode, onClick] - ) - - return ( - - ) -} - -ChipCell.propTypes = { - addChip: PropTypes.func, - chipOptions: CHIP_OPTIONS, - className: PropTypes.string, - delimiter: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), - editChip: PropTypes.func, - elements: PropTypes.arrayOf(PropTypes.string), - isEditMode: PropTypes.bool, - onClick: PropTypes.func, - removeChip: PropTypes.func, - setValidation: PropTypes.func, - shortChips: PropTypes.bool, - visibleChipsMaxLength: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) -} - -export default React.memo(ChipCell) diff --git a/src/common/ChipCell/ChipCellView.jsx b/src/common/ChipCell/ChipCellView.jsx deleted file mode 100644 index 0020e224d4..0000000000 --- a/src/common/ChipCell/ChipCellView.jsx +++ /dev/null @@ -1,148 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' - -import Chip from '../Chip/Chip' -import ChipTooltip from './ChipTooltip/ChipTooltip' -import HiddenChipsBlock from './HiddenChipsBlock/HiddenChipsBlock' - -import { CHIP_OPTIONS, CHIPS } from '../../types' -import { isEveryObjectValueEmpty } from '../../utils/isEveryObjectValueEmpty' - -import Add from 'igz-controls/images/add.svg?react' - -import './chipCell.scss' - -const ChipCellView = React.forwardRef( - ( - { - chips = {}, - chipOptions, - className = '', - editConfig = {}, - handleAddNewChip = () => {}, - handleEditChip, - handleIsEdit = () => {}, - handleRemoveChip, - handleShowElements = () => {}, - isEditMode = false, - setChipsSizes = () => {}, - setEditConfig = () => {}, - setValidation = null, - shortChips, - showChips = false, - showHiddenChips - }, - { chipsCellRef, chipsWrapperRef, hiddenChipsCounterRef, hiddenChipsPopUpRef } - ) => { - const buttonAddClassNames = classnames( - 'button-add', - className, - chipOptions.background && `button-add-background_${chipOptions.background}`, - chipOptions.borderColor && `button-add-border_${chipOptions.borderColor}`, - chipOptions.font && `button-add-font_${chipOptions.font}`, - chipOptions.density && `button-add-density_${chipOptions.density}` - ) - const wrapperClassNames = classnames('chips-wrapper', isEditMode && 'fixed-max-width') - - return ( - (isEditMode || !isEveryObjectValueEmpty(chips)) && ( -
      -
      - {chips.visibleChips.map((chip, index) => { - return ( -
      - - - - {chips.visibleChips.length - 1 === index && showHiddenChips && ( - - )} -
      - ) - })} - {isEditMode && ( - - )} -
      -
      - ) - ) - } -) - -ChipCellView.displayName = 'ChipCellView' - -ChipCellView.propTypes = { - chips: PropTypes.shape({ visibleChips: CHIPS, hiddenChips: CHIPS }), - chipOptions: CHIP_OPTIONS.isRequired, - className: PropTypes.string, - editConfig: PropTypes.object, - handleAddNewChip: PropTypes.func, - handleEditChip: PropTypes.func, - handleIsEdit: PropTypes.func, - handleRemoveChip: PropTypes.func, - handleShowElements: PropTypes.func, - isEditMode: PropTypes.bool, - setChipsSizes: PropTypes.func, - setEditConfig: PropTypes.func, - setValidation: PropTypes.func, - shortChips: PropTypes.bool, - showChips: PropTypes.bool.isRequired, - showHiddenChips: PropTypes.bool.isRequired -} - -export default ChipCellView diff --git a/src/common/ChipCell/ChipTooltip/ChipTooltip.jsx b/src/common/ChipCell/ChipTooltip/ChipTooltip.jsx deleted file mode 100644 index f9d87e4ced..0000000000 --- a/src/common/ChipCell/ChipTooltip/ChipTooltip.jsx +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useMemo } from 'react' -import PropTypes from 'prop-types' - -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' - -import { getChipLabelAndValue } from '../../../utils/getChipLabelAndValue' -import { CHIP } from '../../../types' - -const ChipTooltip = ({ children, chip, editConfig = {} }) => { - const { chipLabel, chipValue } = useMemo(() => getChipLabelAndValue(chip), [chip]) - - return ( - - ) -} - -ChipTooltip.propTypes = { - children: PropTypes.node.isRequired, - chip: CHIP, - editConfig: PropTypes.object -} - -export default ChipTooltip diff --git a/src/common/ChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx b/src/common/ChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx deleted file mode 100644 index c87864e150..0000000000 --- a/src/common/ChipCell/HiddenChipsBlock/HiddenChipsBlock.jsx +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useEffect } from 'react' -import PropTypes from 'prop-types' -import { createPortal } from 'react-dom' - -import Chip from '../../Chip/Chip' -import ChipTooltip from '../ChipTooltip/ChipTooltip' - -import { CHIP_OPTIONS, CHIPS } from '../../../types' -import { useHiddenChipsBlock } from 'igz-controls/hooks' - -const HiddenChipsBlock = React.forwardRef( - ( - { - chips = [], - chipIndex = 0, - chipOptions, - className, - editConfig = {}, - handleEditChip, - handleIsEdit = () => {}, - handleRemoveChip, - handleShowElements, - isEditMode = false, - setEditConfig = () => {} - }, - { hiddenChipsCounterRef, hiddenChipsPopUpRef } - ) => { - const { hiddenChipsBlockClassNames } = useHiddenChipsBlock( - hiddenChipsCounterRef, - hiddenChipsPopUpRef - ) - - useEffect(() => { - if (chips.length === 0) { - handleShowElements() - } - }) - - return createPortal( -
      -
      - {chips?.map((element, index) => { - return ( - - - - ) - })} -
      -
      , - document.getElementById('overlay_container') - ) - } -) - -HiddenChipsBlock.displayName = 'HiddenChipsBlock' - -HiddenChipsBlock.propTypes = { - className: PropTypes.string, - chips: CHIPS, - chipOptions: CHIP_OPTIONS.isRequired, - chipIndex: PropTypes.number, - editConfig: PropTypes.object, - handleEditChip: PropTypes.func, - handleIsEdit: PropTypes.func, - handleRemoveChip: PropTypes.func, - handleShowElements: PropTypes.func.isRequired, - isEditMode: PropTypes.bool, - setEditConfig: PropTypes.func -} - -export default HiddenChipsBlock diff --git a/src/common/ChipCell/SizeChips.js b/src/common/ChipCell/SizeChips.js deleted file mode 100644 index 99a0b770ca..0000000000 --- a/src/common/ChipCell/SizeChips.js +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import { cutChips } from '../../utils/cutChips' - -export const sizeChips = { - 1000: (elements, delimiter) => cutChips(elements, 8, delimiter), - 900: (elements, delimiter) => cutChips(elements, 7, delimiter), - 800: (elements, delimiter) => cutChips(elements, 6, delimiter), - 700: (elements, delimiter) => cutChips(elements, 6, delimiter), - 600: (elements, delimiter) => cutChips(elements, 5, delimiter), - 500: (elements, delimiter) => cutChips(elements, 4, delimiter), - 400: (elements, delimiter) => cutChips(elements, 3, delimiter), - 300: (elements, delimiter) => cutChips(elements, 2, delimiter), - 200: (elements, delimiter) => cutChips(elements, 1, delimiter), - 100: (elements, delimiter) => cutChips(elements, 0, delimiter), - 0: (elements, delimiter) => cutChips(elements, 0, delimiter) -} diff --git a/src/common/ChipCell/chipCell.scss b/src/common/ChipCell/chipCell.scss deleted file mode 100644 index ae970f419b..0000000000 --- a/src/common/ChipCell/chipCell.scss +++ /dev/null @@ -1,53 +0,0 @@ -@use 'igz-controls/scss/colors'; -@use 'igz-controls/scss/borders'; -@use 'igz-controls/scss/mixins'; - -.chips { - &-wrapper { - display: flex; - align-items: center; - max-width: 100%; - } - - &-cell { - display: flex; - flex: 1; - align-items: center; - max-width: 100%; - - .fixed-max-width { - max-width: 100%; - } - - .chip { - &-block { - position: relative; - max-width: 100%; - } - } - - .button-add { - display: flex; - align-items: center; - justify-content: center; - margin: 2px 0 2px 0; - border-radius: 32px; - - &-background { - @include mixins.chipBackground(true); - } - - &_border { - @include mixins.chipBorder(); - } - - &-density { - @include mixins.chipDensity(false, true); - } - - &-font { - @include mixins.chipsFont(ButtonAddChip); - } - } - } -} diff --git a/src/common/ChipForm/ChipForm.jsx b/src/common/ChipForm/ChipForm.jsx deleted file mode 100644 index 47ce465c1c..0000000000 --- a/src/common/ChipForm/ChipForm.jsx +++ /dev/null @@ -1,290 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useState, useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import { isEmpty } from 'lodash' - -import { OptionsMenu, ValidationTemplate } from 'igz-controls/elements' - -import { TAB, TAB_SHIFT } from 'igz-controls/constants' -import { CHIP_OPTIONS } from '../../types' - -import './chipForm.scss' - -const ChipForm = React.forwardRef( - ( - { - checkValidation = null, - chipOptions, - className = '', - editConfig, - onChange, - setEditConfig, - validationRules = [], - value - }, - ref - ) => { - const [chip, setChip] = useState({ - ...value, - keyFieldWidth: 0, - valueFieldWidth: 0 - }) - const maxWidthInput = useMemo(() => { - return ref.current?.clientWidth - 50 - }, [ref]) - const { background, borderColor, density, font, borderRadius } = chipOptions - const minWidthInput = 25 - const minWidthValueInput = 35 - - const refInputKey = useRef() - const refInputValue = useRef() - const refInputContainer = useRef() - - const labelKeyClassName = classnames( - className, - !editConfig.isKeyFocused && 'item_edited', - !isEmpty(validationRules) && 'item_edited_invalid' - ) - const labelContainerClassName = classnames( - 'edit-chip-container', - background && `edit-chip-container-background_${background}`, - borderColor && `edit-chip-container-border_${borderColor}`, - font && `edit-chip-container-font_${font}`, - density && `edit-chip-container-density_${density}`, - borderRadius && `edit-chip-container-border_${borderRadius}`, - (editConfig.isEdit || editConfig.isNewChip) && 'edit-chip-container_edited' - ) - const labelValueClassName = classnames( - 'input-label-value', - !editConfig.isValueFocused && 'item_edited' - ) - - useLayoutEffect(() => { - if (!chip.keyFieldWidth && !chip.valueFieldWidth) { - const currentWidthKeyInput = refInputKey.current.scrollWidth + 1 - const currentWidthValueInput = refInputValue.current.scrollWidth + 1 - - if (chip.key && chip.value) { - setChip(prevState => ({ - ...prevState, - keyFieldWidth: - currentWidthKeyInput >= maxWidthInput ? maxWidthInput : currentWidthKeyInput, - valueFieldWidth: - currentWidthValueInput >= maxWidthInput ? maxWidthInput : currentWidthValueInput - })) - } else { - setChip(prevState => ({ - ...prevState, - keyFieldWidth: minWidthInput, - valueFieldWidth: minWidthValueInput - })) - } - } - }, [ - chip.key, - chip.keyFieldWidth, - chip.value, - chip.valueFieldWidth, - maxWidthInput, - refInputKey, - refInputValue - ]) - - useEffect(() => { - if (editConfig.isKeyFocused) { - refInputKey.current.focus() - } else if (editConfig.isValueFocused) { - refInputValue.current.focus() - } - }, [editConfig.isKeyFocused, editConfig.isValueFocused, refInputKey, refInputValue]) - - const outsideClick = useCallback( - event => { - event.stopPropagation() - const elementPath = event.path ?? event.composedPath?.() - - if (!elementPath.includes(refInputContainer.current)) { - onChange(event, chip, 'Click') - } - }, - [chip, onChange, refInputContainer] - ) - - useEffect(() => { - if (editConfig.isEdit) { - document.addEventListener('click', outsideClick, true) - - return () => { - document.removeEventListener('click', outsideClick, true) - } - } - }, [outsideClick, editConfig.isEdit]) - - const focusChip = useCallback( - event => { - event.stopPropagation() - - if (!event.shiftKey && event.key === TAB && editConfig.isValueFocused) { - onChange(event, chip, TAB) - } else if (event.shiftKey && event.key === TAB && editConfig.isKeyFocused) { - onChange(event, chip, TAB_SHIFT) - } - - if (event.key === 'Backspace' || event.key === 'Delete') { - setChip(prevState => ({ - ...prevState, - keyFieldWidth: editConfig.isKeyFocused ? minWidthInput : prevState.keyFieldWidth, - valueFieldWidth: editConfig.isValueFocused - ? minWidthValueInput - : prevState.valueFieldWidth - })) - } - }, - [editConfig, onChange, chip] - ) - - const handleOnFocus = useCallback( - event => { - if (event.target.name === 'key') { - refInputKey.current.selectionStart = refInputKey.current.selectionEnd - - setEditConfig(prevState => ({ - ...prevState, - isKeyFocused: true, - isValueFocused: false - })) - } else { - refInputValue.current.selectionStart = refInputValue.current.selectionEnd - - setEditConfig(prevState => ({ - ...prevState, - isKeyFocused: false, - isValueFocused: true - })) - } - }, - [refInputKey, refInputValue, setEditConfig] - ) - - const handleOnChange = useCallback( - event => { - event.preventDefault() - - if (event.target.name === 'key') { - const currentWidthKeyInput = refInputKey.current.scrollWidth - checkValidation && checkValidation(refInputKey.current.value) - - setChip(prevState => ({ - ...prevState, - key: refInputKey.current.value, - keyFieldWidth: - refInputKey.current.value.length <= 1 - ? minWidthInput - : currentWidthKeyInput >= maxWidthInput - ? maxWidthInput - : currentWidthKeyInput > minWidthInput - ? currentWidthKeyInput + 2 - : minWidthInput - })) - } else { - const currentWidthValueInput = refInputValue.current.scrollWidth - - setChip(prevState => ({ - ...prevState, - value: refInputValue.current.value, - valueFieldWidth: - refInputValue.current.value.length <= 1 - ? minWidthValueInput - : currentWidthValueInput >= maxWidthInput - ? maxWidthInput - : currentWidthValueInput > minWidthValueInput - ? currentWidthValueInput + 2 - : minWidthValueInput - })) - } - }, - [checkValidation, maxWidthInput, refInputKey, refInputValue] - ) - - const getValidationRules = useCallback(() => { - return validationRules.map(({ isValid = false, label, name }) => { - return - }) - }, [validationRules]) - - return ( - <> -
      editConfig.isEdit && focusChip(event)} - > - -
      :
      - -
      - {validationRules.length > 0 && ( - 0} ref={{ refInputContainer }}> - {getValidationRules()} - - )} - - ) - } -) - -ChipForm.displayName = 'ChipForm' - -ChipForm.propTypes = { - checkValidation: PropTypes.func, - chipOptions: CHIP_OPTIONS.isRequired, - className: PropTypes.string, - editConfig: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - setEditConfig: PropTypes.func.isRequired, - validationRules: PropTypes.array, - value: PropTypes.object.isRequired -} - -export default ChipForm diff --git a/src/common/ChipForm/chipForm.scss b/src/common/ChipForm/chipForm.scss deleted file mode 100644 index 5cd3267412..0000000000 --- a/src/common/ChipForm/chipForm.scss +++ /dev/null @@ -1,66 +0,0 @@ -@use 'igz-controls/scss/colors'; -@use 'igz-controls/scss/borders'; -@use 'igz-controls/scss/mixins'; - -.edit-chip { - &-container { - display: inline-flex; - max-width: 100%; - margin: 2px 8px 2px 0; - padding: 0 8px; - font-size: 14px; - line-height: 22px; - - input { - display: flex; - padding: 0; - font-size: 14px; - background-color: transparent; - border: none; - - &.item_edited { - &::placeholder { - color: colors.$spunPearl; - } - - &_invalid { - color: colors.$amaranth; - } - } - - &::placeholder { - color: colors.$primary; - } - } - - &-background { - @include mixins.chipBackground(false); - } - - &-border { - @include mixins.chipBorder(); - } - - &-density { - @include mixins.chipDensity(true, false); - } - - &-font { - @include mixins.chipsFont(EditableChip); - } - } - - &-separator { - margin-right: 5px; - } - - &__icon-close { - display: flex; - align-items: center; - justify-content: center; - - svg { - transform: scale(0.7); - } - } -} diff --git a/src/common/ChipInput/ChipInput.jsx b/src/common/ChipInput/ChipInput.jsx index a432eca53a..f731d5e550 100644 --- a/src/common/ChipInput/ChipInput.jsx +++ b/src/common/ChipInput/ChipInput.jsx @@ -21,10 +21,9 @@ import React, { useCallback, useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import Chip from '../Chip/Chip' - -import { deleteUnsafeHtml } from '../../utils' -import { CHIP_INPUT_LIST, CHIP_OPTIONS } from '../../types' +import { Chip } from 'igz-controls/components' +import { deleteUnsafeHtml } from 'igz-controls/utils/string.util' +import { CHIP_INPUT_LIST, CHIP_OPTIONS } from 'igz-controls/types' import './chipInput.scss' diff --git a/src/common/CopyToClipboard/CopyToClipboard.jsx b/src/common/CopyToClipboard/CopyToClipboard.jsx deleted file mode 100644 index 7c07a3fc0a..0000000000 --- a/src/common/CopyToClipboard/CopyToClipboard.jsx +++ /dev/null @@ -1,85 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import PropTypes from 'prop-types' -import { useMemo } from 'react' -import { useDispatch } from 'react-redux' - -import { Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' - -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' - -import Copy from 'igz-controls/images/copy-to-clipboard-icon.svg?react' - -const CopyToClipboard = ({ - children = null, - className = '', - disabled = false, - textToCopy = '', - tooltipText -}) => { - const dispatch = useDispatch() - const copyIsDisabled = useMemo(() => disabled || !textToCopy, [disabled, textToCopy]) - - const copyToClipboard = textToCopy => { - navigator.clipboard - .writeText(textToCopy) - .then(() => { - dispatch( - setNotification({ - status: 200, - id: Math.random(), - message: 'Copied to clipboard successfully' - }) - ) - }) - .catch(error => { - showErrorNotification(dispatch, error, '', 'Copy to clipboard failed') - }) - } - - return ( -
      - {children ? ( - } textShow> - copyToClipboard(textToCopy)}>{children} - - ) : ( - copyToClipboard(textToCopy)} - disabled={copyIsDisabled} - > - - - )} -
      - ) -} - -CopyToClipboard.propTypes = { - children: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), - className: PropTypes.string, - disabled: PropTypes.bool, - textToCopy: PropTypes.string, - tooltipText: PropTypes.string.isRequired -} - -export default CopyToClipboard diff --git a/src/common/DatePicker/DatePickerView.jsx b/src/common/DatePicker/DatePickerView.jsx index 2579a9a203..1b9f143d04 100644 --- a/src/common/DatePicker/DatePickerView.jsx +++ b/src/common/DatePicker/DatePickerView.jsx @@ -23,9 +23,15 @@ import MaskedInput from 'react-text-mask' import classnames from 'classnames' import { isEmpty } from 'lodash' -import ErrorMessage from '../ErrorMessage/ErrorMessage' import TimePicker from '../TimePicker/TimePicker' -import { Button, Tip, Tooltip, TextTooltipTemplate, PopUpDialog } from 'igz-controls/components' +import { + Button, + Tip, + Tooltip, + TextTooltipTemplate, + PopUpDialog, + ErrorMessage +} from 'igz-controls/components' import { SelectOption } from 'igz-controls/elements' import { PRIMARY_BUTTON } from 'igz-controls/constants' diff --git a/src/common/ErrorMessage/ErrorMessage.jsx b/src/common/ErrorMessage/ErrorMessage.jsx deleted file mode 100644 index 0cab05011c..0000000000 --- a/src/common/ErrorMessage/ErrorMessage.jsx +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' -import PropTypes from 'prop-types' - -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' - -import UnsuccessAlert from 'igz-controls/images/unsuccess_alert.svg?react' -import Close from 'igz-controls/images/close.svg?react' - -import './errorMessage.scss' - -const ErrorMessage = ({ closeError = null, message }) => { - return ( -
      -
      -
      - -
      -
      {message}
      -
      - {closeError && ( - - )} -
      - ) -} - -ErrorMessage.propTypes = { - closeError: PropTypes.func, - message: PropTypes.string.isRequired -} - -export default ErrorMessage diff --git a/src/common/ErrorMessage/ErrorMessage.test.js b/src/common/ErrorMessage/ErrorMessage.test.js deleted file mode 100644 index 376a8756c0..0000000000 --- a/src/common/ErrorMessage/ErrorMessage.test.js +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import { cleanup, fireEvent, render } from '@testing-library/react' -import React from 'react' -import ErrorMessage from './ErrorMessage' - -jest.mock('igz-controls/images/unsuccess_alert.svg', () => ({ - ReactComponent: 'unsuccess_alert-icon' -})) - -jest.mock('igz-controls/images/close.svg', () => ({ - ReactComponent: 'close-icon' -})) - -describe('ErrorMessage component', () => { - let wrapper - let mockCloseError = jest.fn() - - beforeEach(() => { - const props = { - message: 'Something went wrong', - closeError: mockCloseError - } - wrapper = render() - }) - - afterEach(cleanup) - - it('renders without crashing', () => { - expect(wrapper.queryByTestId('error-message')).not.toBeNull() - }) - - it('should display message if it not empty', () => { - const message = wrapper.getByText(/Something went wrong/i) - expect(message.textContent).toEqual('Something went wrong') - }) - - it('should call "closeError" handler', () => { - const closeIcon = wrapper.queryByTestId('close') - fireEvent.click(closeIcon) - - expect(mockCloseError).toHaveBeenCalled() - }) -}) diff --git a/src/common/ErrorMessage/errorMessage.scss b/src/common/ErrorMessage/errorMessage.scss deleted file mode 100644 index d7aca13451..0000000000 --- a/src/common/ErrorMessage/errorMessage.scss +++ /dev/null @@ -1,30 +0,0 @@ -@use 'igz-controls/scss/borders'; -@use 'igz-controls/scss/colors'; - -.error { - display: flex; - justify-content: space-between; - padding: 10px 14px; - color: colors.$amaranth; - background-color: rgba(colors.$amaranth, 0.1); - border: borders.$errorBorder; - - &__data { - display: flex; - align-items: center; - } - - &__message { - margin-right: 10px; - word-break: break-word; - } - - &__icon { - width: 22px; - height: 22px; - margin-right: 10px; - padding: 5px; - background-color: colors.$burntSienna; - border-radius: 50%; - } -} diff --git a/src/common/Input/Input.jsx b/src/common/Input/Input.jsx index 639da14141..4566217434 100644 --- a/src/common/Input/Input.jsx +++ b/src/common/Input/Input.jsx @@ -27,7 +27,7 @@ import { OptionsMenu, ValidationTemplate } from 'igz-controls/elements' import { Tip, Tooltip, TextTooltipTemplate } from 'igz-controls/components' import { checkPatternsValidity } from 'igz-controls/utils/validation.util' import { useDetectOutsideClick } from 'igz-controls/hooks' -import { DENSITY_OPTIONS } from '../../types' +import { DENSITY_OPTIONS } from 'igz-controls/types' import ExclamationMarkIcon from 'igz-controls/images/exclamation-mark.svg?react' import WarningIcon from 'igz-controls/images/warning.svg?react' diff --git a/src/common/LoadButton/LoadButton.jsx b/src/common/LoadButton/LoadButton.jsx deleted file mode 100644 index ab3491d72e..0000000000 --- a/src/common/LoadButton/LoadButton.jsx +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' -import PropTypes from 'prop-types' -import classNames from 'classnames' - -import { PRIMARY_BUTTON, SECONDARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' - -import './loadButton.scss' - -const LoadButton = React.forwardRef( - ({ className = '', label = 'Load button', variant = TERTIARY_BUTTON, ...restProps }, ref) => { - const buttonClassName = classNames('btn-load', `btn-load-${variant}`, className) - - return ( - - ) - } -) - -LoadButton.displayName = 'LoadButton' - -LoadButton.propTypes = { - className: PropTypes.string, - label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), - variant: PropTypes.PropTypes.oneOf([PRIMARY_BUTTON, SECONDARY_BUTTON, TERTIARY_BUTTON]).isRequired -} - -export default LoadButton diff --git a/src/common/LoadButton/LoadButton.stories.js b/src/common/LoadButton/LoadButton.stories.js deleted file mode 100644 index ed3b1cc244..0000000000 --- a/src/common/LoadButton/LoadButton.stories.js +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' - -import LoadButton from './LoadButton' - -import { PRIMARY_BUTTON, SECONDARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' - -export default { - title: 'Example/LoadButton', - component: LoadButton -} - -const commonArgs = { - disabled: false -} - -const Template = args => - -export const PrimaryLoader = Template.bind({}) -PrimaryLoader.args = { - ...commonArgs, - label: 'Primary loader', - variant: PRIMARY_BUTTON -} - -export const SecondaryLoader = Template.bind({}) -SecondaryLoader.args = { - ...commonArgs, - label: 'Secondary loader', - variant: SECONDARY_BUTTON -} - -export const TertiaryLoader = Template.bind({}) -TertiaryLoader.args = { - ...commonArgs, - label: 'Tertiary loader', - variant: TERTIARY_BUTTON -} diff --git a/src/common/LoadButton/loadButton.scss b/src/common/LoadButton/loadButton.scss deleted file mode 100644 index c0f8c0d3ba..0000000000 --- a/src/common/LoadButton/loadButton.scss +++ /dev/null @@ -1,80 +0,0 @@ -@use 'igz-controls/scss/variables'; -@use 'igz-controls/scss/colors'; -@use 'igz-controls/scss/borders'; - -.btn-load { - display: flex; - align-items: center; - justify-content: center; - min-width: 90px; - height: 40px; - padding: 0 16px; - color: colors.$primary; - font-weight: 500; - font-size: 14px; - font-style: normal; - line-height: 16px; - background: colors.$white; - border: borders.$primaryBorder; - border-radius: variables.$mainBorderRadius; - - svg { - path { - fill: colors.$white; - } - } - - &:active { - background: colors.$gallery; - } - - &:hover { - background: colors.$alabaster; - } - - &:disabled { - color: colors.$spunPearl; - background: colors.$white; - cursor: not-allowed; - - svg { - path { - fill: colors.$alto; - } - } - } - - :first-child { - margin-right: 5px; - } - - &-primary { - border-bottom: borders.$applyBtnBorder; - - &:disabled { - border-bottom: 4px solid colors.$hummingBird; - } - } - - &-secondary { - border-bottom: 4px solid colors.$malibu; - - &:disabled { - border-bottom: 4px solid colors.$titanWhite; - } - } - - &-tertiary { - border-bottom: 4px solid colors.$spunPearl; - - svg { - path { - fill: colors.$primary; - } - } - - &:disabled { - border-bottom: 4px solid colors.$athensGray; - } - } -} diff --git a/src/common/Loader/Loader.jsx b/src/common/Loader/Loader.jsx deleted file mode 100644 index 32cf9dcfbb..0000000000 --- a/src/common/Loader/Loader.jsx +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' -import classnames from 'classnames' -import PropTypes from 'prop-types' - -import './loader.scss' - -const Loader = ({ secondary = false, section = false, small = false }) => { - const wrapperClassNames = classnames( - 'loader-wrapper', - section && 'section-loader', - small && 'small-loader', - secondary && 'secondary-loader' - ) - - return ( -
      -
      -
      - ) -} - -Loader.propTypes = { - secondary: PropTypes.bool, - section: PropTypes.bool, - small: PropTypes.bool -} - -export default React.memo(Loader) diff --git a/src/common/Loader/LoaderForSuspenseFallback.jsx b/src/common/Loader/LoaderForSuspenseFallback.jsx deleted file mode 100644 index 9e5511e80f..0000000000 --- a/src/common/Loader/LoaderForSuspenseFallback.jsx +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useLayoutEffect } from 'react' -import Loader from './Loader' - -const LoaderForSuspenseFallback = () => { - useLayoutEffect(() => { - const overlayContainer = document.getElementById('overlay_container') - const savedVisibilityStyle = overlayContainer ? overlayContainer.style.visibility : 'visible' - - if (overlayContainer) overlayContainer.style.visibility = 'hidden' - - return () => { - if (overlayContainer) overlayContainer.style.visibility = savedVisibilityStyle - } - }, []) - - return -} - -export default React.memo(LoaderForSuspenseFallback) diff --git a/src/common/Loader/loader.scss b/src/common/Loader/loader.scss deleted file mode 100644 index dde643b8bb..0000000000 --- a/src/common/Loader/loader.scss +++ /dev/null @@ -1,59 +0,0 @@ -@use 'igz-controls/scss/colors'; - -.loader-wrapper { - position: fixed; - top: 0; - left: 0; - z-index: 10; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - background-color: rgba(colors.$black, 0.16); - - .loader { - display: flex; - - &::after { - display: block; - width: 64px; - height: 64px; - border: 6px solid colors.$cornflowerBlue; - border-color: colors.$cornflowerBlue transparent colors.$cornflowerBlue transparent; - border-radius: 50%; - animation: rotate 1.5s linear infinite; - content: ' '; - } - } - - &.section-loader { - position: relative; - z-index: 2; - background-color: transparent; - } - - &.small-loader { - .loader { - &::after { - width: 20px; - height: 20px; - border-width: 2px; - } - } - } - - &.secondary-loader { - .loader { - &::after { - border-color: colors.$spunPearl transparent colors.$spunPearl transparent; - } - } - } -} - -@keyframes rotate { - 100% { - transform: rotate(360deg); - } -} diff --git a/src/common/MlChart/MlChart.jsx b/src/common/MlChart/MlChart.jsx index e917a9ef86..f621d477ea 100644 --- a/src/common/MlChart/MlChart.jsx +++ b/src/common/MlChart/MlChart.jsx @@ -20,9 +20,10 @@ such restriction. import React, { useState, useRef, useEffect } from 'react' import PropTypes from 'prop-types' import { Chart } from 'chart.js/auto' -import Loader from '../Loader/Loader' import classnames from 'classnames' +import { Loader } from 'igz-controls/components' + import './mlChart.scss' const defaultOnChartCreated = () => {} diff --git a/src/common/Notifications/Notification.jsx b/src/common/Notifications/Notification.jsx index 44dfef1896..23ce82c3c3 100644 --- a/src/common/Notifications/Notification.jsx +++ b/src/common/Notifications/Notification.jsx @@ -26,7 +26,7 @@ import classnames from 'classnames' import { useTimeout } from '../../hooks/useTimeout' -import { removeNotification } from '../../reducers/notificationReducer' +import { removeNotification } from 'igz-controls/reducers/notificationReducer' import { NOTIFICATION_DURATION } from '../../constants' diff --git a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx index de7ee73f4d..7fd1d32941 100644 --- a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx +++ b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx @@ -22,7 +22,7 @@ import PropTypes from 'prop-types' import { useSelector } from 'react-redux' import { Link, useLocation } from 'react-router-dom' -import { getDateAndTimeByFormat } from '../../utils/' +import { getDateAndTimeByFormat } from 'igz-controls/utils/datetime.util' import { PROJECT_MONITOR, PROJECT_QUICK_ACTIONS_PAGE } from '../../constants' import './ProjectDetailsHeader.scss' diff --git a/src/common/RangeInput/RangeInput.jsx b/src/common/RangeInput/RangeInput.jsx index e18cd53688..34820011ee 100644 --- a/src/common/RangeInput/RangeInput.jsx +++ b/src/common/RangeInput/RangeInput.jsx @@ -25,7 +25,7 @@ import { isNil } from 'lodash' import Input from '../Input/Input' import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' -import { DENSITY_OPTIONS } from '../../types' +import { DENSITY_OPTIONS } from 'igz-controls/types' import Arrow from 'igz-controls/images/range-arrow-small.svg?react' import ExclamationMarkIcon from 'igz-controls/images/exclamation-mark.svg?react' diff --git a/src/common/Search/Search.jsx b/src/common/Search/Search.jsx index a798b8299a..e8cd1fc587 100644 --- a/src/common/Search/Search.jsx +++ b/src/common/Search/Search.jsx @@ -25,7 +25,7 @@ import Input from '../Input/Input' import { SelectOption } from 'igz-controls/elements' import { PopUpDialog } from 'igz-controls/components' -import { deleteUnsafeHtml } from '../../utils' +import { deleteUnsafeHtml } from 'igz-controls/utils/string.util' import SearchIcon from 'igz-controls/images/search.svg?react' diff --git a/src/common/Select/Select.jsx b/src/common/Select/Select.jsx index 0d783ff540..c102f4c8d2 100644 --- a/src/common/Select/Select.jsx +++ b/src/common/Select/Select.jsx @@ -24,7 +24,8 @@ import classNames from 'classnames' import { ConfirmDialog, Tooltip, TextTooltipTemplate, PopUpDialog } from 'igz-controls/components' import { SelectOption } from 'igz-controls/elements' -import { DENSITY_OPTIONS, SELECT_OPTIONS } from '../../types' +import { SELECT_OPTIONS } from '../../types' +import { DENSITY_OPTIONS } from 'igz-controls/types' import { TERTIARY_BUTTON } from 'igz-controls/constants' import Caret from 'igz-controls/images/dropdown.svg?react' diff --git a/src/common/TabsSlider/TabsSlider.jsx b/src/common/TabsSlider/TabsSlider.jsx deleted file mode 100644 index b8b22d5fc6..0000000000 --- a/src/common/TabsSlider/TabsSlider.jsx +++ /dev/null @@ -1,239 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { useCallback, useEffect, useState, useRef } from 'react' -import { Link, useLocation, useParams } from 'react-router-dom' -import PropTypes from 'prop-types' -import classnames from 'classnames' - -import { Tip } from 'igz-controls/components' - -import { SLIDER_TABS } from '../../types' -import { generateUrlFromRouterPath } from '../../utils/link-helper.util' - -import Arrow from 'igz-controls/images/arrow.svg?react' - -const TabsSlider = ({ - fontSize = 'sm', - initialTab = '', - isDetailsPopUp = false, - onClick = () => {}, - skipLink = false, - tabsList -}) => { - const [selectedTab, setSelectedTab] = useState(initialTab) - const [arrowsAreHidden, setArrowsAreHidden] = useState(true) - const [scrolledWidth, setScrolledWidth] = useState(0) - const [rightArrowDisabled, setRightArrowDisabled] = useState(false) - const tabsWrapperRef = useRef() - const tabsRef = useRef() - const location = useLocation() - const params = useParams() - const menuOffsetHalfWidth = 2 - const tabOffset = 1.5 - - const leftArrowClassNames = classnames( - 'tabs-slider__arrow', - 'tabs-slider__arrow_left', - arrowsAreHidden && 'tabs-slider__arrow_hidden', - scrolledWidth === 0 && 'tabs-slider__arrow_disabled' - ) - const rightArrowClassNames = classnames( - 'tabs-slider__arrow', - 'tabs-slider__arrow_right', - arrowsAreHidden && 'tabs-slider__arrow_hidden', - rightArrowDisabled && 'tabs-slider__arrow_disabled' - ) - - const scrollTabs = toRight => { - let scrollWidth - - if (toRight) { - if ( - tabsRef.current?.scrollWidth < - tabsWrapperRef.current?.offsetWidth * tabOffset + scrolledWidth - ) { - scrollWidth = tabsRef.current?.scrollWidth - tabsWrapperRef.current?.offsetWidth - - setRightArrowDisabled(true) - } else { - scrollWidth = scrolledWidth + tabsWrapperRef.current?.offsetWidth / menuOffsetHalfWidth - } - } else { - scrollWidth = Math.max( - 0, - scrolledWidth - tabsWrapperRef.current?.offsetWidth / menuOffsetHalfWidth - ) - - setRightArrowDisabled(false) - } - - setScrolledWidth(scrollWidth) - } - - const handleHideArrows = useCallback(() => { - const scrollIsHidden = tabsRef.current?.offsetWidth === tabsRef.current?.scrollWidth - - setArrowsAreHidden(scrollIsHidden) - - if (rightArrowDisabled) { - setScrolledWidth(tabsRef.current?.scrollWidth - tabsWrapperRef.current?.offsetWidth) - } - - if (scrollIsHidden) { - setScrolledWidth(0) - setRightArrowDisabled(false) - } - }, [rightArrowDisabled, tabsRef, tabsWrapperRef]) - - const moveToSelectedTab = useCallback(() => { - const selectedTabNode = document.querySelector(`[data-tab='${selectedTab}']`) - const centeredTabPosition = - selectedTabNode?.offsetLeft - - tabsWrapperRef.current?.offsetWidth / menuOffsetHalfWidth + - selectedTabNode?.offsetWidth / menuOffsetHalfWidth - - if (centeredTabPosition <= 0) { - setScrolledWidth(0) - setRightArrowDisabled(false) - } else if ( - tabsRef.current?.scrollWidth < - tabsWrapperRef.current?.offsetWidth / menuOffsetHalfWidth + - selectedTabNode?.offsetLeft + - selectedTabNode?.offsetWidth - ) { - setScrolledWidth(tabsRef.current?.scrollWidth - tabsWrapperRef.current?.offsetWidth) - setRightArrowDisabled(true) - } else { - setScrolledWidth(centeredTabPosition) - setRightArrowDisabled(false) - } - }, [selectedTab]) - - const onSelectTab = newTab => { - setSelectedTab(newTab) - onClick && onClick(newTab) - } - - useEffect(() => { - window.addEventListener('resize', handleHideArrows) - - return () => window.removeEventListener('resize', handleHideArrows) - }, [handleHideArrows]) - - useEffect(() => { - window.addEventListener('resize', moveToSelectedTab) - - return () => window.removeEventListener('resize', moveToSelectedTab) - }, [moveToSelectedTab]) - - useEffect(() => { - handleHideArrows() - }, [tabsList, handleHideArrows]) - - useEffect(() => { - moveToSelectedTab() - }, [moveToSelectedTab]) - - useEffect(() => { - if (params.tab && params.tab !== selectedTab && !isDetailsPopUp) { - setSelectedTab(tabsList.find(tab => tab.id === params.tab)?.id) - } - }, [isDetailsPopUp, params.tab, selectedTab, tabsList]) - - return ( -
      -
      { - scrollTabs(false) - }} - > - -
      -
      -
      - {tabsList.map(tab => { - const tabClassName = classnames( - 'content-menu__tab', - `content-menu__tab-${fontSize}`, - selectedTab === tab.id && 'content-menu__tab_active' - ) - - return ( - !tab.hidden && - (!skipLink ? ( - - onSelectTab(tab)} - > - {tab.icon &&
      {tab.icon}
      } - {tab.label} - {tab.tip && } -
      - - ) : ( -
      onSelectTab(tab.id)} - > - {tab.icon &&
      {tab.icon}
      } - {tab.label} - {tab.tip && } -
      - )) - ) - })} -
      -
      -
      scrollTabs(true)}> - -
      -
      - ) -} - -TabsSlider.propTypes = { - fontSize: PropTypes.oneOf(['sm', 'md', 'lg']), - initialTab: PropTypes.string, - isDetailsPopUp: PropTypes.bool, - onClick: PropTypes.func, - skipLink: PropTypes.bool, - tabsList: SLIDER_TABS.isRequired -} - -export default TabsSlider diff --git a/src/common/TargetPath/targetPath.util.js b/src/common/TargetPath/targetPath.util.js index e79fd5a6f1..86ea3c0e86 100644 --- a/src/common/TargetPath/targetPath.util.js +++ b/src/common/TargetPath/targetPath.util.js @@ -34,7 +34,7 @@ import { V3IO_INPUT_PATH_SCHEME } from '../../constants' import { getArtifactReference, getFeatureReference, getParsedResource } from '../../utils/resources' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { fetchArtifact, fetchArtifacts } from '../../reducers/artifactsReducer' import { fetchFeatureVector, fetchFeatureVectors } from '../../reducers/featureStoreReducer' import { fetchProjectsNames } from '../../reducers/projectReducer' diff --git a/src/common/TimePicker/TimePicker.jsx b/src/common/TimePicker/TimePicker.jsx index 0c12f926e0..6e573223e1 100644 --- a/src/common/TimePicker/TimePicker.jsx +++ b/src/common/TimePicker/TimePicker.jsx @@ -22,7 +22,7 @@ import PropTypes from 'prop-types' import MaskedInput from 'react-text-mask' import classNames from 'classnames' -import { DENSITY_OPTIONS } from '../../types' +import { DENSITY_OPTIONS } from 'igz-controls/types' import './timePicker.scss' diff --git a/src/components/ActionBar/ActionBar.jsx b/src/components/ActionBar/ActionBar.jsx index 735812a889..15360caa31 100644 --- a/src/components/ActionBar/ActionBar.jsx +++ b/src/components/ActionBar/ActionBar.jsx @@ -88,7 +88,7 @@ const ActionBar = ({ internalAutoRefreshIsEnabled ) const filtersStore = useSelector(store => store.filtersStore) - const changes = useSelector(store => store.detailsStore.changes) + const changes = useSelector(store => store.commonDetailsStore.changes) const dispatch = useDispatch() const navigate = useNavigate() const params = useParams() diff --git a/src/components/AddToFeatureVectorPage/AddToFeatureVectorPage.jsx b/src/components/AddToFeatureVectorPage/AddToFeatureVectorPage.jsx index c51b67b90d..87a33c71cc 100644 --- a/src/components/AddToFeatureVectorPage/AddToFeatureVectorPage.jsx +++ b/src/components/AddToFeatureVectorPage/AddToFeatureVectorPage.jsx @@ -52,9 +52,9 @@ import { getFiltersConfig } from './addToFeatureVectorPage.util' import { getScssVariableValue } from 'igz-controls/utils/common.util' import { handleFeaturesResponse } from '../FeatureStore/Features/features.util' import { isEveryObjectValueEmpty } from '../../utils/isEveryObjectValueEmpty' -import { setNotification } from '../../reducers/notificationReducer' +import { setNotification } from 'igz-controls/reducers/notificationReducer' import { setTablePanelOpen } from '../../reducers/tableReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { toggleYaml } from '../../reducers/appReducer' import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' import { useGroupContent } from '../../hooks/groupContent.hook' diff --git a/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.jsx b/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.jsx index a50e142d67..6f124dca92 100644 --- a/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.jsx +++ b/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.jsx @@ -22,13 +22,13 @@ import { useParams } from 'react-router-dom' import PropTypes from 'prop-types' import AddToFeatureVectorPageHeader from '../../elements/AddToFeatureVectorPageHeader/AddToFeatureVectorPageHeader' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' import Table from '../Table/Table' import FeatureStoreTableRow from '../../elements/FeatureStoreTableRow/FeatureStoreTableRow' +import { Loader } from 'igz-controls/components' import { ADD_TO_FEATURE_VECTOR_TAB, FEATURE_STORE_PAGE } from '../../constants' -import { VIRTUALIZATION_CONFIG } from '../../types' +import { VIRTUALIZATION_CONFIG } from 'igz-controls/types' import { getNoDataMessage } from '../../utils/getNoDataMessage' import { isRowRendered } from '../../hooks/useVirtualization.hook' import ActionBar from '../ActionBar/ActionBar' diff --git a/src/components/Alerts/Alerts.jsx b/src/components/Alerts/Alerts.jsx index 86b9d88fc9..a07a87dc39 100644 --- a/src/components/Alerts/Alerts.jsx +++ b/src/components/Alerts/Alerts.jsx @@ -22,12 +22,12 @@ import { useNavigate, useParams } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import { isEmpty } from 'lodash' +import { Loader } from 'igz-controls/components' import ActionBar from '../ActionBar/ActionBar' import AlertsFilters from './AlertsFilters' import AlertsTable from '../../elements/AlertsTable/AlertsTable' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import Pagination from '../../common/Pagination/Pagination' -import Loader from '../../common/Loader/Loader' import { ALERTS_FILTERS, ALERTS_PAGE_PATH, MONITOR_ALERTS_PAGE } from '../../constants' import { createAlertRowData } from '../../utils/createAlertsContent' diff --git a/src/components/Alerts/alerts.util.js b/src/components/Alerts/alerts.util.js index 88863bde66..1d73511fde 100644 --- a/src/components/Alerts/alerts.util.js +++ b/src/components/Alerts/alerts.util.js @@ -56,7 +56,7 @@ import { import { fetchAlertById } from '../../reducers/alertsReducer' import { generateObjectNotInTheListMessage } from '../../utils/generateMessage.util' import { createAlertRowData } from '../../utils/createAlertsContent' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' export const getAlertsFiltersConfig = (timeFrameLimit = false, isAlertsPage = false) => { return { diff --git a/src/components/ApplicationMetrics/ApplicationMetrics.jsx b/src/components/ApplicationMetrics/ApplicationMetrics.jsx index 5864f7df63..0415990219 100644 --- a/src/components/ApplicationMetrics/ApplicationMetrics.jsx +++ b/src/components/ApplicationMetrics/ApplicationMetrics.jsx @@ -27,7 +27,6 @@ import classNames from 'classnames' import HistoryBackLink from '../../common/HistoryBackLink/historyBackLink' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' -import Loader from '../../common/Loader/Loader' import DetailsMetrics from '../DetailsMetrics/DetailsMetrics' import NoData from '../../common/NoData/NoData' import { @@ -36,7 +35,8 @@ import { FormOnChange, RoundedIcon, TextTooltipTemplate, - Tooltip + Tooltip, + Loader } from 'igz-controls/components' import { fetchModelEndpoints } from '../../reducers/artifactsReducer' diff --git a/src/components/ArtifactInfoSources/ArtifactInfoSources.jsx b/src/components/ArtifactInfoSources/ArtifactInfoSources.jsx index fc2a230a84..9b5ce8da37 100644 --- a/src/components/ArtifactInfoSources/ArtifactInfoSources.jsx +++ b/src/components/ArtifactInfoSources/ArtifactInfoSources.jsx @@ -22,13 +22,12 @@ import PropTypes from 'prop-types' import FeatureVectorPopUp from '../../elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp' import ArtifactPopUp from '../../elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, CopyToClipboard } from 'igz-controls/components' import { openPopUp } from 'igz-controls/utils/common.util' import { FEATURE_VECTORS_TAB } from '../../constants' import './artifactInfoSources.scss' -import CopyToClipboard from '../../common/CopyToClipboard/CopyToClipboard' const ArtifactInfoSources = ({ isDetailsPopUp = false, sources = {} }) => { const handleOpenSourceDetails = sourceData => { diff --git a/src/components/Artifacts/Artifacts.jsx b/src/components/Artifacts/Artifacts.jsx index aa398a1e40..f46f443839 100644 --- a/src/components/Artifacts/Artifacts.jsx +++ b/src/components/Artifacts/Artifacts.jsx @@ -21,17 +21,13 @@ such restriction. import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useLocation, useNavigate, useParams } from 'react-router-dom' +import { chain, isEmpty, isNil } from 'lodash' import PropTypes from 'prop-types' +import AddArtifactTagPopUp from '../../elements/AddArtifactTagPopUp/AddArtifactTagPopUp' import ArtifactsView from './ArtifactsView' +import DeployModelPopUp from '../../elements/DeployModelPopUp/DeployModelPopUp' -import { getViewMode } from '../../utils/helper' -import { getSavedSearchParams, transformSearchParams } from '../../utils/filter.util' -import { getFiltersConfig } from './artifacts.util' -import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' -import { useRefreshAfterDelete } from '../../hooks/useRefreshAfterDelete.hook' -import { getCloseDetailsLink, isDetailsTabExists } from '../../utils/link-helper.util' -import { openPopUp } from 'igz-controls/utils/common.util' import { ALL_VERSIONS_PATH, BE_PAGE, @@ -44,18 +40,21 @@ import { TAG_FILTER, TAG_FILTER_ALL_ITEMS } from '../../constants' -import { toggleYaml } from '../../reducers/appReducer' -import { chain, isEmpty, isNil } from 'lodash' -import { fetchArtifactsFunctions, fetchArtifactTags } from '../../reducers/artifactsReducer' -import { getFilterTagOptions, setFilters } from '../../reducers/filtersReducer' -import AddArtifactTagPopUp from '../../elements/AddArtifactTagPopUp/AddArtifactTagPopUp' -import DeployModelPopUp from '../../elements/DeployModelPopUp/DeployModelPopUp' -import { setNotification } from '../../reducers/notificationReducer' -import { usePagination } from '../../hooks/usePagination.hook' import { checkForSelectedArtifact, setFullSelectedArtifact } from '../../utils/artifacts.util' -import { getFeatureVectorData } from '../ModelsPage/Models/models.util' +import { fetchArtifactsFunctions, fetchArtifactTags } from '../../reducers/artifactsReducer' import { fetchModelFeatureVector } from '../../reducers/detailsReducer' +import { getCloseDetailsLink, isDetailsTabExists } from '../../utils/link-helper.util' +import { getFeatureVectorData } from '../ModelsPage/Models/models.util' +import { getFilterTagOptions, setFilters } from '../../reducers/filtersReducer' +import { getFiltersConfig } from './artifacts.util' +import { getSavedSearchParams, transformSearchParams } from 'igz-controls/utils/filter.util' +import { openPopUp, getViewMode } from 'igz-controls/utils/common.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { toggleYaml } from '../../reducers/appReducer' +import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' import { useMode } from '../../hooks/mode.hook' +import { usePagination } from '../../hooks/usePagination.hook' +import { useRefreshAfterDelete } from '../../hooks/useRefreshAfterDelete.hook' const Artifacts = ({ actionButtons = [], diff --git a/src/components/Artifacts/ArtifactsTable.jsx b/src/components/Artifacts/ArtifactsTable.jsx index 451df06d23..7ca8ff0545 100644 --- a/src/components/Artifacts/ArtifactsTable.jsx +++ b/src/components/Artifacts/ArtifactsTable.jsx @@ -22,7 +22,6 @@ import PropTypes from 'prop-types' import { isEmpty } from 'lodash' import NoData from '../../common/NoData/NoData' -import Loader from '../../common/Loader/Loader' import Table from '../Table/Table' import ArtifactsFilters from '../ArtifactsActionBar/ArtifactsFilters' import ActionBar from '../ActionBar/ActionBar' @@ -30,11 +29,13 @@ import HistoryBackLink from '../../common/HistoryBackLink/historyBackLink' import Details from '../Details/Details' import ArtifactsTableRow from '../../elements/ArtifactsTableRow/ArtifactsTableRow' import Pagination from '../../common/Pagination/Pagination' +import { Loader } from 'igz-controls/components' -import { getNoDataMessage } from '../../utils/getNoDataMessage' -import { ALL_VERSIONS_PATH, FULL_VIEW_MODE } from '../../constants' +import { ALL_VERSIONS_PATH } from '../../constants' +import { FULL_VIEW_MODE } from 'igz-controls/constants' import { getCloseDetailsLink } from '../../utils/link-helper.util' import { getDefaultFirstHeader } from '../../utils/createArtifactsContent' +import { getNoDataMessage } from '../../utils/getNoDataMessage' let ArtifactsTable = ({ actionButtons, diff --git a/src/components/Artifacts/ArtifactsView.jsx b/src/components/Artifacts/ArtifactsView.jsx index 283a9ffb10..2168b061f7 100644 --- a/src/components/Artifacts/ArtifactsView.jsx +++ b/src/components/Artifacts/ArtifactsView.jsx @@ -22,8 +22,8 @@ import PropTypes from 'prop-types' import ArtifactsTable from './ArtifactsTable' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' -import Loader from '../../common/Loader/Loader' import PreviewModal from '../../elements/PreviewModal/PreviewModal' +import { Loader } from 'igz-controls/components' import './artifacts.scss' diff --git a/src/components/ArtifactsPreview/ArtifactsPreview.jsx b/src/components/ArtifactsPreview/ArtifactsPreview.jsx index 2ad5abc0f4..28c9f1bf9a 100644 --- a/src/components/ArtifactsPreview/ArtifactsPreview.jsx +++ b/src/components/ArtifactsPreview/ArtifactsPreview.jsx @@ -22,8 +22,8 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import ArtifactsPreviewView from './ArtifactsPreviewView' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' +import { Loader } from 'igz-controls/components' const ArtifactsPreview = ({ className = '', noData, preview }) => { const [showErrorBody, setShowErrorBody] = useState(false) diff --git a/src/components/ConsumerGroup/ConsumerGroup.jsx b/src/components/ConsumerGroup/ConsumerGroup.jsx index 43156676f8..be29d755ba 100644 --- a/src/components/ConsumerGroup/ConsumerGroup.jsx +++ b/src/components/ConsumerGroup/ConsumerGroup.jsx @@ -22,13 +22,12 @@ import { useDispatch, useSelector } from 'react-redux' import { isEmpty } from 'lodash' import { useParams } from 'react-router-dom' -import Loader from '../../common/Loader/Loader' +import ConsumerGroupShardLagTableRow from '../../elements/ConsumerGroupShardLagTableRow/ConsumerGroupShardLagTableRow' import NoData from '../../common/NoData/NoData' import PageHeader from '../../elements/PageHeader/PageHeader' -import Table from '../Table/Table' -import { RoundedIcon } from 'igz-controls/components' -import ConsumerGroupShardLagTableRow from '../../elements/ConsumerGroupShardLagTableRow/ConsumerGroupShardLagTableRow' import Search from '../../common/Search/Search' +import Table from '../Table/Table' +import { RoundedIcon, Loader } from 'igz-controls/components' import { CONSUMER_GROUP_PAGE, @@ -38,7 +37,7 @@ import createConsumerGroupContent from '../../utils/createConsumerGroupContent' import { fetchNuclioV3ioStreamShardLags, resetV3ioStreamShardLagsError } from '../../reducers/nuclioReducer.js' import { generatePageData } from './consumerGroup.util.js' import { getNoDataMessage } from '../../utils/getNoDataMessage' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import RefreshIcon from 'igz-controls/images/refresh.svg?react' diff --git a/src/components/ConsumerGroups/ConsumerGroups.jsx b/src/components/ConsumerGroups/ConsumerGroups.jsx index 5f86492ffd..099c79b4a9 100644 --- a/src/components/ConsumerGroups/ConsumerGroups.jsx +++ b/src/components/ConsumerGroups/ConsumerGroups.jsx @@ -21,12 +21,12 @@ import React, { useEffect, useMemo, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useParams, useOutletContext } from 'react-router-dom' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' import PageHeader from '../../elements/PageHeader/PageHeader' import Search from '../../common/Search/Search' import Table from '../Table/Table' import ConsumerGroupTableRow from '../../elements/ConsumerGroupTableRow/ConsumerGroupTableRow' +import { Loader } from 'igz-controls/components' import createConsumerGroupsContent from '../../utils/createConsumerGroupsContent' import { CONSUMER_GROUPS_PAGE, GROUP_BY_NONE, NAME_FILTER } from '../../constants' diff --git a/src/components/ConsumerGroupsWrapper/ConsumerGroupsWrapper.jsx b/src/components/ConsumerGroupsWrapper/ConsumerGroupsWrapper.jsx index e43c882ced..42957a1e37 100644 --- a/src/components/ConsumerGroupsWrapper/ConsumerGroupsWrapper.jsx +++ b/src/components/ConsumerGroupsWrapper/ConsumerGroupsWrapper.jsx @@ -22,14 +22,14 @@ import { useNavigate, useParams, Outlet } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import { isEmpty } from 'lodash' +import { Loader } from 'igz-controls/components' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' -import Loader from '../../common/Loader/Loader' import { GROUP_BY_NONE } from '../../constants' import { areNuclioStreamsEnabled } from '../../utils/helper' import { fetchNuclioV3ioStreams, resetV3ioStreamsError } from '../../reducers/nuclioReducer' import { setFilters } from '../../reducers/filtersReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' const ConsumerGroupsWrapper = () => { const [requestErrorMessage, setRequestErrorMessage] = useState('') diff --git a/src/components/Datasets/datasets.util.jsx b/src/components/Datasets/datasets.util.jsx index 7ce396d648..f442249195 100644 --- a/src/components/Datasets/datasets.util.jsx +++ b/src/components/Datasets/datasets.util.jsx @@ -25,17 +25,15 @@ import DeleteArtifactPopUp from '../../elements/DeleteArtifactPopUp/DeleteArtifa import { ARTIFACT_MAX_DOWNLOAD_SIZE, DATASET_TYPE, - DATASETS_PAGE, - FULL_VIEW_MODE + DATASETS_PAGE } from '../../constants' -import { PRIMARY_BUTTON } from 'igz-controls/constants' +import { PRIMARY_BUTTON, FULL_VIEW_MODE } from 'igz-controls/constants' import { applyTagChanges, chooseOrFetchArtifact } from '../../utils/artifacts.util' -import { copyToClipboard } from '../../utils/copyToClipboard' import { getIsTargetPathValid } from '../../utils/createArtifactsContent' import { showArtifactsPreview } from '../../reducers/artifactsReducer' import { generateUri } from '../../utils/resources' import { handleDeleteArtifact } from '../../utils/handleDeleteArtifact' -import { openPopUp, openDeleteConfirmPopUp } from 'igz-controls/utils/common.util' +import { openPopUp, openDeleteConfirmPopUp, copyToClipboard } from 'igz-controls/utils/common.util' import { setDownloadItem, setShowDownloadsList } from '../../reducers/downloadReducer' import TagIcon from 'igz-controls/images/tag-icon.svg?react' diff --git a/src/components/Details/Details.jsx b/src/components/Details/Details.jsx index b99e4bfb04..1bed60c636 100644 --- a/src/components/Details/Details.jsx +++ b/src/components/Details/Details.jsx @@ -17,23 +17,12 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useEffect, useCallback, useRef, useMemo, useState } from 'react' +import React, { useEffect, useCallback } from 'react' import PropTypes from 'prop-types' -import { useLocation, useParams } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' -import { createForm } from 'final-form' -import arrayMutators from 'final-form-arrays' -import { Form } from 'react-final-form' -import { cloneDeep, isEqual, pickBy } from 'lodash' -import classnames from 'classnames' -import { ConfirmDialog } from 'igz-controls/components' -import ErrorMessage from '../../common/ErrorMessage/ErrorMessage' -import DetailsTabsContent from './DetailsTabsContent/DetailsTabsContent' import DetailsHeader from './DetailsHeader/DetailsHeader' -import Loader from '../../common/Loader/Loader' -import TabsSlider from '../../common/TabsSlider/TabsSlider' -import BlockerSpy from '../../common/BlockerSpy/BlockerSpy' +import DetailsTabsContent from './DetailsTabsContent/DetailsTabsContent' import { ALERTS_PAGE, @@ -47,8 +36,7 @@ import { JOBS_PAGE, LLM_PROMPTS_PAGE, MODEL_ENDPOINTS_TAB, - MODELS_TAB, - VIEW_SEARCH_PARAMETER + MODELS_TAB } from '../../constants' import { generateAlertsContent, @@ -57,24 +45,13 @@ import { generateFunctionsContent, generateJobsContent } from './details.util' -import { - removeDetailsPopUpInfoContent, - removeInfoContent, - removeModelFeatureVector, - resetChanges, - setDetailsPopUpInfoContent, - setEditMode, - setFiltersWasHandled, - setInfoContent, - showWarning -} from '../../reducers/detailsReducer' -import { ACTIONS_MENU } from '../../types' -import { TERTIARY_BUTTON, PRIMARY_BUTTON } from 'igz-controls/constants' +import { DETAILS_MENU, ACTIONS_MENU } from 'igz-controls/types' import { isEveryObjectValueEmpty } from '../../utils/isEveryObjectValueEmpty' -import { setFieldState } from 'igz-controls/utils/form.util' +import { removeModelFeatureVector } from '../../reducers/detailsReducer' import { showArtifactsPreview } from '../../reducers/artifactsReducer' +import { useDetails } from 'igz-controls/hooks/useDetails.hook' -import './details.scss' +import 'igz-controls/scss/details.scss' const Details = ({ actionsMenu, @@ -94,37 +71,36 @@ const Details = ({ tab = '', withActionMenu = true }) => { - const [blocker, setBlocker] = useState({}) - const applyChangesRef = useRef() - const dispatch = useDispatch() - const detailsRef = useRef() - const params = useParams() + const { + DetailsContainer, + applyChanges, + applyChangesRef, + blocker, + cancelChanges, + detailsPanelClassNames, + detailsRef, + commonDetailsStore, + doNotLeavePage, + formRef, + handleShowWarning, + leavePage, + location, + params, + removeDetailsInfo, + setBlocker, + setDetailsInfo, + shouldDetailsBlock + } = useDetails({ + applyDetailsChanges, + applyDetailsChangesCallback, + formInitialValues, + isDetailsPopUp, + isDetailsScreen, + selectedItem + }) const detailsStore = useSelector(store => store.detailsStore) const frontendSpec = useSelector(store => store.appStore.frontendSpec) - const location = useLocation() - const [setDetailsInfo, removeDetailsInfo] = useMemo(() => { - return isDetailsPopUp - ? [setDetailsPopUpInfoContent, removeDetailsPopUpInfoContent] - : [setInfoContent, removeInfoContent] - }, [isDetailsPopUp]) - const previousPathnameRef = useRef( - location.pathname.substring(0, location.pathname.lastIndexOf(params.tab)) - ) - - const detailsPanelClassNames = classnames( - 'table__item', - detailsStore.showWarning && 'pop-up-dialog-opened', - isDetailsScreen && 'table__item_big', - isDetailsPopUp && 'table__item-popup' - ) - - const formRef = useRef( - createForm({ - initialValues: formInitialValues, - mutators: { ...arrayMutators, setFieldState }, - onSubmit: () => {} - }) - ) + const dispatch = useDispatch() const handlePreview = useCallback(() => { dispatch( @@ -135,14 +111,6 @@ const Details = ({ ) }, [dispatch, selectedItem]) - useEffect(() => { - return () => { - if (!isDetailsPopUp) { - dispatch(resetChanges()) - } - } - }, [dispatch, isDetailsPopUp]) - useEffect(() => { if (!isEveryObjectValueEmpty(selectedItem)) { if (pageData.details.type === JOBS_PAGE) { @@ -200,189 +168,54 @@ const Details = ({ } }, [dispatch, pageData.details.type, removeDetailsInfo, selectedItem]) - const handleShowWarning = useCallback( - show => { - dispatch(showWarning(show)) - }, - [dispatch] - ) - - const handleRefreshClick = useCallback( - event => { - if ( - detailsStore.changes.counter > 0 && - document.getElementById('refresh')?.contains(event.target) - ) { - handleShowWarning(true) - dispatch(setFiltersWasHandled(true)) - } - }, - [detailsStore.changes.counter, dispatch, handleShowWarning] - ) - - useEffect(() => { - window.addEventListener('click', handleRefreshClick) - - return () => { - window.removeEventListener('click', handleRefreshClick) - } - }, [handleRefreshClick]) - - const shouldDetailsBlock = useCallback( - ({ currentLocation, nextLocation }) => { - const currentDetailsView = currentLocation.search.split(`${VIEW_SEARCH_PARAMETER}=`)?.[1] - const nextDetailsView = nextLocation.search.split(`${VIEW_SEARCH_PARAMETER}=`)?.[1] - const currentLocationPathname = currentLocation.pathname.split('/') - const nextLocationPathname = nextLocation.pathname.split('/') - currentLocationPathname.pop() - nextLocationPathname.pop() - - return ( - detailsStore.changes.counter > 0 && - (currentLocationPathname.join('/') !== nextLocationPathname.join('/') || - currentDetailsView !== nextDetailsView) - ) - }, - [detailsStore.changes.counter] - ) - - useEffect(() => { - if ( - formRef.current && - detailsStore.changes.counter === 0 && - !isEqual(pickBy(formInitialValues), pickBy(formRef.current.getState()?.values)) && - !formRef.current.getState()?.active - ) { - formRef.current.restart(formInitialValues) - } - }, [formInitialValues, detailsStore.changes.counter]) - - useEffect(() => { - const currentPathname = location.pathname.substring( - 0, - location.pathname.lastIndexOf(params.tab) - ) - - if (previousPathnameRef.current !== currentPathname && !isDetailsPopUp) { - formRef.current.restart(formInitialValues) - dispatch(setEditMode(false)) - previousPathnameRef.current = currentPathname - } - }, [dispatch, formInitialValues, isDetailsPopUp, location.pathname, params.tab]) - - const applyChanges = useCallback(() => { - applyDetailsChanges(detailsStore.changes).then(() => { - dispatch(resetChanges()) - - const changes = cloneDeep(detailsStore.changes) - - // todo [redux-toolkit] rework it after redux-toolkit will be added to the details store. Need to remove setTimeout and use a Promise that resolves after the state is updated. - setTimeout(() => { - applyDetailsChangesCallback(changes, selectedItem) - }) - }) - }, [ - applyDetailsChanges, - applyDetailsChangesCallback, - detailsStore.changes, - dispatch, - selectedItem - ]) - - const cancelChanges = useCallback(() => { - if (detailsStore.changes.counter > 0) { - dispatch(resetChanges()) - formRef.current.reset(formInitialValues) - } - }, [detailsStore.changes.counter, dispatch, formInitialValues]) - - const leavePage = useCallback(() => { - cancelChanges() - handleShowWarning(false) - - if (detailsStore.filtersWasHandled) { - dispatch(setFiltersWasHandled(false)) - } else { - blocker.proceed?.() - } - - window.dispatchEvent(new CustomEvent('discardChanges')) - }, [blocker, cancelChanges, detailsStore.filtersWasHandled, dispatch, handleShowWarning]) - - const doNotLeavePage = useCallback(() => { - blocker.reset?.() - dispatch(showWarning(false)) - window.dispatchEvent(new CustomEvent('cancelLeave')) - }, [blocker, dispatch]) - return ( -
      {}}> - {formState => ( -
      - {detailsStore.loadingCounter > 0 && } - {detailsStore.error && } -
      - - {withActionMenu && ( - setDetailsPopUpSelectedTab && setDetailsPopUpSelectedTab(newTab)} - skipLink={isDetailsPopUp} - tabsList={detailsMenu} - /> - )} -
      -
      - -
      - {(blocker.state === 'blocked' || detailsStore.showWarning) && ( - - )} - {!isDetailsPopUp && ( - - )} -
      + ( + + )} + renderTabsContent={(formState) => ( + )} - + setBlocker={setBlocker} + shouldDetailsBlock={shouldDetailsBlock} + withActionMenu={withActionMenu} + /> ) } @@ -390,13 +223,7 @@ Details.propTypes = { actionsMenu: ACTIONS_MENU.isRequired, applyDetailsChanges: PropTypes.func, applyDetailsChangesCallback: PropTypes.func, - detailsMenu: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - hidden: PropTypes.bool - }) - ).isRequired, + detailsMenu: DETAILS_MENU.isRequired, detailsPopUpSelectedTab: PropTypes.string, formInitialValues: PropTypes.object, getCloseDetailsLink: PropTypes.func, diff --git a/src/components/Details/DetailsHeader/DetailsHeader.jsx b/src/components/Details/DetailsHeader/DetailsHeader.jsx index 1b49000623..b6b39600ea 100644 --- a/src/components/Details/DetailsHeader/DetailsHeader.jsx +++ b/src/components/Details/DetailsHeader/DetailsHeader.jsx @@ -17,40 +17,24 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useCallback, useRef, useMemo } from 'react' +import React, { useMemo, useCallback } from 'react' import PropTypes from 'prop-types' -import { Link, useLocation, useNavigate, useParams } from 'react-router-dom' -import { isEmpty } from 'lodash' import { useDispatch, useSelector } from 'react-redux' +import { Link } from 'react-router-dom' +import { isEmpty } from 'lodash' -import { Button, Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' -import LoadButton from '../../../common/LoadButton/LoadButton' import Select from '../../../common/Select/Select' -import ActionsMenu from '../../../common/ActionsMenu/ActionsMenu' +import { Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' -import { - DETAILS_ARTIFACTS_TAB, - FULL_VIEW_MODE, - JOBS_PAGE, - VIEW_SEARCH_PARAMETER -} from '../../../constants' -import { formatDatetime } from '../../../utils' -import { TERTIARY_BUTTON } from 'igz-controls/constants' -import { ACTIONS_MENU } from '../../../types' -import { getViewMode } from '../../../utils/helper' -import { - generateUrlFromRouterPath, - getDefaultCloseDetailsLink -} from '../../../utils/link-helper.util' -import { getFilteredSearchParams } from '../../../utils/filter.util' +import { ACTIONS_MENU } from 'igz-controls/types' +import { DETAILS_ARTIFACTS_TAB, JOBS_PAGE } from '../../../constants' +import { formatDatetime } from 'igz-controls/utils/datetime.util' +import { generateUrlFromRouterPath } from 'igz-controls/utils/common.util' +import { getDefaultCloseDetailsLink } from '../../../utils/link-helper.util' import { setIteration } from '../../../reducers/detailsReducer' +import { useDetailsHeader } from 'igz-controls/hooks/useDetailsHeader.hook' -import Close from 'igz-controls/images/close.svg?react' import Back from 'igz-controls/images/back-arrow.svg?react' -import Refresh from 'igz-controls/images/refresh.svg?react' -import EnlargeIcon from 'igz-controls/images/ml-enlarge.svg?react' -import MinimizeIcon from 'igz-controls/images/ml-minimize.svg?react' -import HistoryIcon from 'igz-controls/images/history.svg?react' import InfoIcon from 'igz-controls/images/info-fill.svg?react' const DetailsHeader = ({ @@ -60,22 +44,36 @@ const DetailsHeader = ({ cancelChanges, getCloseDetailsLink = null, handleCancel = null, - handleRefresh, + handleRefresh = null, handleShowWarning, - isDetailsScreen, isDetailsPopUp = false, + isDetailsScreen, pageData, selectedItem, - tab, + tab = '', withActionMenu = true }) => { + const { + DetailsHeaderContainer, + actionButton, + commonDetailsStore, + handleBackClick, + handleCancelClick, + headerRef, + location, + navigate, + params, + showAllVersions, + viewMode, + withToggleViewBtn + } = useDetailsHeader({ + handleCancel, + handleShowWarning, + isDetailsPopUp, + pageData + }) + const detailsStore = useSelector(store => store.detailsStore) - const params = useParams() - const navigate = useNavigate() - const viewMode = getViewMode(window.location.search) - const { actionButton, withToggleViewBtn, showAllVersions } = pageData.details - const headerRef = useRef() - const location = useLocation() const dispatch = useDispatch() const errorMessage = useMemo( @@ -92,253 +90,183 @@ const DetailsHeader = ({ return isDetailsPopUp ? detailsStore.detailsJobPods : detailsStore.pods }, [detailsStore.detailsJobPods, detailsStore.pods, isDetailsPopUp]) - const { - value: stateValue, - label: stateLabel, - className: stateClassName - } = selectedItem.state || {} + const state = useMemo(() => { + const selectedItemState = selectedItem.state || {} - const handleBackClick = useCallback(() => { - if (detailsStore.changes.counter > 0) { - handleShowWarning(true) - } else { - handleCancel() + return { + value: selectedItemState.value, + label: selectedItemState.label, + className: selectedItemState.className } - }, [detailsStore.changes.counter, handleCancel, handleShowWarning]) + }, [selectedItem.state]) - const handleCancelClick = useCallback(() => { - if (detailsStore.changes.counter === 0 || isDetailsPopUp) { - handleCancel() - } - }, [detailsStore.changes.counter, handleCancel, isDetailsPopUp]) - - return ( -
      -
      -

      - {isDetailsScreen && !pageData.details.hideBackBtn && !isDetailsPopUp && ( - - - - - - )} - } + const renderTitle = useCallback(() => { + return ( + <> + {isDetailsScreen && !pageData.details.hideBackBtn && !isDetailsPopUp && ( + - {selectedItem.name || selectedItem.db_key} - -

      -
      - {/*In the Workflow page we display both Jobs and Functions items. The function contains `updated` property. + + + + + )} + }> + {selectedItem.name || selectedItem.db_key} + + + ) + }, [ + isDetailsScreen, + pageData.details.hideBackBtn, + isDetailsPopUp, + getCloseDetailsLink, + selectedItem.name, + handleBackClick, + selectedItem.db_key + ]) + + const renderStatus = useCallback(() => { + return ( + <> + {/*In the Workflow page we display both Jobs and Functions items. The function contains `updated` property. The job contains startTime property.*/} -
      - - {Object.keys(selectedItem).length > 0 && - pageData.page === JOBS_PAGE && - !selectedItem?.updated - ? formatDatetime( - selectedItem?.startTime, - stateValue === 'aborted' ? 'N/A' : 'Not yet started' - ) - : selectedItem?.updated - ? formatDatetime(selectedItem?.updated, 'N/A') - : pageData.details.additionalHeaderInfo || ''} - - {stateValue && stateLabel && ( - }> - - - )} -
      -
      - {selectedItem.ui?.customError?.title && selectedItem.ui?.customError?.message && ( - - } - > - {selectedItem.ui.customError.title} {selectedItem.ui.customError.message} - - )} - {errorMessage && ( - } - > - {errorMessage} - - )} - {!isEmpty(podsData?.podsPending) && ( - - {`${podsData.podsPending.length} of ${podsData.podsList.length} pods are pending`} - - )} - {detailsStore.pods.error && ( - Failed to load pods - )} -
      - {selectedItem.ui?.infoMessage && ( -
      -
      - - } - > - {selectedItem.ui.infoMessage} - -
      -
      +
      + + {Object.keys(selectedItem).length > 0 && + pageData.page === JOBS_PAGE && + !selectedItem?.updated + ? formatDatetime( + selectedItem?.startTime, + state.value === 'aborted' ? 'N/A' : 'Not yet started' + ) + : selectedItem?.updated + ? formatDatetime(selectedItem?.updated, 'N/A') + : pageData.details.additionalHeaderInfo || ''} + + {state.value && state.label && ( + }> + + )}
      -
      -
      - {params.tab === DETAILS_ARTIFACTS_TAB && detailsStore.iteration && !isDetailsPopUp && ( - { + dispatch(setIteration(option)) + }} + options={detailsStore.iterationOptions} + selectedId={detailsStore.iteration} + /> + ) + ) + }, [params.tab, detailsStore.iteration, detailsStore.iterationOptions, isDetailsPopUp, dispatch]) + + return ( + ) } diff --git a/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx b/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx index 1d1dceec11..3881824ea8 100644 --- a/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx +++ b/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx @@ -1,7 +1,9 @@ import { useCallback, useState } from 'react' -import { ARGUMENTS_TAB, PROMPT_TAB } from '../../../constants' + import PromptTab from './PromptTab' +import { ARGUMENTS_TAB, PROMPT_TAB } from '../../../constants' + import './detailsPromptTemplate.scss' const DetailsPromptTemplate = () => { diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx index fd200c7f71..bd8c739130 100644 --- a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -20,9 +20,9 @@ such restriction. import { useState } from 'react' import PropTypes from 'prop-types' +import { CopyToClipboard } from 'igz-controls/components' import ContentMenu from '../../../elements/ContentMenu/ContentMenu' import SearchNavigator from '../../../common/SearchNavigator/SearchNavigator' -import CopyToClipboard from '../../../common/CopyToClipboard/CopyToClipboard' import Copy from 'igz-controls/images/copy-to-clipboard-icon.svg?react' diff --git a/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx b/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx index 3ad0c8f926..91dea08197 100644 --- a/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx +++ b/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx @@ -22,12 +22,13 @@ import PropTypes from 'prop-types' import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' -import DetailsDrillDownAlert from '../../DetailsDrillDownAlert/DetailsDrillDownAlert' import DetailsAlerts from '../../DetailsAlerts/DetailsAlerts' import DetailsAnalysis from '../../DetailsAnalysis/DetailsAnalysis' import DetailsArtifacts from '../../DetailsArtifacts/DetailsArtifacts' import DetailsCode from '../../DetailsCode/DetailsCode' +import DetailsCollections from '../../DetailsCollections/DetailsCollections' import DetailsDriftAnalysis from '../../DetailsDriftAnalysis/DetailsDriftAnalysis' +import DetailsDrillDownAlert from '../../DetailsDrillDownAlert/DetailsDrillDownAlert' import DetailsFeatureAnalysis from '../../DetailsFeaturesAnalysis/DetailsFeaturesAnalysis' import DetailsInfo from '../../DetailsInfo/DetailsInfo' import DetailsInputs from '../../DetailsInputs/DetailsInputs' @@ -36,18 +37,16 @@ import DetailsMetadata from '../../DetailsMetadata/DetailsMetadata' import DetailsMetrics from '../../DetailsMetrics/DetailsMetrics' import DetailsPods from '../../DetailsPods/DetailsPods' import DetailsPreview from '../../DetailsPreview/DetailsPreview' +import DetailsPromptTemplate from '../DetailsPromptTemplate/DetailsPromptTemplate' import DetailsRequestedFeatures from '../../DetailsRequestedFeatures/DetailsRequestedFeatures' import DetailsResults from '../../DetailsResults/DetailsResults' import DetailsStatistics from '../../DetailsStatistics/DetailsStatistics' import DetailsTransformations from '../../DetailsTransformations/DetailsTransformations' import NoData from '../../../common/NoData/NoData' -import DetailsCollections from '../../DetailsCollections/DetailsCollections' - -import { isJobKindDask, JOB_STEADY_STATES } from '../../Jobs/jobs.util' import { - DETAILS_ALERT_APPLICATION, DETAILS_ALERTS_TAB, + DETAILS_ALERT_APPLICATION, DETAILS_ANALYSIS_TAB, DETAILS_ARTIFACTS_TAB, DETAILS_BUILD_LOG_TAB, @@ -70,7 +69,7 @@ import { DETAILS_STATISTICS_TAB, DETAILS_TRANSFORMATIONS_TAB } from '../../../constants' -import DetailsPromptTemplate from '../DetailsPromptTemplate/DetailsPromptTemplate' +import { isJobKindDask, JOB_STEADY_STATES } from '../../Jobs/jobs.util' const DetailsTabsContent = ({ applyChangesRef, @@ -82,13 +81,14 @@ const DetailsTabsContent = ({ selectedItem }) => { const detailsStore = useSelector(store => store.detailsStore) + const commonDetailsStore = useSelector(store => store.commonDetailsStore) const params = useParams() switch (isDetailsPopUp ? detailsPopUpSelectedTab : params.tab) { case DETAILS_OVERVIEW_TAB: return ( * { - margin: 0; - } - } - - &__navigation-buttons { - display: flex; - } - - &__pods { - &-error { - color: colors.$spunPearl; - } - } - - &__data { - flex: 1 0 0; - min-width: 250px; - margin-right: auto; - - h3 { - margin: 0 0 5px 0; - font-size: 24px; - line-height: 28px; - } - - .state { - display: inline-block; - min-width: 18px; - - i { - margin: 0 10px 0 5px; - } - } - - .error-container { - flex: 1; - margin-left: 0; - - &:not(:last-child) { - margin-right: 1em; - padding-right: 1em; - border-right: borders.$secondaryBorder; - } - } - } - - &__custom-elements { - z-index: 7; - display: flex; - align-items: center; - margin-right: 10px; - } - - &__buttons { - z-index: 7; - display: flex; - align-items: center; - - a { - display: inline-block; - margin: 21px 21px 21px 10px; - - &.details-close-btn { - margin: 0; - } - } - - .btn { - margin: 0 0.2rem; - } - - .table-actions-container { - display: block; - } - - .actions-menu { - &__container { - display: block; - - .btn { - padding: 0; - border: none; - - &:hover { - background-color: transparent; - } - - :first-child { - margin-right: 0; - } - } - } - } - - .details-date-picker { - margin-right: 12px; - } - } - } - - &__content { - border-top: borders.$secondaryBorder; - } - } - - &_inputs { - width: 100%; - - @include mixins.resetSpaces; - - &_item { - display: flex; - flex-direction: row; - align-items: center; - padding: 27px 24px; - border-bottom: borders.$secondaryBorder; - - div { - min-width: 237px; - padding: 0 5px; - } - } - } - - &-logs { - position: relative; - display: flex; - flex: 1; - width: 100%; - min-height: 200px; - padding: 10px 0; - color: colors.$white; - font-family: 'Source Code Pro', 'Courier New', monospace; - white-space: pre-wrap; - background-color: colors.$black; - - &:not(:last-child) { - margin-bottom: 10px; - } - - &-container { - display: flex; - flex-direction: column; - height: 100%; - } - - &-content { - width: 100%; - height: 100%; - padding: 0 10px; - overflow-y: scroll; - - /* Define the thumb style */ - &::-webkit-scrollbar-thumb { - background: colors.$doveGray; - border-radius: 5px; - } - } - - &-panel { - padding: 0 10px; - - .logs-refresh { - .btn { - min-width: 40px; - padding: 0; - border-radius: 50%; - - & > * { - margin: 0; - } - } - } - - .logs-loader { - width: 40px; - height: 40px; - } - } - } - - &_artifacts { - display: flex; - flex: 1; - flex-direction: column; - - &_wrapper { - width: 100%; - } - } - - .details-item { - &__buttons-block { - display: flex; - } - - &__apply-btn-wrapper { - width: 30px; - } - - &__apply-btn { - display: block; - min-width: 30px; - height: 30px; - margin: 0; - padding: 0; - } - } - - .preview_container { - display: flex; - flex-flow: column; - width: 100%; - height: 100%; - - &__header { - display: flex; - justify-content: space-between; - - &-text { - align-self: center; - } - } - - .inputs_container { - width: 100%; - } - - .accordion { - &__container { - &.open { - .accordion__body { - overflow: initial; - } - } - } - } - - .preview { - &_popout { - margin: 0; - padding: 0; - background: colors.$white; - border: none; - outline: none; - cursor: pointer; - } - } - - .json { - padding: 0 15px; - } - - .preview-table { - display: flex; - flex: 1; - flex-direction: column; - overflow: auto; - - .table-header { - top: 0; - } - } - } - - &_code { - flex: 1; - overflow: auto; - - h3 { - text-align: center; - vertical-align: middle; - } - - pre { - padding: 8px 16px; - white-space: pre-wrap; - word-break: break-word; - } - } - - &.pop-up-dialog-opened { - overflow-y: hidden; - } - - .chips { - &-wrapper { - flex-wrap: wrap; - width: 100%; - } - } - } -} diff --git a/src/components/Details/details.util.js b/src/components/Details/details.util.js index 762e6c05ed..0d2f37bbd7 100644 --- a/src/components/Details/details.util.js +++ b/src/components/Details/details.util.js @@ -42,16 +42,17 @@ import { MODELS_TAB, TAG_LATEST } from '../../constants' -import { formatDatetime, generateLinkPath, parseUri } from '../../utils' +import { generateLinkPath, parseUri } from '../../utils' import { isArtifactTagUnique } from '../../utils/artifacts.util' import { getFunctionImage } from '../FunctionsPage/functions.util' import { openPopUp } from 'igz-controls/utils/common.util' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import { setChangesCounter, setChangesData, setFiltersWasHandled, showWarning -} from '../../reducers/detailsReducer' +} from 'igz-controls/reducers/commonDetailsReducer' export const generateArtifactsContent = ( detailsType, @@ -147,10 +148,10 @@ export const generateArtifactsContent = ( ] } }, - handleDiscardChanges: (formState, detailsStore) => { + handleDiscardChanges: (formState, commonDetailsStore) => { formState.form.change( 'tag', - detailsStore.changes.data.tag?.currentFieldValue ?? formState.initialValues.tag + commonDetailsStore.changes.data.tag?.currentFieldValue ?? formState.initialValues.tag ) } }, @@ -407,10 +408,10 @@ export const generateFeatureSetsOverviewContent = (selectedItem, isDetailsPopUp) fieldData: { name: 'description' }, - handleDiscardChanges: (formState, detailsStore) => { + handleDiscardChanges: (formState, commonDetailsStore) => { formState.form.change( 'description', - detailsStore.changes.data.description?.currentFieldValue ?? + commonDetailsStore.changes.data.description?.currentFieldValue ?? formState.initialValues.description ) } @@ -462,10 +463,10 @@ export const generateFeatureVectorsOverviewContent = (selectedItem, isDetailsPop fieldData: { name: 'description' }, - handleDiscardChanges: (formState, detailsStore) => { + handleDiscardChanges: (formState, commonDetailsStore) => { formState.form.change( 'description', - detailsStore.changes.data.description?.currentFieldValue ?? + commonDetailsStore.changes.data.description?.currentFieldValue ?? formState.initialValues.description ) } diff --git a/src/components/DetailsArtifacts/DetailsArtifacts.jsx b/src/components/DetailsArtifacts/DetailsArtifacts.jsx index f123c239fd..553b216964 100644 --- a/src/components/DetailsArtifacts/DetailsArtifacts.jsx +++ b/src/components/DetailsArtifacts/DetailsArtifacts.jsx @@ -24,9 +24,8 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import ArtifactsPreviewController from '../ArtifactsPreview/ArtifactsPreviewController' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' -import { TextTooltipTemplate, Tooltip, Tip } from 'igz-controls/components' +import { TextTooltipTemplate, Tooltip, Tip, Loader } from 'igz-controls/components' import { generateArtifactsPreviewContent, @@ -37,7 +36,7 @@ import { ALLOW_SORT_BY, DEFAULT_SORT_BY, EXCLUDE_SORT_BY } from 'igz-controls/ty import { fetchArtifacts } from '../../reducers/artifactsReducer' import { fetchJob } from '../../reducers/jobReducer' import { generateArtifactIdentifiers } from '../Details/details.util' -import { getChipLabelAndValue } from '../../utils/getChipLabelAndValue' +import { getChipLabelAndValue } from 'igz-controls/utils/chips.util' import { setIteration, setIterationOption } from '../../reducers/detailsReducer' import { useSortTable } from '../../hooks/useSortTable.hook' @@ -280,7 +279,7 @@ DetailsArtifacts.propTypes = { excludeSortBy: EXCLUDE_SORT_BY, isDetailsPopUp: PropTypes.bool, iteration: PropTypes.string.isRequired, - selectedItem: PropTypes.object.isRequired, + selectedItem: PropTypes.object.isRequired } export default DetailsArtifacts diff --git a/src/components/DetailsArtifacts/detailsArtifacts.util.jsx b/src/components/DetailsArtifacts/detailsArtifacts.util.jsx index ace8668040..b90ab6a625 100644 --- a/src/components/DetailsArtifacts/detailsArtifacts.util.jsx +++ b/src/components/DetailsArtifacts/detailsArtifacts.util.jsx @@ -19,13 +19,13 @@ such restriction. */ import prettyBytes from 'pretty-bytes' -import CopyToClipboard from '../../common/CopyToClipboard/CopyToClipboard' +import { RoundedIcon, TextTooltipTemplate, Tooltip, CopyToClipboard } from 'igz-controls/components' import Download from '../../common/Download/Download' -import { RoundedIcon, TextTooltipTemplate, Tooltip } from 'igz-controls/components' import ArtifactPopUp from '../../elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp' import { openPopUp } from 'igz-controls/utils/common.util' -import { formatDatetime, parseKeyValues } from '../../utils' +import { formatDatetime } from 'igz-controls/utils/datetime.util' +import { parseKeyValues } from '../../utils' import { parseArtifacts } from '../../utils/parseArtifacts' import DetailsIcon from 'igz-controls/images/view-details.svg?react' diff --git a/src/components/DetailsDriftAnalysis/detailsDriftAnalysis.util.js b/src/components/DetailsDriftAnalysis/detailsDriftAnalysis.util.js index 58c52a9e2f..8f2f8a7b03 100644 --- a/src/components/DetailsDriftAnalysis/detailsDriftAnalysis.util.js +++ b/src/components/DetailsDriftAnalysis/detailsDriftAnalysis.util.js @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { roundFloats } from '../../utils/roundFloats' +import { roundFloats } from 'igz-controls/utils/common.util' export const generateDriftAnalysis = measures => { measures ??= {} diff --git a/src/components/DetailsDrillDownAlert/DetailsDrillDownAlert.jsx b/src/components/DetailsDrillDownAlert/DetailsDrillDownAlert.jsx index f797a7c9f1..c7f3ac3a32 100644 --- a/src/components/DetailsDrillDownAlert/DetailsDrillDownAlert.jsx +++ b/src/components/DetailsDrillDownAlert/DetailsDrillDownAlert.jsx @@ -34,7 +34,7 @@ import EnlargeIcon from 'igz-controls/images/ml-enlarge.svg?react' import '../DetailsInfo/detailsInfo.scss' const DetailsDrillDownAlert = React.forwardRef( - ({ detailsStore, formState, isDetailsPopUp, pageData, selectedItem }, applyChangesRef) => { + ({ commonDetailsStore, formState, isDetailsPopUp, pageData, selectedItem }, applyChangesRef) => { const openAlertsLogsModal = useCallback(() => { openPopUp(AlertLogsModal, { selectedItem, pageData }) }, [pageData, selectedItem]) @@ -42,7 +42,7 @@ const DetailsDrillDownAlert = React.forwardRef( return ( <> { + ({ commonDetailsStore, formState, isDetailsPopUp, pageData, selectedItem }, applyChangesRef) => { const location = useLocation() const [detailsInfoState, detailsInfoDispatch] = useReducer(detailsInfoReducer, initialState) const params = useParams() @@ -128,7 +128,7 @@ const DetailsInfo = React.forwardRef( dispatch(setEditMode(false)) return handleFinishEdit( - detailsStore.changes, + commonDetailsStore.changes, detailsInfoActions, detailsInfoDispatch, currentField, @@ -136,7 +136,7 @@ const DetailsInfo = React.forwardRef( dispatch ) }, - [detailsStore.changes, dispatch, formState] + [commonDetailsStore.changes, dispatch, formState] ) return ( @@ -144,7 +144,7 @@ const DetailsInfo = React.forwardRef( additionalInfo={{ alerts, configuration, document_loader, drift, producer, sources }} detailsInfoDispatch={detailsInfoDispatch} detailsInfoState={detailsInfoState} - detailsStore={detailsStore} + commonDetailsStore={commonDetailsStore} formState={formState} handleDiscardChanges={handleDiscardChanges} handleFinishEdit={finishEdit} @@ -162,7 +162,7 @@ const DetailsInfo = React.forwardRef( DetailsInfo.displayName = 'DetailsInfo' DetailsInfo.propTypes = { - detailsStore: PropTypes.object.isRequired, + commonDetailsStore: PropTypes.object.isRequired, formState: PropTypes.object.isRequired, isDetailsPopUp: PropTypes.bool.isRequired, pageData: PropTypes.object.isRequired, diff --git a/src/components/DetailsInfo/DetailsInfoView.jsx b/src/components/DetailsInfo/DetailsInfoView.jsx index 4b8defee30..fd99725b73 100644 --- a/src/components/DetailsInfo/DetailsInfoView.jsx +++ b/src/components/DetailsInfo/DetailsInfoView.jsx @@ -41,7 +41,7 @@ import { MODELS_PAGE } from '../../constants' import { parseKeyValues } from '../../utils' -import { getChipOptions } from '../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import RightArrow from 'igz-controls/images/ic_arrow-right.svg?react' @@ -58,7 +58,7 @@ const DetailsInfoView = React.forwardRef( }, detailsInfoDispatch, detailsInfoState, - detailsStore, + commonDetailsStore, formState, handleDiscardChanges, handleFinishEdit, @@ -71,8 +71,8 @@ const DetailsInfoView = React.forwardRef( ref ) => { const infoContent = useMemo( - () => (isDetailsPopUp ? detailsStore.detailsPopUpInfoContent : detailsStore.infoContent), - [detailsStore.infoContent, detailsStore.detailsPopUpInfoContent, isDetailsPopUp] + () => (isDetailsPopUp ? commonDetailsStore.detailsPopUpInfoContent : commonDetailsStore.infoContent), + [commonDetailsStore.infoContent, commonDetailsStore.detailsPopUpInfoContent, isDetailsPopUp] ) const wrapperClassNames = classnames( !isEveryObjectValueEmpty(additionalInfo) @@ -160,8 +160,8 @@ const DetailsInfoView = React.forwardRef( chipsData.delimiter = } - info = !isNil(detailsStore.changes.data[header.id]) - ? detailsStore.changes.data[header.id].currentFieldValue + info = !isNil(commonDetailsStore.changes.data[header.id]) + ? commonDetailsStore.changes.data[header.id].currentFieldValue : selectedItem && infoContent[header.id]?.value } else if (pageData.page === FUNCTIONS_PAGE) { info = @@ -269,7 +269,7 @@ DetailsInfoView.propTypes = { }), detailsInfoDispatch: PropTypes.func.isRequired, detailsInfoState: PropTypes.object.isRequired, - detailsStore: PropTypes.object.isRequired, + commonDetailsStore: PropTypes.object.isRequired, formState: PropTypes.object, handleDiscardChanges: PropTypes.func.isRequired, handleFinishEdit: PropTypes.func.isRequired, diff --git a/src/components/DetailsInfo/detailsInfo.util.jsx b/src/components/DetailsInfo/detailsInfo.util.jsx index 3c1c749fab..c2bb649bc3 100644 --- a/src/components/DetailsInfo/detailsInfo.util.jsx +++ b/src/components/DetailsInfo/detailsInfo.util.jsx @@ -34,14 +34,15 @@ import { MODEL_ENDPOINTS_TAB, MLRUN_STORAGE_INPUT_PATH_SCHEME } from '../../constants' -import { formatDatetime, parseKeyValues, parseUri } from '../../utils' +import { parseKeyValues, parseUri } from '../../utils' import { getTriggerCriticalTimePeriod } from '../../utils/createAlertsContent' -import { getChipOptions } from '../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import { getLimitsGpuType } from '../../elements/FormResourcesUnits/formResourcesUnits.util' import { isEveryObjectValueEmpty } from '../../utils/isEveryObjectValueEmpty' -import { roundFloats } from '../../utils/roundFloats' +import { roundFloats } from 'igz-controls/utils/common.util' import { generateFunctionPriorityLabel } from '../../utils/generateFunctionPriorityLabel' import { openPopUp } from 'igz-controls/utils/common.util' +import { formatDatetime } from 'igz-controls/utils/datetime.util' export const generateTriggerInfoContent = criteria => { if (criteria) { diff --git a/src/components/DetailsInputs/DetailsInputs.jsx b/src/components/DetailsInputs/DetailsInputs.jsx index 6b5efbc228..178dc7004e 100644 --- a/src/components/DetailsInputs/DetailsInputs.jsx +++ b/src/components/DetailsInputs/DetailsInputs.jsx @@ -25,9 +25,8 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import ArtifactsPreviewController from '../ArtifactsPreview/ArtifactsPreviewController' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import { ARTIFACT_OTHER_TYPE, diff --git a/src/components/DetailsInputs/detailsInputs.util.jsx b/src/components/DetailsInputs/detailsInputs.util.jsx index f83167b95d..cf29606217 100644 --- a/src/components/DetailsInputs/detailsInputs.util.jsx +++ b/src/components/DetailsInputs/detailsInputs.util.jsx @@ -20,8 +20,7 @@ such restriction. import React from 'react' import classnames from 'classnames' -import CopyToClipboard from '../../common/CopyToClipboard/CopyToClipboard' -import { RoundedIcon, TextTooltipTemplate, Tooltip } from 'igz-controls/components' +import { RoundedIcon, TextTooltipTemplate, Tooltip, CopyToClipboard } from 'igz-controls/components' import ArtifactPopUp from '../../elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp' import FeatureVectorPopUp from '../../elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp' diff --git a/src/components/DetailsLogs/Logs.jsx b/src/components/DetailsLogs/Logs.jsx index b9ee49f02c..3d5110b9f1 100644 --- a/src/components/DetailsLogs/Logs.jsx +++ b/src/components/DetailsLogs/Logs.jsx @@ -20,8 +20,7 @@ such restriction. import React from 'react' import PropTypes from 'prop-types' -import { Button } from 'igz-controls/components' -import Loader from '../../common/Loader/Loader' +import { Button, Loader } from 'igz-controls/components' import NoData from '../../common/NoData/NoData' import RefreshIcon from 'igz-controls/images/refresh.svg?react' diff --git a/src/components/DetailsMetadata/DetailsMetadata.jsx b/src/components/DetailsMetadata/DetailsMetadata.jsx index 124eaba663..3e25ce7878 100644 --- a/src/components/DetailsMetadata/DetailsMetadata.jsx +++ b/src/components/DetailsMetadata/DetailsMetadata.jsx @@ -21,9 +21,8 @@ import React from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import ChipCell from '../../common/ChipCell/ChipCell' import NoData from '../../common/NoData/NoData' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, ChipCell } from 'igz-controls/components' import { generateMetadata } from './detailsMetadata.util' diff --git a/src/components/DetailsPods/DetailsPods.jsx b/src/components/DetailsPods/DetailsPods.jsx index 003bcd448c..b947d8b8bd 100644 --- a/src/components/DetailsPods/DetailsPods.jsx +++ b/src/components/DetailsPods/DetailsPods.jsx @@ -23,10 +23,9 @@ import { useSelector } from 'react-redux' import Prism from 'prismjs' import classnames from 'classnames' import { useParams } from 'react-router-dom' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import { generatePods } from './detailsPods.util' diff --git a/src/components/DetailsRequestedFeatures/DetailsRequestedFeatures.jsx b/src/components/DetailsRequestedFeatures/DetailsRequestedFeatures.jsx index 0c15405821..7c195c2563 100644 --- a/src/components/DetailsRequestedFeatures/DetailsRequestedFeatures.jsx +++ b/src/components/DetailsRequestedFeatures/DetailsRequestedFeatures.jsx @@ -24,8 +24,12 @@ import { useDispatch } from 'react-redux' import DetailsRequestedFeaturesView from './DetailsRequestedFeaturesView' +import { + setChanges, + setChangesCounter, + setChangesData +} from 'igz-controls/reducers/commonDetailsReducer' import { countChanges } from '../Details/details.util' -import { setChanges, setChangesCounter, setChangesData } from '../../reducers/detailsReducer' const DetailsRequestedFeatures = ({ changes, formState, isDetailsPopUp = false, selectedItem }) => { const [confirmDialogData, setConfirmDialogData] = useState({ diff --git a/src/components/DetailsResults/DetailsResults.jsx b/src/components/DetailsResults/DetailsResults.jsx index 35b2f94956..2f404e92c7 100644 --- a/src/components/DetailsResults/DetailsResults.jsx +++ b/src/components/DetailsResults/DetailsResults.jsx @@ -25,7 +25,7 @@ import classNames from 'classnames' import NoData from '../../common/NoData/NoData' import { Tip, Tooltip, TextTooltipTemplate } from 'igz-controls/components' -import { roundFloats } from '../../utils/roundFloats' +import { roundFloats } from 'igz-controls/utils/common.util' import { generateResultsContent } from '../../utils/resultsTable' import { useSortTable } from '../../hooks/useSortTable.hook' import { ALLOW_SORT_BY, DEFAULT_SORT_BY, EXCLUDE_SORT_BY } from 'igz-controls/types' diff --git a/src/components/DetailsStatistics/detailsStatistics.util.jsx b/src/components/DetailsStatistics/detailsStatistics.util.jsx index 53ae6f0a14..5d137d742b 100644 --- a/src/components/DetailsStatistics/detailsStatistics.util.jsx +++ b/src/components/DetailsStatistics/detailsStatistics.util.jsx @@ -21,7 +21,7 @@ import React from 'react' import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' -import { roundFloats } from '../../utils/roundFloats' +import { roundFloats } from 'igz-controls/utils/common.util' import Primary from 'igz-controls/images/ic-key.svg?react' import LabelColumn from 'igz-controls/images/ic_target-with-dart.svg?react' diff --git a/src/components/DetailsTransformations/ConfigSource/ConfigSource.jsx b/src/components/DetailsTransformations/ConfigSource/ConfigSource.jsx index c65374b8f4..9f9041b826 100644 --- a/src/components/DetailsTransformations/ConfigSource/ConfigSource.jsx +++ b/src/components/DetailsTransformations/ConfigSource/ConfigSource.jsx @@ -23,8 +23,7 @@ import { map } from 'lodash' import cronstrue from 'cronstrue' import Accordion from '../../../common/Accordion/Accordion' -import ChipCell from '../../../common/ChipCell/ChipCell' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, ChipCell } from 'igz-controls/components' import Arrow from 'igz-controls/images/arrow.svg?react' diff --git a/src/components/Documents/documents.util.jsx b/src/components/Documents/documents.util.jsx index 1fa571f1c9..d7f48a7005 100644 --- a/src/components/Documents/documents.util.jsx +++ b/src/components/Documents/documents.util.jsx @@ -23,21 +23,24 @@ import { cloneDeep, isEmpty, omit } from 'lodash' import { ARTIFACT_MAX_DOWNLOAD_SIZE, DOCUMENT_TYPE, - DOCUMENTS_PAGE, - FULL_VIEW_MODE + DOCUMENTS_PAGE } from '../../constants' +import { + openDeleteConfirmPopUp, + openPopUp, + getErrorMsg, + copyToClipboard +} from 'igz-controls/utils/common.util' import { getIsTargetPathValid } from '../../utils/createArtifactsContent' import { applyTagChanges, chooseOrFetchArtifact } from '../../utils/artifacts.util' import { setDownloadItem, setShowDownloadsList } from '../../reducers/downloadReducer' -import { copyToClipboard } from '../../utils/copyToClipboard' import { generateUri } from '../../utils/resources' import DeleteArtifactPopUp from '../../elements/DeleteArtifactPopUp/DeleteArtifactPopUp' import { handleDeleteArtifact } from '../../utils/handleDeleteArtifact' -import { openDeleteConfirmPopUp, openPopUp, getErrorMsg } from 'igz-controls/utils/common.util' -import { FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' +import { FORBIDDEN_ERROR_STATUS_CODE, FULL_VIEW_MODE } from 'igz-controls/constants' import { convertChipsData } from '../../utils/convertChipsData' import { updateArtifact } from '../../reducers/artifactsReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import TagIcon from 'igz-controls/images/tag-icon.svg?react' import YamlIcon from 'igz-controls/images/yaml.svg?react' diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanel.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanel.jsx index 63ad5ad080..b864ff6c12 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanel.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanel.jsx @@ -29,7 +29,7 @@ import arrayMutators from 'final-form-arrays' import FeatureSetsPanelView from './FeatureSetsPanelView' import { FEATURE_SETS_TAB, TAG_FILTER_LATEST } from '../../constants' -import { setNotification } from '../../reducers/notificationReducer' +import { setNotification } from 'igz-controls/reducers/notificationReducer' import { checkValidation } from './featureSetPanel.util' import { setFieldState } from 'igz-controls/utils/form.util' import { diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelTableRow/FeatureSetsPanelTableRow.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanelTableRow/FeatureSetsPanelTableRow.jsx index 29b1ecf17b..98f184f9ff 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelTableRow/FeatureSetsPanelTableRow.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelTableRow/FeatureSetsPanelTableRow.jsx @@ -22,10 +22,9 @@ import PropTypes from 'prop-types' import { map } from 'lodash' import classnames from 'classnames' -import ActionsMenu from '../../../common/ActionsMenu/ActionsMenu' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, ActionsMenu } from 'igz-controls/components' -import { ACTIONS_MENU } from '../../../types' +import { ACTIONS_MENU } from 'igz-controls/types' const FeatureSetsPanelTableRow = ({ actionButton = null, diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStoreView.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStoreView.jsx index ee0bd4454d..b54d59366b 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStoreView.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStoreView.jsx @@ -23,13 +23,18 @@ import { CSSTransition } from 'react-transition-group' import classNames from 'classnames' import CheckBox from '../../../common/CheckBox/CheckBox' -import ErrorMessage from '../../../common/ErrorMessage/ErrorMessage' import FeatureSetsPanelSection from '../FeatureSetsPanelSection/FeatureSetsPanelSection' import Input from '../../../common/Input/Input' import PartitionFields from '../../../elements/PartitionFields/PartitionFields' import Select from '../../../common/Select/Select' import UrlPath from '../UrlPath' -import { Tip, Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' +import { + Tip, + Tooltip, + TextTooltipTemplate, + RoundedIcon, + ErrorMessage +} from 'igz-controls/components' import { MLRUN_STORAGE_INPUT_PATH_SCHEME, diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelTitle/FeatureSetsPanelTitleView.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanelTitle/FeatureSetsPanelTitleView.jsx index 660612adf4..a4b4c17296 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelTitle/FeatureSetsPanelTitleView.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelTitle/FeatureSetsPanelTitleView.jsx @@ -30,7 +30,7 @@ import { getValidationRules, getInternalLabelsValidationRule } from 'igz-controls/utils/validation.util' -import { getChipOptions } from '../../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import CloseIcon from 'igz-controls/images/close.svg?react' diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelView.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanelView.jsx index 959c3949f9..2f41404f3b 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelView.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelView.jsx @@ -26,9 +26,8 @@ import FeatureSetsPanelDataSource from './FeatureSetsPanelDataSource/FeatureSets import FeatureSetsPanelSchema from './FeatureSetsPanelSchema/FeatureSetsPanelSchema' import FeatureSetsPanelTargetStore from './FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStore' import FeatureSetsPanelTitle from './FeatureSetsPanelTitle/FeatureSetsPanelTitle' -import Loader from '../../common/Loader/Loader' import PanelCredentialsAccessKey from '../../elements/PanelCredentialsAccessKey/PanelCredentialsAccessKey' -import { Button, ConfirmDialog } from 'igz-controls/components' +import { Button, ConfirmDialog, Loader } from 'igz-controls/components' import { PRIMARY_BUTTON, TERTIARY_BUTTON, LABEL_BUTTON } from 'igz-controls/constants' import { setNewFeatureSetCredentialsAccessKey } from '../../reducers/featureStoreReducer' diff --git a/src/components/FeatureSetsPanel/ScheduleFeatureSet/ScheduleFeatureSet.jsx b/src/components/FeatureSetsPanel/ScheduleFeatureSet/ScheduleFeatureSet.jsx index c9f4b5f50c..95f0743943 100644 --- a/src/components/FeatureSetsPanel/ScheduleFeatureSet/ScheduleFeatureSet.jsx +++ b/src/components/FeatureSetsPanel/ScheduleFeatureSet/ScheduleFeatureSet.jsx @@ -22,12 +22,12 @@ import PropTypes from 'prop-types' import ScheduleFeatureSetView from './ScheduleFeatureSetView' -import { tabs } from './scheduleFeatureSet.util' -import { initialState, recurringReducer, scheduleActionType } from './recurringReducer' import { decodeLocale, getWeekDays, getWeekStart } from '../../../utils/datePicker.util' -import { getFormatTime } from '../../../utils' import { generateCronInitialValue } from '../../../utils/generateCronInitialValue' import { getDefaultSchedule } from '../../../utils/getDefaultSchedule' +import { getFormatTime } from 'igz-controls/utils/datetime.util' +import { initialState, recurringReducer, scheduleActionType } from './recurringReducer' +import { tabs } from './scheduleFeatureSet.util' const ScheduleFeatureSet = ({ defaultCron = '', setNewFeatureSetSchedule, setShowSchedule }) => { const [activeTab, setActiveTab] = useState(tabs[0].id) diff --git a/src/components/FeatureSetsPanel/ScheduleFeatureSet/ScheduleFeatureSetView.jsx b/src/components/FeatureSetsPanel/ScheduleFeatureSet/ScheduleFeatureSetView.jsx index 10231586da..4008979181 100644 --- a/src/components/FeatureSetsPanel/ScheduleFeatureSet/ScheduleFeatureSetView.jsx +++ b/src/components/FeatureSetsPanel/ScheduleFeatureSet/ScheduleFeatureSetView.jsx @@ -21,10 +21,9 @@ import React from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import ErrorMessage from '../../../common/ErrorMessage/ErrorMessage' import ScheduleFeatureSetSimple from '../ScheduleFeatureSetSimple/ScheduleFeatureSetSimple' import ScheduleCron from '../../ScheduleCron/ScheduleCron' -import { Button, RoundedIcon } from 'igz-controls/components' +import { Button, RoundedIcon, ErrorMessage } from 'igz-controls/components' import { tabs } from './scheduleFeatureSet.util' import { PRIMARY_BUTTON } from 'igz-controls/constants' diff --git a/src/components/FeatureSetsPanel/UrlPath.utils.js b/src/components/FeatureSetsPanel/UrlPath.utils.js index f560e6c2fa..74de9cfb0c 100644 --- a/src/components/FeatureSetsPanel/UrlPath.utils.js +++ b/src/components/FeatureSetsPanel/UrlPath.utils.js @@ -35,7 +35,7 @@ import { generateArtifactsReferencesList, generateProjectsList } from '../../utils/panelPathScheme' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { fetchArtifact, fetchArtifacts } from '../../reducers/artifactsReducer' import { fetchProjectsNames } from '../../reducers/projectReducer' import { isCommunityEdition } from '../../utils/helper' diff --git a/src/components/FeatureStore/FeatureSets/FeatureSets.jsx b/src/components/FeatureStore/FeatureSets/FeatureSets.jsx index cb97ad0a03..afd62585ad 100644 --- a/src/components/FeatureStore/FeatureSets/FeatureSets.jsx +++ b/src/components/FeatureStore/FeatureSets/FeatureSets.jsx @@ -60,8 +60,8 @@ import { getScssVariableValue } from 'igz-controls/utils/common.util' import { isDetailsTabExists } from '../../../utils/link-helper.util' import { parseChipsData } from '../../../utils/convertChipsData' import { parseFeatureSets } from '../../../utils/parseFeatureSets' -import { setNotification } from '../../../reducers/notificationReducer' -import { sortListByDate } from '../../../utils' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { sortListByDate } from 'igz-controls/utils/datetime.util' import { useFiltersFromSearchParams } from '../../../hooks/useFiltersFromSearchParams.hook' import { useGroupContent } from '../../../hooks/groupContent.hook' import { useInitialTableFetch } from '../../../hooks/useInitialTableFetch.hook' diff --git a/src/components/FeatureStore/FeatureSets/FeatureSetsView.jsx b/src/components/FeatureStore/FeatureSets/FeatureSetsView.jsx index 5ca68e8eb3..3b78f620fa 100644 --- a/src/components/FeatureStore/FeatureSets/FeatureSetsView.jsx +++ b/src/components/FeatureStore/FeatureSets/FeatureSetsView.jsx @@ -21,18 +21,18 @@ import React from 'react' import { useParams } from 'react-router-dom' import PropTypes from 'prop-types' +import { Loader } from 'igz-controls/components' import FeatureSetsPanel from '../../FeatureSetsPanel/FeatureSetsPanel' import FeatureStoreTableRow from '../../../elements/FeatureStoreTableRow/FeatureStoreTableRow' import NoData from '../../../common/NoData/NoData' import Table from '../../Table/Table' import ActionBar from '../../ActionBar/ActionBar' import FeatureStoreFilters from '../FeatureStoreFilters' -import Loader from '../../../common/Loader/Loader' import FeatureStorePageTabs from '../FeatureStorePageTabs/FeatureStorePageTabs' import { FEATURE_SETS_TAB, FEATURE_STORE_PAGE } from '../../../constants' import { PRIMARY_BUTTON } from 'igz-controls/constants' -import { VIRTUALIZATION_CONFIG } from '../../../types' +import { VIRTUALIZATION_CONFIG } from 'igz-controls/types' import { filtersConfig } from './featureSets.util' import { getNoDataMessage } from '../../../utils/getNoDataMessage' import { isRowRendered } from '../../../hooks/useVirtualization.hook' diff --git a/src/components/FeatureStore/FeatureSets/featureSets.util.jsx b/src/components/FeatureStore/FeatureSets/featureSets.util.jsx index 8492f1a4fe..1bddf6a01b 100644 --- a/src/components/FeatureStore/FeatureSets/featureSets.util.jsx +++ b/src/components/FeatureStore/FeatureSets/featureSets.util.jsx @@ -28,7 +28,7 @@ import { TAG_FILTER, TAG_FILTER_LATEST } from '../../../constants' -import { showErrorNotification } from '../../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { fetchFeatureSet } from '../../../reducers/featureStoreReducer' import Yaml from 'igz-controls/images/yaml.svg?react' diff --git a/src/components/FeatureStore/FeatureStore.jsx b/src/components/FeatureStore/FeatureStore.jsx index c399bb4ce5..753179f93a 100644 --- a/src/components/FeatureStore/FeatureStore.jsx +++ b/src/components/FeatureStore/FeatureStore.jsx @@ -21,9 +21,8 @@ import React, { useCallback, useState } from 'react' import { Outlet } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' -import Loader from '../../common/Loader/Loader' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' -import { ConfirmDialog } from 'igz-controls/components' +import { ConfirmDialog, Loader } from 'igz-controls/components' import { TABLE_CONTAINER } from '../../constants' import { toggleYaml } from '../../reducers/appReducer' diff --git a/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx b/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx index a2a249049c..44836a5fbb 100644 --- a/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx +++ b/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx @@ -59,9 +59,9 @@ import { getScssVariableValue } from 'igz-controls/utils/common.util' import { isDetailsTabExists } from '../../../utils/link-helper.util' import { parseFeatureVectors } from '../../../utils/parseFeatureVectors' import { setFeaturesPanelData } from '../../../reducers/tableReducer' -import { setNotification } from '../../../reducers/notificationReducer' -import { showErrorNotification } from '../../../utils/notifications.util' -import { sortListByDate } from '../../../utils' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' +import { sortListByDate } from 'igz-controls/utils/datetime.util' import { useFiltersFromSearchParams } from '../../../hooks/useFiltersFromSearchParams.hook' import { useGroupContent } from '../../../hooks/groupContent.hook' import { useInitialTableFetch } from '../../../hooks/useInitialTableFetch.hook' diff --git a/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.jsx b/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.jsx index d7a87bf793..0bfe8edb0c 100644 --- a/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.jsx +++ b/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.jsx @@ -30,7 +30,7 @@ import Table from '../../Table/Table' import { FEATURE_STORE_PAGE, FEATURE_VECTORS_TAB } from '../../../constants' import { PRIMARY_BUTTON } from 'igz-controls/constants' -import { VIRTUALIZATION_CONFIG } from '../../../types' +import { VIRTUALIZATION_CONFIG } from 'igz-controls/types' import { createFeatureVectorTitle } from '../featureStore.util' import { filtersConfig } from './featureVectors.util' import { getNoDataMessage } from '../../../utils/getNoDataMessage' diff --git a/src/components/FeatureStore/Features/FeaturesView.jsx b/src/components/FeatureStore/Features/FeaturesView.jsx index bb7a51a18e..f1df3f8c2e 100644 --- a/src/components/FeatureStore/Features/FeaturesView.jsx +++ b/src/components/FeatureStore/Features/FeaturesView.jsx @@ -20,20 +20,20 @@ such restriction. import React from 'react' import PropTypes from 'prop-types' +import ActionBar from '../../ActionBar/ActionBar' +import FeatureStoreFilters from '../FeatureStoreFilters' +import FeatureStorePageTabs from '../FeatureStorePageTabs/FeatureStorePageTabs' import FeatureStoreTableRow from '../../../elements/FeatureStoreTableRow/FeatureStoreTableRow' import NoData from '../../../common/NoData/NoData' import Table from '../../Table/Table' -import FeatureStorePageTabs from '../FeatureStorePageTabs/FeatureStorePageTabs' import { FEATURE_STORE_PAGE, FEATURES_TAB } from '../../../constants' import { PRIMARY_BUTTON } from 'igz-controls/constants' -import { VIRTUALIZATION_CONFIG } from '../../../types' +import { VIRTUALIZATION_CONFIG } from 'igz-controls/types' +import { addToFeatureVectorTitle } from '../featureStore.util' import { filtersConfig } from './features.util' import { getNoDataMessage } from '../../../utils/getNoDataMessage' import { isRowRendered } from '../../../hooks/useVirtualization.hook' -import ActionBar from '../../ActionBar/ActionBar' -import FeatureStoreFilters from '../FeatureStoreFilters' -import { addToFeatureVectorTitle } from '../featureStore.util' const FeaturesView = React.forwardRef( ( diff --git a/src/components/FeatureStore/featureStore.util.js b/src/components/FeatureStore/featureStore.util.js index 8486e88eff..f78e296f30 100644 --- a/src/components/FeatureStore/featureStore.util.js +++ b/src/components/FeatureStore/featureStore.util.js @@ -31,8 +31,8 @@ import { } from '../../constants' import { FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' import { convertChipsData } from '../../utils/convertChipsData' -import { showErrorNotification } from '../../utils/notifications.util' -import { truncateUid } from '../../utils' +import { showErrorNotification } from 'igz-controls/utils/notification.util' +import { truncateUid } from 'igz-controls/utils/string.util' import { updateFeatureStoreData } from '../../reducers/featureStoreReducer' export const createFeatureSetTitle = 'Create set' diff --git a/src/components/Files/files.util.jsx b/src/components/Files/files.util.jsx index b151dfcc2c..15c58af40f 100644 --- a/src/components/Files/files.util.jsx +++ b/src/components/Files/files.util.jsx @@ -25,17 +25,16 @@ import { ARTIFACT_MAX_DOWNLOAD_SIZE, ARTIFACT_OTHER_TYPE, ARTIFACT_TYPE, - FILES_PAGE, - FULL_VIEW_MODE + FILES_PAGE } from '../../constants' +import { FULL_VIEW_MODE } from 'igz-controls/constants' import { applyTagChanges, chooseOrFetchArtifact } from '../../utils/artifacts.util' -import { copyToClipboard } from '../../utils/copyToClipboard' -import { getIsTargetPathValid } from '../../utils/createArtifactsContent' -import { showArtifactsPreview } from '../../reducers/artifactsReducer' import { generateUri } from '../../utils/resources' +import { getIsTargetPathValid } from '../../utils/createArtifactsContent' import { handleDeleteArtifact } from '../../utils/handleDeleteArtifact' -import { openDeleteConfirmPopUp, openPopUp } from 'igz-controls/utils/common.util' +import { openDeleteConfirmPopUp, openPopUp, copyToClipboard } from 'igz-controls/utils/common.util' import { setDownloadItem, setShowDownloadsList } from '../../reducers/downloadReducer' +import { showArtifactsPreview } from '../../reducers/artifactsReducer' import TagIcon from 'igz-controls/images/tag-icon.svg?react' import YamlIcon from 'igz-controls/images/yaml.svg?react' diff --git a/src/components/FilterMenu/FilterMenu.jsx b/src/components/FilterMenu/FilterMenu.jsx index ea60c6804c..f190c7520d 100644 --- a/src/components/FilterMenu/FilterMenu.jsx +++ b/src/components/FilterMenu/FilterMenu.jsx @@ -56,7 +56,7 @@ import { filterSelectOptions, tagFilterOptions } from './filterMenu.settings' import { generateProjectsList } from '../../utils/projects' import { getDefaultCloseDetailsLink } from '../../utils/link-helper.util' import { removeFilters, setFilterProjectOptions, setFilters } from '../../reducers/filtersReducer' -import { setFiltersWasHandled, showWarning } from '../../reducers/detailsReducer' +import { setFiltersWasHandled, showWarning } from 'igz-controls/reducers/commonDetailsReducer' import './filterMenu.scss' @@ -84,7 +84,7 @@ const FilterMenu = ({ const dispatch = useDispatch() const filtersStore = useSelector(store => store.filtersStore) const projectStore = useSelector(store => store.projectStore) - const changes = useSelector(store => store.detailsStore.changes) + const changes = useSelector(store => store.commonDetailsStore.changes) useEffect(() => { setLabels(filtersStore.labels) diff --git a/src/components/FunctionsPage/Functions.jsx b/src/components/FunctionsPage/Functions.jsx index 25b4a242a9..932491593f 100644 --- a/src/components/FunctionsPage/Functions.jsx +++ b/src/components/FunctionsPage/Functions.jsx @@ -62,15 +62,15 @@ import { } from '../../reducers/functionReducer' import createFunctionsRowData from '../../utils/createFunctionsRowData' import { DANGER_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' -import { transformSearchParams } from '../../utils/filter.util' +import { transformSearchParams } from 'igz-controls/utils/filter.util' import { isBackgroundTaskRunning } from '../../utils/poll.util' import { isDetailsTabExists } from '../../utils/link-helper.util' import { openPopUp } from 'igz-controls/utils/common.util' import { parseFunctions } from '../../utils/parseFunctions' import { runNewJob } from '../../reducers/jobReducer' import { setFilters } from '../../reducers/filtersReducer' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { toggleYaml } from '../../reducers/appReducer' import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' import { useMode } from '../../hooks/mode.hook' diff --git a/src/components/FunctionsPage/FunctionsView.jsx b/src/components/FunctionsPage/FunctionsView.jsx index 89c2dfaaf8..4c482b8084 100644 --- a/src/components/FunctionsPage/FunctionsView.jsx +++ b/src/components/FunctionsPage/FunctionsView.jsx @@ -27,11 +27,10 @@ import FunctionsFilters from './FunctionsFilters' import FunctionsPanel from '../FunctionsPanel/FunctionsPanel' import FunctionsTableRow from '../../elements/FunctionsTableRow/FunctionsTableRow' import HistoryBackLink from '../../common/HistoryBackLink/historyBackLink' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' import Pagination from '../../common/Pagination/Pagination' import Table from '../Table/Table' -import { ConfirmDialog } from 'igz-controls/components' +import { ConfirmDialog, Loader } from 'igz-controls/components' import { FUNCTIONS_PAGE, @@ -44,7 +43,7 @@ import { FILTERS_CONFIG } from '../../types' import { PRIMARY_BUTTON } from 'igz-controls/constants' import { getCloseDetailsLink } from '../../utils/link-helper.util' import { getNoDataMessage } from '../../utils/getNoDataMessage' -import { getSavedSearchParams } from '../../utils/filter.util' +import { getSavedSearchParams } from 'igz-controls/utils/filter.util' import { isEmpty } from 'lodash' const FunctionsView = ({ diff --git a/src/components/FunctionsPage/functions.util.jsx b/src/components/FunctionsPage/functions.util.jsx index 6371618c3c..d62bf3880b 100644 --- a/src/components/FunctionsPage/functions.util.jsx +++ b/src/components/FunctionsPage/functions.util.jsx @@ -50,8 +50,8 @@ import { getFunctionLogs, getFunctionNuclioLogs } from '../../utils/getFunctionL import { parseFunction } from '../../utils/parseFunction' import { parseIdentifier } from '../../utils' import { setJobFunction } from '../../reducers/jobReducer' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import Delete from 'igz-controls/images/delete.svg?react' import Run from 'igz-controls/images/run.svg?react' diff --git a/src/components/FunctionsPageOld/FunctionsOld.jsx b/src/components/FunctionsPageOld/FunctionsOld.jsx index 8621af6d8e..7e7b12a2c4 100644 --- a/src/components/FunctionsPageOld/FunctionsOld.jsx +++ b/src/components/FunctionsPageOld/FunctionsOld.jsx @@ -67,8 +67,8 @@ import { openPopUp, getScssVariableValue } from 'igz-controls/utils/common.util' import { parseFunctions } from '../../utils/parseFunctions' import { runNewJob } from '../../reducers/jobReducer' import { setFilters } from '../../reducers/filtersReducer' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { toggleYaml } from '../../reducers/appReducer' import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' import { useGroupContent } from '../../hooks/groupContent.hook' diff --git a/src/components/FunctionsPageOld/FunctionsViewOld.jsx b/src/components/FunctionsPageOld/FunctionsViewOld.jsx index fe17e01448..d29cb7f2ab 100644 --- a/src/components/FunctionsPageOld/FunctionsViewOld.jsx +++ b/src/components/FunctionsPageOld/FunctionsViewOld.jsx @@ -26,10 +26,9 @@ import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import FunctionsFilters from '../FunctionsPage/FunctionsFilters' import FunctionsPanel from '../FunctionsPanel/FunctionsPanel' import FunctionsTableRowOld from '../../elements/FunctionsTableRow/FunctionsTableRowOld' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' import Table from '../Table/Table' -import { ConfirmDialog } from 'igz-controls/components' +import { ConfirmDialog, Loader } from 'igz-controls/components' import { FUNCTIONS_PAGE, @@ -38,7 +37,8 @@ import { PANEL_EDIT_MODE } from '../../constants' import { PRIMARY_BUTTON } from 'igz-controls/constants' -import { FILTERS_CONFIG, VIRTUALIZATION_CONFIG } from '../../types' +import { VIRTUALIZATION_CONFIG } from 'igz-controls/types' +import { FILTERS_CONFIG } from '../../types' import { getNoDataMessage } from '../../utils/getNoDataMessage' import { isRowRendered } from '../../hooks/useVirtualization.hook' diff --git a/src/components/FunctionsPageOld/functionsOld.util.jsx b/src/components/FunctionsPageOld/functionsOld.util.jsx index ac0c25886c..737016b51b 100644 --- a/src/components/FunctionsPageOld/functionsOld.util.jsx +++ b/src/components/FunctionsPageOld/functionsOld.util.jsx @@ -43,8 +43,8 @@ import functionsApi from '../../api/functions-api' import tasksApi from '../../api/tasks-api' import { BG_TASK_FAILED, BG_TASK_SUCCEEDED, pollTask } from '../../utils/poll.util' import { parseFunction } from '../../utils/parseFunction' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { getFunctionLogs, getFunctionNuclioLogs } from '../../utils/getFunctionLogs' import { setJobFunction } from '../../reducers/jobReducer' diff --git a/src/components/FunctionsPanel/FunctionsPanelView.jsx b/src/components/FunctionsPanel/FunctionsPanelView.jsx index 14d15a18cc..2f8d66223b 100644 --- a/src/components/FunctionsPanel/FunctionsPanelView.jsx +++ b/src/components/FunctionsPanel/FunctionsPanelView.jsx @@ -22,16 +22,14 @@ import PropTypes from 'prop-types' import { useDispatch } from 'react-redux' import Accordion from '../../common/Accordion/Accordion' -import ErrorMessage from '../../common/ErrorMessage/ErrorMessage' import FunctionsPanelCode from '../../elements/FunctionsPanelCode/FunctionsPanelCode' import FunctionsPanelEnvironmentVariables from '../../elements/FunctionsPanelEnvironmentVariables/FunctionsPanelEnvironmentVariables' import FunctionsPanelGeneral from '../../elements/FunctionsPanelGeneral/FunctionsPanelGeneral' import FunctionsPanelResources from '../../elements/FunctionsPanelResources/FunctionsPanelResources' import FunctionsPanelRuntime from '../../elements/FunctionsPanelRuntime/FunctionsPanelRuntime' import FunctionsPanelTitle from '../../elements/FunctionsPanelTitle/FunctionsPanelTitle' -import Loader from '../../common/Loader/Loader' import PanelCredentialsAccessKey from '../../elements/PanelCredentialsAccessKey/PanelCredentialsAccessKey' -import { Button, ConfirmDialog } from 'igz-controls/components' +import { Button, ConfirmDialog, ErrorMessage, Loader } from 'igz-controls/components' import { removeFunctionsError, diff --git a/src/components/JobWizard/JobWizard.jsx b/src/components/JobWizard/JobWizard.jsx index 9278b8cf95..5caccb1994 100644 --- a/src/components/JobWizard/JobWizard.jsx +++ b/src/components/JobWizard/JobWizard.jsx @@ -34,9 +34,8 @@ import JobWizardHyperparameterStrategy from './JobWizardSteps/JobWizardHyperpara import JobWizardParameters from './JobWizardSteps/JobWizardParameters/JobWizardParameters' import JobWizardResources from './JobWizardSteps/JobWizardResources/JobWizardResources' import JobWizardRunDetails from './JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails' -import Loader from '../../common/Loader/Loader' import ScheduleWizard from '../SheduleWizard/ScheduleWizard' -import { Wizard } from 'igz-controls/components' +import { Wizard, Loader } from 'igz-controls/components' import { ADVANCED_STEP, @@ -73,8 +72,8 @@ import { editJob, removeJobFunction, runNewJob } from '../../reducers/jobReducer import { fetchProject } from '../../reducers/projectReducer' import { resetModalFilter } from '../../reducers/filtersReducer' import { setFieldState, isSubmitDisabled } from 'igz-controls/utils/form.util' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { useModalBlockHistory } from '../../hooks/useModalBlockHistory.hook' import './jobWizard.scss' diff --git a/src/components/JobWizard/JobWizard.util.js b/src/components/JobWizard/JobWizard.util.js index 3a5dcdf0ea..85c29df8e0 100644 --- a/src/components/JobWizard/JobWizard.util.js +++ b/src/components/JobWizard/JobWizard.util.js @@ -86,7 +86,7 @@ import { generateObjectFromKeyValue, parseObjectToKeyValue } from 'igz-controls/ import { getDefaultSchedule, scheduleDataInitialState } from '../SheduleWizard/scheduleWizard.util' import { getErrorDetail } from 'igz-controls/utils/common.util' import { getPreemptionMode } from '../../utils/getPreemptionMode' -import { trimSplit } from '../../utils' +import { trimSplit } from 'igz-controls/utils/string.util' const volumeTypesMap = { [CONFIG_MAP_VOLUME_TYPE]: 'configMap', diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails.jsx b/src/components/JobWizard/JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails.jsx index 646f18487e..57f9259aca 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails.jsx +++ b/src/components/JobWizard/JobWizardSteps/JobWizardRunDetails/JobWizardRunDetails.jsx @@ -43,7 +43,7 @@ import { } from '../../../../constants' import { PRIMARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' import { areFormValuesChanged } from 'igz-controls/utils/form.util' -import { getChipOptions } from '../../../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import { getValidationRules, getInternalLabelsValidationRule diff --git a/src/components/Jobs/Jobs.jsx b/src/components/Jobs/Jobs.jsx index 29eab255a4..80feb7b0ca 100644 --- a/src/components/Jobs/Jobs.jsx +++ b/src/components/Jobs/Jobs.jsx @@ -24,9 +24,8 @@ import { defaultsDeep, isEmpty } from 'lodash' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import ContentMenu from '../../elements/ContentMenu/ContentMenu' -import Loader from '../../common/Loader/Loader' import PreviewModal from '../../elements/PreviewModal/PreviewModal' -import { ConfirmDialog } from 'igz-controls/components' +import { ConfirmDialog, Loader } from 'igz-controls/components' import { INACTIVE_JOBS_TAB, diff --git a/src/components/Jobs/jobs.util.js b/src/components/Jobs/jobs.util.js index 06526f5315..1884cc0031 100644 --- a/src/components/Jobs/jobs.util.js +++ b/src/components/Jobs/jobs.util.js @@ -37,10 +37,6 @@ import { ERROR_STATE, FAILED_STATE } from '../../constants' -import { generateKeyValues, parseKeyValues, truncateUid } from '../../utils' -import { BG_TASK_FAILED, BG_TASK_SUCCEEDED, pollTask } from '../../utils/poll.util' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' import { abortJob, deleteAllJobRuns, @@ -48,7 +44,12 @@ import { fetchJobFunction, fetchJobFunctions } from '../../reducers/jobReducer' +import { BG_TASK_FAILED, BG_TASK_SUCCEEDED, pollTask } from '../../utils/poll.util' import { generateFunctionPriorityLabel } from '../../utils/generateFunctionPriorityLabel' +import { generateKeyValues, parseKeyValues } from '../../utils' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' +import { truncateUid } from 'igz-controls/utils/string.util' export const page = JOBS_PAGE const LOG_LEVEL_ID = 'logLevel' diff --git a/src/components/LLMPrompts/llmPrompts.util.jsx b/src/components/LLMPrompts/llmPrompts.util.jsx index d4bb7a5bc1..492e5cf999 100644 --- a/src/components/LLMPrompts/llmPrompts.util.jsx +++ b/src/components/LLMPrompts/llmPrompts.util.jsx @@ -19,20 +19,21 @@ such restriction. */ import React from 'react' +import DeleteArtifactPopUp from '../../elements/DeleteArtifactPopUp/DeleteArtifactPopUp' + import { ARTIFACT_MAX_DOWNLOAD_SIZE, - FULL_VIEW_MODE, LLM_PROMPT_TYPE, LLM_PROMPTS_PAGE } from '../../constants' -import { getIsTargetPathValid } from '../../utils/createArtifactsContent' +import { FULL_VIEW_MODE } from 'igz-controls/constants' import { applyTagChanges, chooseOrFetchArtifact } from '../../utils/artifacts.util' -import { setDownloadItem, setShowDownloadsList } from '../../reducers/downloadReducer' import { copyToClipboard } from '../../utils/copyToClipboard' import { generateUri } from '../../utils/resources' -import { openDeleteConfirmPopUp, openPopUp } from 'igz-controls/utils/common.util' -import DeleteArtifactPopUp from '../../elements/DeleteArtifactPopUp/DeleteArtifactPopUp' +import { getIsTargetPathValid } from '../../utils/createArtifactsContent' import { handleDeleteArtifact } from '../../utils/handleDeleteArtifact' +import { openDeleteConfirmPopUp, openPopUp } from 'igz-controls/utils/common.util' +import { setDownloadItem, setShowDownloadsList } from '../../reducers/downloadReducer' import { showArtifactsPreview } from '../../reducers/artifactsReducer' import TagIcon from 'igz-controls/images/tag-icon.svg?react' diff --git a/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx b/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx index 00f0757b07..2ffa16ef07 100644 --- a/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx +++ b/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx @@ -24,11 +24,11 @@ import { isEmpty } from 'lodash' import ActionBar from '../../ActionBar/ActionBar' import ArtifactsTableRow from '../../../elements/ArtifactsTableRow/ArtifactsTableRow' -import Loader from '../../../common/Loader/Loader' import ModelEndpointsFilters from './ModelEndpointsFilters' import ModelsPageTabs from '../ModelsPageTabs/ModelsPageTabs' import NoData from '../../../common/NoData/NoData' import Table from '../../Table/Table' +import { Loader } from 'igz-controls/components' import { GROUP_BY_NONE, diff --git a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx index cce5b39f29..0f0e510078 100644 --- a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx +++ b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx @@ -21,9 +21,9 @@ import { isEmpty } from 'lodash' import { LABELS_FILTER, MODEL_ENDPOINTS_TAB, MODELS_PAGE } from '../../../constants' import { TERTIARY_BUTTON } from 'igz-controls/constants' -import { showErrorNotification } from '../../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { fetchModelEndpoint } from '../../../reducers/artifactsReducer' -import { formatDatetime } from '../../../utils' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import Alert from 'igz-controls/images/alerts.svg?react' diff --git a/src/components/ModelsPage/Models/models.util.jsx b/src/components/ModelsPage/Models/models.util.jsx index 4443779221..d762809a9c 100644 --- a/src/components/ModelsPage/Models/models.util.jsx +++ b/src/components/ModelsPage/Models/models.util.jsx @@ -27,21 +27,24 @@ import { MODELS_PAGE, MODELS_TAB, TAG_LATEST, - FULL_VIEW_MODE, MODEL_TYPE, ARTIFACT_MAX_DOWNLOAD_SIZE } from '../../../constants' +import { + getErrorMsg, + openPopUp, + openDeleteConfirmPopUp, + copyToClipboard +} from 'igz-controls/utils/common.util' import { showArtifactsPreview, updateArtifact } from '../../../reducers/artifactsReducer' -import { FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' +import { FORBIDDEN_ERROR_STATUS_CODE, FULL_VIEW_MODE } from 'igz-controls/constants' import { applyTagChanges, chooseOrFetchArtifact } from '../../../utils/artifacts.util' import { convertChipsData } from '../../../utils/convertChipsData' -import { copyToClipboard } from '../../../utils/copyToClipboard' import { getIsTargetPathValid } from '../../../utils/createArtifactsContent' import { generateUri } from '../../../utils/resources' -import { getErrorMsg, openPopUp, openDeleteConfirmPopUp } from 'igz-controls/utils/common.util' import { handleDeleteArtifact } from '../../../utils/handleDeleteArtifact' import { setDownloadItem, setShowDownloadsList } from '../../../reducers/downloadReducer' -import { showErrorNotification } from '../../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import TagIcon from 'igz-controls/images/tag-icon.svg?react' import YamlIcon from 'igz-controls/images/yaml.svg?react' diff --git a/src/components/ModelsPage/ModelsPage.jsx b/src/components/ModelsPage/ModelsPage.jsx index 3c97271d62..d1d2233fed 100644 --- a/src/components/ModelsPage/ModelsPage.jsx +++ b/src/components/ModelsPage/ModelsPage.jsx @@ -22,8 +22,8 @@ import { Outlet } from 'react-router-dom' import { useSelector } from 'react-redux' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' -import Loader from '../../common/Loader/Loader' import PreviewModal from '../../elements/PreviewModal/PreviewModal' +import { Loader } from 'igz-controls/components' import { ModelsPageProvider } from './ModelsPage.context' diff --git a/src/components/ModelsPage/RealTimePipelines/RealTimePipelines.jsx b/src/components/ModelsPage/RealTimePipelines/RealTimePipelines.jsx index e8ba7af382..d1a164222b 100644 --- a/src/components/ModelsPage/RealTimePipelines/RealTimePipelines.jsx +++ b/src/components/ModelsPage/RealTimePipelines/RealTimePipelines.jsx @@ -24,12 +24,12 @@ import classnames from 'classnames' import { isNil } from 'lodash' import ActionBar from '../../ActionBar/ActionBar' -import Loader from '../../../common/Loader/Loader' import ModelsPageTabs from '../ModelsPageTabs/ModelsPageTabs' import NoData from '../../../common/NoData/NoData' import Pipeline from '../../Pipeline/Pipeline' import RealTimePipelinesTableRow from '../../../elements/RealTimePipelinesTableRow/RealTimePipelinesTableRow' import Table from '../../Table/Table' +import { Loader } from 'igz-controls/components' import { GROUP_BY_NAME, diff --git a/src/components/ModelsPage/RealTimePipelines/realTimePipelines.util.js b/src/components/ModelsPage/RealTimePipelines/realTimePipelines.util.js index c0211d6984..919ea26f9e 100644 --- a/src/components/ModelsPage/RealTimePipelines/realTimePipelines.util.js +++ b/src/components/ModelsPage/RealTimePipelines/realTimePipelines.util.js @@ -19,7 +19,7 @@ such restriction. */ import { MODELS_PAGE, NAME_FILTER } from '../../../constants' import { parseFunction } from '../../../utils/parseFunction' -import { showErrorNotification } from '../../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { fetchFunction } from '../../../reducers/functionReducer' export const filtersConfig = { diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx index c2c93bb6d2..c43fafbded 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx @@ -22,8 +22,8 @@ import moment from 'moment' import PropTypes from 'prop-types' import MlChart from '../../../common/MlChart/MlChart' -import { Tip } from 'igz-controls/components' import NoData from '../../../common/NoData/NoData' +import { Tip } from 'igz-controls/components' import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicationsPage.util' import { getMEPsWithDetectionChartConfig } from '../../../utils/getChartConfig' diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx index 5576c4c66e..3c939fa228 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.jsx @@ -22,12 +22,8 @@ import { Link, useParams } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import NoData from '../../../../common/NoData/NoData' -import { Tip } from 'igz-controls/components' import SectionTable from '../../../../elements/SectionTable/SectionTable' - -import { removeMonitoringApplication } from '../../../../reducers/monitoringApplicationsReducer' -import { removeArtifacts } from '../../../../reducers/artifactsReducer' -import { FILES_PAGE, NAME_FILTER } from '../../../../constants' +import { Tip } from 'igz-controls/components' import { generateArtifactsTableContent, @@ -35,7 +31,10 @@ import { generateResultsTableContent, generateShardsStatusTableContent } from './MonitoringApplication.util' +import { FILES_PAGE, NAME_FILTER } from '../../../../constants' import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../../MonitoringApplicationsPage.util' +import { removeArtifacts } from '../../../../reducers/artifactsReducer' +import { removeMonitoringApplication } from '../../../../reducers/monitoringApplicationsReducer' import './monitoringApplication.scss' diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx index a280025c41..45a936e3eb 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx @@ -20,10 +20,10 @@ such restriction. import prettyBytes from 'pretty-bytes' import { capitalize, isNumber } from 'lodash' -import { parseChipsData } from '../../../../utils/convertChipsData' -import { formatDatetime } from '../../../../utils' import { METRIC_TYPE, RESULT_TYPE } from '../../../../constants' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import { getDriftStatusData } from '../../../../utils/createArtifactsContent' +import { parseChipsData } from '../../../../utils/convertChipsData' export const generateArtifactsTableContent = (artifacts = []) => { const tableHeaders = [ diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx index 3245eba66f..40e44f9b56 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx @@ -20,9 +20,8 @@ such restriction. import React from 'react' import PropTypes from 'prop-types' -import Loader from '../../../../../common/Loader/Loader' import StatsCard from '../../../../../common/StatsCard/StatsCard' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' const MonitoringApplicationCard = ({ counterData, diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx index d94e33312c..43c87fe408 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx @@ -21,18 +21,18 @@ import React, { useEffect, useMemo } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useNavigate, useParams } from 'react-router-dom' -import Table from '../../Table/Table' +import ApplicationTableRow from '../../../elements/ApplicationTableRow/ApplicationTableRow' +import MEPsWithDetections from './MEPsWithDetections' import NoData from '../../../common/NoData/NoData' import SectionTable from '../../../elements/SectionTable/SectionTable' +import Table from '../../Table/Table' import { Tip } from 'igz-controls/components' -import ApplicationTableRow from '../../../elements/ApplicationTableRow/ApplicationTableRow' -import MEPsWithDetections from './MEPsWithDetections' +import { MODEL_ENDPOINTS_TAB, MONITORING_APP_PAGE } from '../../../constants' import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicationsPage.util' -import { generateOperatingFunctionsTable } from './monitoringApplications.util' import { createApplicationContent } from '../../../utils/createApplicationContent' +import { generateOperatingFunctionsTable } from './monitoringApplications.util' import { removeMonitoringApplications } from '../../../reducers/monitoringApplicationsReducer' -import { MODEL_ENDPOINTS_TAB, MONITORING_APP_PAGE } from '../../../constants' import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js index 0f070f0103..474e78b300 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js @@ -21,7 +21,8 @@ import { capitalize } from 'lodash' import classnames from 'classnames' import moment from 'moment' -import { formatDatetime, generateNuclioLink } from '../../../utils' +import { generateNuclioLink } from '../../../utils' +import { formatDatetime } from 'igz-controls/utils/datetime.util' export const generateOperatingFunctionsTable = functions => { const tableHeaders = [ diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index 16d9e60ab9..064a70063b 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -22,23 +22,22 @@ import { Outlet, useNavigate, useParams, useSearchParams } from 'react-router-do import { useDispatch, useSelector } from 'react-redux' import ActionBar from '../ActionBar/ActionBar' -import Loader from '../../common/Loader/Loader' -import TableTop from '../../elements/TableTop/TableTop' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import MonitoringApplicationCounters from './MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCounters' +import TableTop from '../../elements/TableTop/TableTop' +import { Loader } from 'igz-controls/components' -import { MODEL_ENDPOINTS_TAB, MONITORING_APP_PAGE } from '../../constants' -import { getFiltersConfig } from './MonitoringApplicationsPage.util' -import { showErrorNotification } from '../../utils/notifications.util' -import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' import { fetchMonitoringApplication, fetchMonitoringApplications, fetchMonitoringApplicationsSummary } from '../../reducers/monitoringApplicationsReducer' -import { fetchArtifacts } from '../../reducers/artifactsReducer' - +import { MODEL_ENDPOINTS_TAB, MONITORING_APP_PAGE } from '../../constants' import { PRIMARY_BUTTON } from 'igz-controls/constants' +import { fetchArtifacts } from '../../reducers/artifactsReducer' +import { getFiltersConfig } from './MonitoringApplicationsPage.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' +import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' @@ -130,7 +129,11 @@ const MonitoringApplicationsPage = () => { label: 'Application metrics', className: 'action-button', hidden: !params.name, - onClick: () => {navigate(`/projects/${params.projectName}/${MONITORING_APP_PAGE}/${params.name}/${MODEL_ENDPOINTS_TAB}${window.location.search}`)}, + onClick: () => { + navigate( + `/projects/${params.projectName}/${MONITORING_APP_PAGE}/${params.name}/${MODEL_ENDPOINTS_TAB}${window.location.search}` + ) + }, icon: } ]} diff --git a/src/components/Pipeline/Pipeline.jsx b/src/components/Pipeline/Pipeline.jsx index 42af4b3e76..c8c11e2da1 100644 --- a/src/components/Pipeline/Pipeline.jsx +++ b/src/components/Pipeline/Pipeline.jsx @@ -27,8 +27,7 @@ import { useDispatch, useSelector } from 'react-redux' import MlReactFlow from '../../common/ReactFlow/MlReactFlow' import CodeBlock from '../../common/CodeBlock/CodeBlock' import NoData from '../../common/NoData/NoData' -import { Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' -import Loader from '../../common/Loader/Loader' +import { Tooltip, TextTooltipTemplate, RoundedIcon, Loader } from 'igz-controls/components' import { DEFAULT_EDGE, diff --git a/src/components/Project/ProjectMonitor.jsx b/src/components/Project/ProjectMonitor.jsx index ef5d50a382..f2c88a9c29 100644 --- a/src/components/Project/ProjectMonitor.jsx +++ b/src/components/Project/ProjectMonitor.jsx @@ -48,8 +48,8 @@ import { generateCreateNewOptions, handleFetchProjectError } from './project.uti import { openPopUp } from 'igz-controls/utils/common.util' import { removeFunctionsError, removeNewFunction } from '../../reducers/functionReducer' import { removeNewFeatureSet } from '../../reducers/featureStoreReducer' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { useMode } from '../../hooks/mode.hook' import { useNuclioMode } from '../../hooks/nuclioMode.hook' diff --git a/src/components/Project/ProjectMonitorView.jsx b/src/components/Project/ProjectMonitorView.jsx index ec06b0e911..090d790f02 100644 --- a/src/components/Project/ProjectMonitorView.jsx +++ b/src/components/Project/ProjectMonitorView.jsx @@ -25,7 +25,6 @@ import AlertsCounters from '../../elements/ProjectsMonitoringCounters/AlertsCoun import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import FeatureSetsPanel from '../FeatureSetsPanel/FeatureSetsPanel' import FunctionsPanel from '../FunctionsPanel/FunctionsPanel' -import Loader from '../../common/Loader/Loader' import NewFunctionPopUp from '../../elements/NewFunctionPopUp/NewFunctionPopUp' import NoData from '../../common/NoData/NoData' import ProjectFunctions from '../../elements/ProjectFunctions/ProjectFunctions' @@ -33,7 +32,7 @@ import ProjectDetailsHeader from '../../common/ProjectDetailsHeader/ProjectDetai import ProjectJobs from '../../elements/ProjectJobs/ProjectJobs' import ProjectSummaryCard from '../../elements/ProjectSummaryCard/ProjectSummaryCard' import Select from '../../common/Select/Select' -import { ConfirmDialog, RoundedIcon } from 'igz-controls/components' +import { ConfirmDialog, RoundedIcon, Loader } from 'igz-controls/components' import { PANEL_CREATE_MODE } from '../../constants' import { launchIDEOptions, generateTipMessageForCounter } from './project.utils' diff --git a/src/components/Project/ProjectOverview/ProjectOverview.jsx b/src/components/Project/ProjectOverview/ProjectOverview.jsx index 0ad2b5ae6d..e702e01ee5 100644 --- a/src/components/Project/ProjectOverview/ProjectOverview.jsx +++ b/src/components/Project/ProjectOverview/ProjectOverview.jsx @@ -23,12 +23,11 @@ import { isEmpty } from 'lodash' import { useNavigate, useParams } from 'react-router-dom' import Breadcrumbs from '../../../common/Breadcrumbs/Breadcrumbs' -import Loader from '../../../common/Loader/Loader' import NoData from '../../../common/NoData/NoData' import ProjectAction from '../ProjectAction/ProjectAction' import ProjectDetailsHeader from '../../../common/ProjectDetailsHeader/ProjectDetailsHeader' import ProjectOverviewTableRow from '../ProjectOverviewTableRow/ProjectOverviewTableRow' -import { ConfirmDialog } from 'igz-controls/components' +import { ConfirmDialog, Loader } from 'igz-controls/components' import { handleClick, getInitialCards } from './ProjectOverview.util' import { handleFetchProjectError } from '../project.utils' diff --git a/src/components/Project/project.utils.jsx b/src/components/Project/project.utils.jsx index 2a241c8351..eb8d060f2d 100644 --- a/src/components/Project/project.utils.jsx +++ b/src/components/Project/project.utils.jsx @@ -24,7 +24,7 @@ import JobWizard from '../JobWizard/JobWizard' import { ARTIFACT_TYPE, DATASET_TYPE } from '../../constants' import { PRIMARY_BUTTON, FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' import { openPopUp } from 'igz-controls/utils/common.util' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import Jupyter from 'igz-controls/images/jupyter.svg?react' import VSCode from 'igz-controls/images/vs-code.svg?react' diff --git a/src/components/ProjectSettings/ProjectSettings.jsx b/src/components/ProjectSettings/ProjectSettings.jsx index cfc1fad842..8d101c0574 100644 --- a/src/components/ProjectSettings/ProjectSettings.jsx +++ b/src/components/ProjectSettings/ProjectSettings.jsx @@ -26,10 +26,7 @@ import ProjectSettingsMembers from '../../elements/ProjectSettingsMembers/Projec import ProjectSettingsSecrets from '../../elements/ProjectSettingsSecrets/ProjectSettingsSecrets' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import ContentMenu from '../../elements/ContentMenu/ContentMenu' -import Loader from '../../common/Loader/Loader' - -import { Button, ConfirmDialog } from 'igz-controls/components' -import { DANGER_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' +import { Button, ConfirmDialog, Loader } from 'igz-controls/components' import { COMPLETED_STATE, @@ -39,17 +36,18 @@ import { tabs, validTabs } from './projectSettings.util' -import { onDeleteProject } from '../ProjectsPage/projects.util' import { initialMembersState, membersActions, membersReducer } from '../../elements/MembersPopUp/membersReducer' import projectsIguazioApi from '../../api/projects-iguazio-api' +import { DANGER_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' import { PROJECTS_SETTINGS_MEMBERS_TAB, PROJECTS_SETTINGS_SECRETS_TAB } from '../../constants' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' import { fetchProjects } from '../../reducers/projectReducer' +import { onDeleteProject } from '../ProjectsPage/projects.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import './projectSettings.scss' diff --git a/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.jsx b/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.jsx index a441a97b07..0b63cd81ad 100644 --- a/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.jsx +++ b/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.jsx @@ -22,15 +22,14 @@ import { useDispatch, useSelector } from 'react-redux' import { Outlet, useLocation, useNavigate, useParams } from 'react-router-dom' import { defaultsDeep, isEmpty } from 'lodash' +import { ConfirmDialog, Loader } from 'igz-controls/components' import ContentMenu from '../../elements/ContentMenu/ContentMenu' -import { ConfirmDialog } from 'igz-controls/components' import PreviewModal from '../../elements/PreviewModal/PreviewModal' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import ActionBar from '../ActionBar/ActionBar' import JobsMonitoringFilters from './JobsMonitoring/JobsMonitoringFilters' import ScheduledMonitoringFilters from './ScheduledMonitoring/ScheduledMonitoringFilters' import WorkflowsMonitoringFilters from './WorkflowsMonitoring/WorkflowsMonitoringFilters' -import Loader from '../../common/Loader/Loader' import { STATS_TOTAL_CARD, tabs } from './projectsJobsMotinoring.util' import { diff --git a/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.jsx b/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.jsx index 8134fd7281..640db4dcde 100644 --- a/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.jsx +++ b/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.jsx @@ -24,12 +24,18 @@ import { Form } from 'react-final-form' import { useDispatch, useSelector } from 'react-redux' import { createForm } from 'final-form' -import ErrorMessage from '../../../common/ErrorMessage/ErrorMessage' -import Loader from '../../../common/Loader/Loader' -import { Button, FormChipCell, FormInput, FormTextarea, PopUpDialog } from 'igz-controls/components' +import { + Button, + FormChipCell, + FormInput, + FormTextarea, + PopUpDialog, + ErrorMessage, + Loader +} from 'igz-controls/components' import { PRIMARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' -import { getChipOptions } from '../../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import { getValidationRules, getInternalLabelsValidationRule @@ -57,10 +63,7 @@ const CreateProjectDialog = ({ closeNewProjectPopUp, handleCreateProject, isOpen }) ) const dispatch = useDispatch() - const { handleCloseModal } = useModalBlockHistory( - closeNewProjectPopUp, - formRef.current - ) + const { handleCloseModal } = useModalBlockHistory(closeNewProjectPopUp, formRef.current) return ( { - const tableRefLocal = useRef(null) - const tableBodyRefLocal = useRef(null) - const tableRef = ref?.tableRef ?? tableRefLocal - const tableBodyRef = ref?.tableBodyRef ?? tableBodyRefLocal - const tableContentRef = useRef(null) - const tablePanelRef = useRef(null) - const tableHeadRef = useRef(null) - const params = useParams() - const tableStore = useSelector(store => store.tableStore) - - useEffect(() => { - const calculatePanelHeight = () => { - if (tableHeadRef?.current && tableContentRef?.current && tablePanelRef?.current) { - const tableContentHeight = tableContentRef.current.getBoundingClientRect().height - const tableHeadCords = tableHeadRef.current.getBoundingClientRect() - const panelHeight = window.innerHeight - tableHeadCords.top - - tablePanelRef.current.style.height = - tableContentHeight > panelHeight - ? `${panelHeight}px` - : `${panelHeight - (panelHeight - tableContentHeight)}px` - } - } - - if (tableStore.isTablePanelOpen && tablePanelRef.current) { - calculatePanelHeight() - - document.getElementById('main-wrapper').addEventListener('scroll', calculatePanelHeight) - window.addEventListener('resize', calculatePanelHeight) - } - return () => { - window.removeEventListener('scroll', calculatePanelHeight) - window.removeEventListener('resize', calculatePanelHeight) - } - }, [tableStore.isTablePanelOpen]) - - const handleTableHScroll = useCallback( - e => { - if (tableRef.current) { - const tableScrollPosition = e.target.scrollLeft - - if (tableScrollPosition > 0) { - tableRef.current.classList.add('table__scrolled') - } else { - tableRef.current.classList.remove('table__scrolled') - } - } - }, - [tableRef] - ) - - useEffect(() => { - window.addEventListener('scroll', handleTableHScroll, true) - - return () => window.removeEventListener('scroll', handleTableHScroll, true) - }, [handleTableHScroll]) + const { + TableContainer, + tableBodyRef, + tableClass, + tableContentRef, + tableHeadRef, + tablePanelRef, + tableRef, + tableStore, + tableWrapperClass + } = useTable({ + ref, + selectedItem, + skipTableWrapper, + tableClassName + }) return ( - + !isEmpty(selectedItem) && + viewMode !== FULL_VIEW_MODE && ( +
      + ) + } > {children} - + ) } ) diff --git a/src/components/Table/TableHead.jsx b/src/components/Table/TableHead.jsx deleted file mode 100644 index 2b8c478302..0000000000 --- a/src/components/Table/TableHead.jsx +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' -import PropTypes from 'prop-types' -import classNames from 'classnames' -import { isEmpty } from 'lodash' - -import { Tip, Tooltip, TextTooltipTemplate } from 'igz-controls/components' - -import { SORT_PROPS } from 'igz-controls/types' - -const TableHead = React.forwardRef( - ( - { content, hideActionsMenu = false, mainRowItemsCount, selectedItem, sortProps = null }, - ref - ) => { - const getHeaderCellClasses = ( - headerId, - isSortable, - tableItemClassName, - headerCellClassName, - index - ) => - classNames( - 'table-header__cell', - tableItemClassName, - headerCellClassName, - isSortable && 'sortable-header-cell', - isSortable && sortProps?.selectedColumnName === headerId && 'sortable-header-cell_active', - !isEmpty(selectedItem) && index >= mainRowItemsCount && 'table-body__cell_hidden' - ) - - return ( - - - {content.map(({ headerLabel, headerId, isSortable, ...tableItem }, index) => { - return tableItem.type !== 'hidden' && !tableItem.hidden && !tableItem.headerIsHidden ? ( - sortProps.sortTable(headerId) : null} - > - }> - - - - {tableItem.tip && } - - ) : null - })} - {!hideActionsMenu && } - - - ) - } -) - -TableHead.displayName = 'TableHead' - -TableHead.propTypes = { - content: PropTypes.array.isRequired, - hideActionsMenu: PropTypes.bool, - mainRowItemsCount: PropTypes.number.isRequired, - selectedItem: PropTypes.object.isRequired, - sortProps: SORT_PROPS -} - -export default TableHead diff --git a/src/components/Table/TableView.jsx b/src/components/Table/TableView.jsx deleted file mode 100644 index a118977482..0000000000 --- a/src/components/Table/TableView.jsx +++ /dev/null @@ -1,151 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' -import PropTypes from 'prop-types' -import { isEmpty } from 'lodash' -import classnames from 'classnames' - -import Details from '../Details/Details' -import TableHead from './TableHead' - -import { ACTIONS_MENU, VIRTUALIZATION_CONFIG } from '../../types' -import { FULL_VIEW_MODE, MAIN_TABLE_BODY_ID, MAIN_TABLE_ID } from '../../constants' -import { SORT_PROPS } from 'igz-controls/types' - -const TableView = ({ - actionsMenu, - applyDetailsChanges = () => {}, - applyDetailsChangesCallback = () => {}, - children, - detailsFormInitialValues, - getCloseDetailsLink = null, - handleCancel, - hideActionsMenu, - isTablePanelOpen, - mainRowItemsCount, - pageData, - selectedItem, - skipTableWrapper = false, - sortProps = null, - tab, - tableBodyRef, - tableClassName, - tableContentRef, - tableHeadRef, - tableHeaders, - tablePanelRef, - tableRef, - viewMode, - virtualizationConfig, - withActionMenu -}) => { - const tableClass = classnames( - 'table', - 'table-main', - !isEmpty(selectedItem) && 'table-with-details', - tableClassName && tableClassName - ) - const tableWrapperClass = classnames(!skipTableWrapper && 'table__wrapper') - - return ( -
      -
      -
      - - {tableHeaders?.length > 0 && ( - - )} - - {children} - -
      - {isTablePanelOpen && ( -
      -
      {pageData.tablePanel}
      -
      - )} -
      - {!isEmpty(selectedItem) && viewMode !== FULL_VIEW_MODE && ( -
      - )} -
      -
      - ) -} - -TableView.propTypes = { - actionsMenu: ACTIONS_MENU.isRequired, - applyDetailsChanges: PropTypes.func, - applyDetailsChangesCallback: PropTypes.func, - children: PropTypes.node.isRequired, - detailsFormInitialValues: PropTypes.object.isRequired, - getCloseDetailsLink: PropTypes.func, - handleCancel: PropTypes.func.isRequired, - hideActionsMenu: PropTypes.bool.isRequired, - isTablePanelOpen: PropTypes.bool.isRequired, - mainRowItemsCount: PropTypes.number.isRequired, - pageData: PropTypes.object.isRequired, - selectedItem: PropTypes.object.isRequired, - skipTableWrapper: PropTypes.bool, - sortProps: SORT_PROPS, - tab: PropTypes.string, - tableBodyRef: PropTypes.object.isRequired, - tableClassName: PropTypes.string.isRequired, - tableContentRef: PropTypes.object.isRequired, - tableHeadRef: PropTypes.object, - tableHeaders: PropTypes.array, - tablePanelRef: PropTypes.object, - tableRef: PropTypes.object.isRequired, - viewMode: PropTypes.string.isRequired, - virtualizationConfig: VIRTUALIZATION_CONFIG.isRequired, - withActionMenu: PropTypes.bool -} - -export default TableView diff --git a/src/components/Table/table.scss b/src/components/Table/table.scss deleted file mode 100644 index 88a69e481c..0000000000 --- a/src/components/Table/table.scss +++ /dev/null @@ -1,283 +0,0 @@ -@use 'igz-controls/scss/variables'; -@use 'igz-controls/scss/colors'; -@use 'igz-controls/scss/mixins'; -@use 'igz-controls/scss/borders'; -@use 'igz-controls/scss/shadows'; - -@mixin tableCellWidth { - flex: 0 0 auto; - min-width: 75px; -} - -.table { - &__flex { - display: flex; - flex: 1; - flex-flow: row wrap; - } - - &__content { - position: relative; - flex: 1; - - [class*='icon'] { - flex-wrap: nowrap; - } - - .text-bold { - font-weight: 500; - } - } - - &__wrapper { - .content & { - position: absolute; - top: 0; - right: 0; - z-index: 2; - display: flex; - width: 100%; - height: 100%; - overflow-y: auto; - color: colors.$mulledWine; - background-color: colors.$white; - } - } - - & [class*='table-cell-'] { - @include tableCellWidth; - } - - .table-row { - .table-cell { - &-1 { - flex: 1; - } - - &-2 { - flex: 2; - } - - &-3 { - flex: 3; - } - - &-4 { - flex: 4; - } - - &-5 { - flex: 5; - } - - &-6 { - flex: 6; - } - - &-7 { - flex: 7; - } - - &-8 { - flex: 8; - } - - &-9 { - flex: 9; - } - - &-10 { - flex: 10; - } - - &-extra-small { - flex: 1; - max-width: 85px; - } - - &-small { - flex: 1; - max-width: 150px; - } - } - - &:has(.actions-menu__container-active) { - background-color: colors.$ghostWhite; - } - } - - &.table { - &__scrolled { - .table-cell-name { - &::after { - position: absolute; - top: 0; - right: 0; - bottom: 0; - width: 5px; - background-color: inherit; - border-right: borders.$secondaryBorder; - box-shadow: 2px 0 2px -1px rgba(colors.$black, 0.2); - content: ''; - } - } - - .parent-row_expanded { - .row_grouped-by { - .table-cell-name { - border-right: none; - box-shadow: none; - } - } - } - } - } - - .targets-cell { - flex-wrap: nowrap; - min-width: 130px; - - svg { - margin: 0 5px; - - &:first-child { - margin-left: 0; - } - } - } - - &__panel-container { - position: sticky; - top: 0; - z-index: 1; - width: auto; - border-left: borders.$primaryBorder; - box-shadow: shadows.$tablePanelShadow; - - &.hidden { - display: none; - } - } - - &__panel { - height: 100%; - overflow: hidden auto; - } - - .error-message { - justify-content: center; - width: 100%; - } - - .table { - &-header { - &__cell { - @include tableCellWidth; - - &.buttonPopout, - &.buttonDownload { - @include mixins.tableColumnFlex(0.5, 80px); - } - - &.align-right { - justify-content: flex-end; - } - - .tip-container { - margin-left: 2px; - } - } - - .icons-container { - min-width: 150px; - } - } - - &-body { - color: colors.$mulledWine; - - &__cell { - @include tableCellWidth; - - &_hidden { - font-size: 0; - - * { - visibility: hidden; - } - - .chip { - visibility: hidden; - } - } - - .cell_name { - position: relative; - display: flex; - flex: 1; - flex-direction: column; - margin: 0; - } - - .text_small { - min-width: 100%; - max-width: 50px; - } - - &.align-right { - justify-content: flex-end; - } - - &_type { - display: inline-flex; - text-transform: capitalize; - } - - a { - position: relative; - width: 100%; - margin: 0; - text-decoration: none; - - span { - display: block; - width: 100%; - } - } - - i { - margin-right: 5px; - } - - button { - display: flex; - font-size: 15px; - background-color: transparent; - border: none; - - &:disabled { - cursor: default; - } - - &:not(:disabled) { - cursor: pointer; - } - } - - .path-tooltip { - cursor: pointer; - } - - .chip_short { - max-width: 100px; - } - - .alert-icon-cell { - display: flex; - gap: 4px; - align-items: center; - } - } - } - } -} diff --git a/src/components/Workflow/JobsFunctionsTableRow/JobsFunctionsTableRow.jsx b/src/components/Workflow/JobsFunctionsTableRow/JobsFunctionsTableRow.jsx index 3ab4f8cea1..b11e2c38ba 100644 --- a/src/components/Workflow/JobsFunctionsTableRow/JobsFunctionsTableRow.jsx +++ b/src/components/Workflow/JobsFunctionsTableRow/JobsFunctionsTableRow.jsx @@ -22,7 +22,7 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import { useParams } from 'react-router-dom' -import TableCell from '../../../elements/TableCell/TableCell' +import { TableCell } from 'igz-controls/components' import { DETAILS_OVERVIEW_TAB } from '../../../constants' import { isWorkflowJobSelected } from '../workflow.util' @@ -41,7 +41,7 @@ const JobsFunctionsTableRow = ({ handleSelectItem = () => {}, rowItem, selectedI return ( !rowItemProp.hidden && ( { - const dispatch = useDispatch() - const changes = useSelector(store => store.detailsStore.changes) - - const iconClassNames = classnames( - 'actions-menu__icon', - isIconDisplayed && 'actions-menu__icon_visible' - ) - const menuClassNames = classnames( - 'actions-menu__option', - menuItem.className && `actions-menu__option_${menuItem.className}`, - menuItem.disabled && 'actions-menu__option_disabled' - ) - - const handleActionClick = async () => { - if (!menuItem.disabled) { - if (menuItem.allowLeaveWarning) { - const actionCanBePerformed = await performDetailsActionHelper(changes, dispatch) - - if (actionCanBePerformed) { - menuItem.onClick(dataItem) - } - } else { - menuItem.onClick(dataItem) - } - } - } - - return ( -
    • - } - hidden={!menuItem.tooltip} - key={menuItem.label} - > - {menuItem.icon} - {menuItem.label} - -
    • - ) -} - -ActionsMenuItem.propTypes = { - dataItem: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - index: PropTypes.number.isRequired, - isIconDisplayed: PropTypes.bool.isRequired, - menuItem: PropTypes.object.isRequired -} - -export default ActionsMenuItem diff --git a/src/elements/ActionMenuItem/actionsMenuItem.scss b/src/elements/ActionMenuItem/actionsMenuItem.scss deleted file mode 100644 index 53fd421504..0000000000 --- a/src/elements/ActionMenuItem/actionsMenuItem.scss +++ /dev/null @@ -1,66 +0,0 @@ -@use 'igz-controls/scss/shadows'; -@use 'igz-controls/scss/colors'; - -.actions-menu { - &__icon { - display: none; - align-items: center; - justify-content: center; - width: 25px; - height: 25px; - margin-right: 5px; - - svg { - path { - &:first-child { - fill: colors.$topaz; - } - } - } - - &_visible { - display: flex; - } - } - - &__option { - padding: 10px; - color: colors.$primary; - cursor: pointer; - - &:hover { - background-color: colors.$alabaster; - } - - &_danger { - color: colors.$amaranth; - - svg { - path:first-child { - fill: colors.$amaranth; - } - } - } - - &_disabled { - color: colors.$spunPearl; - cursor: not-allowed; - - .actions-menu__icon { - svg { - path:first-child { - fill: rgba(colors.$black, 0.2); - } - } - } - } - - & > * { - display: flex; - flex: 1; - align-items: center; - justify-content: flex-start; - width: 100%; - } - } -} diff --git a/src/elements/AddArtifactTagPopUp/AddArtifactTagPopUp.jsx b/src/elements/AddArtifactTagPopUp/AddArtifactTagPopUp.jsx index 403534164d..c92fffab9b 100644 --- a/src/elements/AddArtifactTagPopUp/AddArtifactTagPopUp.jsx +++ b/src/elements/AddArtifactTagPopUp/AddArtifactTagPopUp.jsx @@ -24,15 +24,14 @@ import { useLocation } from 'react-router-dom' import { Form } from 'react-final-form' import { createForm } from 'final-form' -import { Button, FormInput, Modal } from 'igz-controls/components' -import Loader from '../../common/Loader/Loader' +import { Button, FormInput, Modal, Loader } from 'igz-controls/components' import { DATASET_TYPE, MODEL_TYPE, TAG_LATEST } from '../../constants' import { PRIMARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' import { addTag, fetchAllArtifactKindsTags } from '../../reducers/artifactsReducer' import { getValidationRules } from 'igz-controls/utils/validation.util' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { useModalBlockHistory } from '../../hooks/useModalBlockHistory.hook' import { isSubmitDisabled } from 'igz-controls/utils/form.util' diff --git a/src/elements/AlertsTable/AlertsTable.jsx b/src/elements/AlertsTable/AlertsTable.jsx index 1bb47cec39..7cb4cc7dad 100644 --- a/src/elements/AlertsTable/AlertsTable.jsx +++ b/src/elements/AlertsTable/AlertsTable.jsx @@ -21,9 +21,9 @@ import PropTypes from 'prop-types' import { isEmpty } from 'lodash' import AlertsTableRow from '../../elements/AlertsTableRow/AlertsTableRow' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' import Table from '../../components/Table/Table' +import { Loader } from 'igz-controls/components' import { ALERTS_PAGE, ALERTS_PAGE_PATH, MONITOR_ALERTS_PAGE } from '../../constants' import { getNoDataMessage } from '../../utils/getNoDataMessage' diff --git a/src/elements/AlertsTableRow/AlertsTableRow.jsx b/src/elements/AlertsTableRow/AlertsTableRow.jsx index 139a57ad64..49b1f196b3 100644 --- a/src/elements/AlertsTableRow/AlertsTableRow.jsx +++ b/src/elements/AlertsTableRow/AlertsTableRow.jsx @@ -22,7 +22,7 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import DetailsAlertsMetrics from '../../components/DetailsDrillDownAlert/DetailsAlertsMetrics' -import TableCell from '../TableCell/TableCell' +import { TableCell } from 'igz-controls/components' import { ALERTS_PAGE } from '../../constants' import { getIdentifierMethod } from '../../utils/getUniqueIdentifier' @@ -56,7 +56,7 @@ const AlertsTableRow = ({ !value.hidden && ( { +const ApplicationTableRow = ({ actionsMenu, hideActionsMenu = false, rowItem }) => { const rowClassNames = classnames('table-row', 'table-body-row', 'parent-row') return ( @@ -40,7 +35,7 @@ const ApplicationTableRow = ({ return ( !value.hidden && ( { const rowClassNames = classnames('table-row', 'parent-row') const currentItem = content.find( contentItem => - getV3ioStreamShardLagIdentifier(contentItem) === rowItem.shardLagId?.identifierUnique + getV3ioStreamShardLagIdentifier(contentItem, true) === rowItem.shardLagId?.identifierUnique ) return ( @@ -39,7 +39,7 @@ const ConsumerGroupShardLagTableRow = ({ content, rowItem }) => { return ( !rowItemProp.hidden && ( { const parent = useRef() const rowClassNames = classnames('table-row', 'parent-row') const currentItem = content.find( - contentItem => getV3ioStreamIdentifier(contentItem) === rowItem.consumerGroup?.identifierUnique + contentItem => + getV3ioStreamIdentifier(contentItem, true) === rowItem.consumerGroup?.identifierUnique ) return ( @@ -38,7 +39,7 @@ const ConsumerGroupTableRow = ({ content, rowItem }) => { return ( !rowItemProp.hidden && ( { const [inputIsValid, setInputIsValid] = useState(true) - const detailsStore = useSelector(store => store.detailsStore) + const commonDetailsStore = useSelector(store => store.commonDetailsStore) const discardChanges = () => { handleDiscardChanges && handleDiscardChanges(currentField) - item.handleDiscardChanges && item.handleDiscardChanges(formState, detailsStore) + item.handleDiscardChanges && item.handleDiscardChanges(formState, commonDetailsStore) } if (item?.editModeEnabled && item?.editModeType === 'chips') { @@ -79,7 +85,7 @@ const DetailsInfoItem = React.forwardRef( chipsData={chipsData} currentField={currentField} detailsInfoDispatch={detailsInfoDispatch} - detailsStore={detailsStore} + commonDetailsStore={commonDetailsStore} editableFieldType={editableFieldType} formState={formState} handleFinishEdit={handleFinishEdit} diff --git a/src/elements/DetailsInfoItemChip/DetailsInfoItemChip.jsx b/src/elements/DetailsInfoItemChip/DetailsInfoItemChip.jsx index 959537b647..2532afb5ff 100644 --- a/src/elements/DetailsInfoItemChip/DetailsInfoItemChip.jsx +++ b/src/elements/DetailsInfoItemChip/DetailsInfoItemChip.jsx @@ -30,16 +30,16 @@ import { getInternalLabelsValidationRule } from 'igz-controls/utils/validation.util' import { detailsInfoActions } from '../../components/DetailsInfo/detailsInfoReducer' -import { setEditMode } from '../../reducers/detailsReducer' +import { setEditMode } from 'igz-controls/reducers/commonDetailsReducer' import Close from 'igz-controls/images/close.svg?react' import Checkmark from 'igz-controls/images/checkmark2.svg?react' const DetailsInfoItemChip = ({ chipsData, + commonDetailsStore, currentField, detailsInfoDispatch, - detailsStore, editableFieldType, formState, handleFinishEdit, @@ -61,7 +61,7 @@ const DetailsInfoItemChip = ({ !isFieldInEditMode && !isEqual( formState.values[item.fieldData.name], - detailsStore.changes.data?.[item.fieldData.name]?.currentFieldValue + commonDetailsStore.changes.data?.[item.fieldData.name]?.currentFieldValue ) ) { detailsInfoDispatch({ @@ -78,7 +78,7 @@ const DetailsInfoItemChip = ({ }, [ currentField, detailsInfoDispatch, - detailsStore.changes.data, + commonDetailsStore.changes.data, dispatch, formState.form, formState.values, @@ -94,7 +94,7 @@ const DetailsInfoItemChip = ({ !formState.form.getFieldState(item.fieldData.name).pristine && !isEqual( formState.values[item.fieldData.name], - detailsStore.changes.data?.[item.fieldData.name]?.currentFieldValue + commonDetailsStore.changes.data?.[item.fieldData.name]?.currentFieldValue ) && !isFieldInEditMode ) { @@ -109,7 +109,7 @@ const DetailsInfoItemChip = ({ } else if ( !isEmpty(formState.initialValues[item.fieldData.name]) && isEmpty(formState.values[item.fieldData.name]) && - !detailsStore.changes.data?.[item.fieldData.name] && + !commonDetailsStore.changes.data?.[item.fieldData.name] && !isFieldInEditMode ) { detailsInfoDispatch({ @@ -124,7 +124,7 @@ const DetailsInfoItemChip = ({ }, [ currentField, detailsInfoDispatch, - detailsStore.changes.data, + commonDetailsStore.changes.data, dispatch, formState.form, formState.initialValues, @@ -151,7 +151,7 @@ const DetailsInfoItemChip = ({ const discardChanges = () => { formState.form.change( item.fieldData.name, - detailsStore.changes.data[item.fieldData.name]?.currentFieldValue ?? + commonDetailsStore.changes.data[item.fieldData.name]?.currentFieldValue ?? formState.initialValues[item.fieldData.name] ) dispatch(setEditMode(false)) @@ -196,9 +196,9 @@ const DetailsInfoItemChip = ({ DetailsInfoItemChip.propTypes = { chipsData: PropTypes.object.isRequired, + commonDetailsStore: PropTypes.object.isRequired, currentField: PropTypes.string.isRequired, detailsInfoDispatch: PropTypes.func.isRequired, - detailsStore: PropTypes.object.isRequired, editableFieldType: PropTypes.string.isRequired, formState: PropTypes.object.isRequired, handleFinishEdit: PropTypes.func.isRequired, diff --git a/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx b/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx index d2c711ae29..54531db6c5 100644 --- a/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx +++ b/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx @@ -25,7 +25,7 @@ import PropTypes from 'prop-types' import DetailsPopUp from '../DetailsPopUp' import { showArtifactErrorNotification } from '../../../utils/artifacts.util' -import { getViewMode } from '../../../utils/helper' +import { getViewMode } from 'igz-controls/utils/common.util' import { generateActionsMenu as generateFileActionsMenu, generatePageData as generateFilePageData diff --git a/src/elements/DetailsPopUp/DetailsPopUp.jsx b/src/elements/DetailsPopUp/DetailsPopUp.jsx index 8eb620fca7..1a6e2ffe9f 100644 --- a/src/elements/DetailsPopUp/DetailsPopUp.jsx +++ b/src/elements/DetailsPopUp/DetailsPopUp.jsx @@ -21,9 +21,8 @@ import React, { useEffect, useRef, useState } from 'react' import { useLocation } from 'react-router-dom' import PropTypes from 'prop-types' -import Loader from '../../common/Loader/Loader' import Details from '../../components/Details/Details' -import { Modal } from 'igz-controls/components' +import { Modal, Loader } from 'igz-controls/components' import { MODAL_MAX } from 'igz-controls/constants' import { DETAILS_OVERVIEW_TAB } from '../../constants' diff --git a/src/elements/DetailsPopUp/FeatureSetPopUp/FeatureSetPopUp.jsx b/src/elements/DetailsPopUp/FeatureSetPopUp/FeatureSetPopUp.jsx index 2463712a83..7a0826247c 100644 --- a/src/elements/DetailsPopUp/FeatureSetPopUp/FeatureSetPopUp.jsx +++ b/src/elements/DetailsPopUp/FeatureSetPopUp/FeatureSetPopUp.jsx @@ -28,7 +28,7 @@ import { generatePageData, generateActionsMenu } from '../../../components/FeatureStore/FeatureSets/featureSets.util' -import { showErrorNotification } from '../../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { toggleYaml } from '../../../reducers/appReducer' import { fetchFeatureSet } from '../../../reducers/featureStoreReducer' diff --git a/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx b/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx index c429f175ff..7559c04f65 100644 --- a/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx +++ b/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx @@ -24,7 +24,7 @@ import PropTypes from 'prop-types' import DetailsPopUp from '../DetailsPopUp' -import { showErrorNotification } from '../../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { parseFeatureVectors } from '../../../utils/parseFeatureVectors' import { generateActionsMenu, diff --git a/src/elements/DetailsPopUp/FunctionPopUp/FunctionPopUp.jsx b/src/elements/DetailsPopUp/FunctionPopUp/FunctionPopUp.jsx index 7870fcd204..9a2314f217 100644 --- a/src/elements/DetailsPopUp/FunctionPopUp/FunctionPopUp.jsx +++ b/src/elements/DetailsPopUp/FunctionPopUp/FunctionPopUp.jsx @@ -32,7 +32,7 @@ import { } from '../../../components/FunctionsPage/functions.util' import { parseFunction } from '../../../utils/parseFunction' import { parseFunctionUri } from '../../../utils/link-helper.util' -import { showErrorNotification } from '../../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import functionsApi from '../../../api/functions-api' import { toggleYaml } from '../../../reducers/appReducer' diff --git a/src/elements/DetailsPopUp/JobPopUp/JobPopUp.jsx b/src/elements/DetailsPopUp/JobPopUp/JobPopUp.jsx index b9067bf438..f3798b26ec 100644 --- a/src/elements/DetailsPopUp/JobPopUp/JobPopUp.jsx +++ b/src/elements/DetailsPopUp/JobPopUp/JobPopUp.jsx @@ -30,7 +30,7 @@ import { generatePageData } from '../../JobsTable/jobsTable.util' import { getJobLogs } from '../../../utils/getJobLogs.util' import { enrichRunWithFunctionFields, monitorJob } from '../../../components/Jobs/jobs.util' import { generateActionsMenu } from '../../../components/Jobs/MonitorJobs/monitorJobs.util' -import { showErrorNotification } from '../../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { usePods } from '../../../hooks/usePods.hook' import { toggleYaml } from '../../../reducers/appReducer' import { fetchJob } from '../../../reducers/jobReducer' diff --git a/src/elements/EnvironmentVariables/EnvironmentVariablesView.jsx b/src/elements/EnvironmentVariables/EnvironmentVariablesView.jsx index 44aab7c701..aae6798674 100644 --- a/src/elements/EnvironmentVariables/EnvironmentVariablesView.jsx +++ b/src/elements/EnvironmentVariables/EnvironmentVariablesView.jsx @@ -21,11 +21,10 @@ import React from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import ActionsMenu from '../../common/ActionsMenu/ActionsMenu' import AddEnvironmentVariablesRow from './AddEnvironmentVariablesRow' import EditableEnvironmentVariablesRow from './EditableEnvironmentVariablesRow' import PanelSection from '../PanelSection/PanelSection' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, ActionsMenu } from 'igz-controls/components' import { tableHeaders } from './environmentVariables.util' diff --git a/src/elements/FeatureStoreTableRow/FeatureStoreTableRow.jsx b/src/elements/FeatureStoreTableRow/FeatureStoreTableRow.jsx index cfe7a39979..7774004574 100644 --- a/src/elements/FeatureStoreTableRow/FeatureStoreTableRow.jsx +++ b/src/elements/FeatureStoreTableRow/FeatureStoreTableRow.jsx @@ -24,12 +24,9 @@ import { useParams } from 'react-router-dom' import { createPortal } from 'react-dom' import { isEmpty } from 'lodash' -import ActionsMenu from '../../common/ActionsMenu/ActionsMenu' -import ErrorMessage from '../../common/ErrorMessage/ErrorMessage' -import Loader from '../../common/Loader/Loader' -import TableCell from '../TableCell/TableCell' +import { ErrorMessage, Loader, ActionsMenu, TableCell } from 'igz-controls/components' -import { ACTIONS_MENU } from '../../types' +import { ACTIONS_MENU } from 'igz-controls/types' import { DETAILS_OVERVIEW_TAB, TABLE_CONTAINER } from '../../constants' import { generateTableRowTestId } from '../../utils/generateTableRowTestId' import { getIdentifierMethod } from '../../utils/getUniqueIdentifier' @@ -86,7 +83,7 @@ const FeatureStoreTableRow = ({ !data.hidden && ( { diff --git a/src/elements/FunctionCardTemplate/FunctionCardTemplate.jsx b/src/elements/FunctionCardTemplate/FunctionCardTemplate.jsx index c67ad8976c..3732d12128 100644 --- a/src/elements/FunctionCardTemplate/FunctionCardTemplate.jsx +++ b/src/elements/FunctionCardTemplate/FunctionCardTemplate.jsx @@ -24,7 +24,7 @@ import { get } from 'lodash' import { FormChipCell, Tooltip, TextTooltipTemplate } from 'igz-controls/components' -import { getChipOptions } from '../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import './functionCardTemplate.scss' diff --git a/src/elements/FunctionPanelTopologyModelTable/FunctionPanelTopologyModelTableView.jsx b/src/elements/FunctionPanelTopologyModelTable/FunctionPanelTopologyModelTableView.jsx index bf07227920..01a04788c6 100644 --- a/src/elements/FunctionPanelTopologyModelTable/FunctionPanelTopologyModelTableView.jsx +++ b/src/elements/FunctionPanelTopologyModelTable/FunctionPanelTopologyModelTableView.jsx @@ -22,10 +22,9 @@ import { map } from 'lodash' import classnames from 'classnames' import PropTypes from 'prop-types' -import ActionsMenu from '../../common/ActionsMenu/ActionsMenu' import AddRouteRow from './AddRouteRow' import EditableRouteRow from './EditableRouteRow' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, ActionsMenu } from 'igz-controls/components' import { tableHeaders } from './functionPanelTopologyModelTable.util' diff --git a/src/elements/FunctionsPanelCode/FunctionsPanelCode.jsx b/src/elements/FunctionsPanelCode/FunctionsPanelCode.jsx index 1b5d89a8d8..0086b98760 100644 --- a/src/elements/FunctionsPanelCode/FunctionsPanelCode.jsx +++ b/src/elements/FunctionsPanelCode/FunctionsPanelCode.jsx @@ -33,7 +33,7 @@ import { sourceCodeInBase64 } from './functionsPanelCode.util' import { FUNCTION_DEFAULT_HANDLER, PANEL_CREATE_MODE, TAG_LATEST } from '../../constants' -import { splitTrim, trimSplit } from '../../utils' +import { splitTrim, trimSplit } from 'igz-controls/utils/string.util' import { resetNewFunctionCodeCustomImage, setNewFunctionBaseImage, diff --git a/src/elements/FunctionsPanelCode/FunctionsPanelCodeView.jsx b/src/elements/FunctionsPanelCode/FunctionsPanelCodeView.jsx index 6134ac9055..9e45d6e198 100644 --- a/src/elements/FunctionsPanelCode/FunctionsPanelCodeView.jsx +++ b/src/elements/FunctionsPanelCode/FunctionsPanelCodeView.jsx @@ -49,7 +49,7 @@ import { } from '../../reducers/functionReducer' import { FUNCTION_TYPE_SERVING, PANEL_EDIT_MODE } from '../../constants' import { LABEL_BUTTON } from 'igz-controls/constants' -import { splitTrim, trimSplit } from '../../utils' +import { splitTrim, trimSplit } from 'igz-controls/utils/string.util' import Edit from 'igz-controls/images/edit.svg?react' diff --git a/src/elements/FunctionsPanelGeneral/FunctionsPanelGeneralView.jsx b/src/elements/FunctionsPanelGeneral/FunctionsPanelGeneralView.jsx index d845475247..fbf6c883a1 100644 --- a/src/elements/FunctionsPanelGeneral/FunctionsPanelGeneralView.jsx +++ b/src/elements/FunctionsPanelGeneral/FunctionsPanelGeneralView.jsx @@ -26,7 +26,7 @@ import TextArea from '../../common/TextArea/TextArea' import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' import { getInternalLabelsValidationRule } from 'igz-controls/utils/validation.util' -import { getChipOptions } from '../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import { TAG_LATEST } from '../../constants' diff --git a/src/elements/FunctionsPanelParameters/FunctionsPanelParametersView.jsx b/src/elements/FunctionsPanelParameters/FunctionsPanelParametersView.jsx index 6d94ffc70a..0bdb940f1b 100644 --- a/src/elements/FunctionsPanelParameters/FunctionsPanelParametersView.jsx +++ b/src/elements/FunctionsPanelParameters/FunctionsPanelParametersView.jsx @@ -22,11 +22,10 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import { map } from 'lodash' -import ActionsMenu from '../../common/ActionsMenu/ActionsMenu' import AddFunctionParameterRow from './AddFunctionParameterRow' import EditableFunctionParameterRow from './EditableFunctionParameterRow' import PanelSection from '../PanelSection/PanelSection' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, ActionsMenu } from 'igz-controls/components' import { tableHeaders } from './functionsPanelParameters.util' diff --git a/src/elements/FunctionsTableRow/FunctionsTableRow.jsx b/src/elements/FunctionsTableRow/FunctionsTableRow.jsx index e02e637132..61b35c8f1e 100644 --- a/src/elements/FunctionsTableRow/FunctionsTableRow.jsx +++ b/src/elements/FunctionsTableRow/FunctionsTableRow.jsx @@ -22,10 +22,9 @@ import PropTypes from 'prop-types' import classnames from 'classnames' import { useParams } from 'react-router-dom' -import ActionsMenu from '../../common/ActionsMenu/ActionsMenu' -import TableCell from '../TableCell/TableCell' +import { ActionsMenu, TableCell } from 'igz-controls/components' -import { ACTIONS_MENU } from '../../types' +import { ACTIONS_MENU } from 'igz-controls/types' import { DETAILS_OVERVIEW_TAB } from '../../constants' import { getFunctionIdentifier } from '../../utils/getUniqueIdentifier' @@ -54,7 +53,7 @@ const FunctionsTableRow = ({ return ( !value.hidden && ( {}, rowItem, selectedJob = {} }) => { @@ -44,7 +43,7 @@ const JobsTableRow = ({ actionsMenu, handleSelectJob = () => {}, rowItem, select return ( !rowItemProp.hidden && ( { @@ -159,6 +160,7 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { ) ? upperFirst(lowerCase(func.status.state)) : 'Building', + types: typesOfJob, className: funcClassName } } diff --git a/src/elements/ProjectJobs/projectJobs.utils.js b/src/elements/ProjectJobs/projectJobs.utils.js index b12dba2610..68b539e55e 100644 --- a/src/elements/ProjectJobs/projectJobs.utils.js +++ b/src/elements/ProjectJobs/projectJobs.utils.js @@ -19,9 +19,10 @@ such restriction. */ import { orderBy } from 'lodash' -import { MONITOR_JOBS_TAB, MONITOR_WORKFLOWS_TAB, SCHEDULE_TAB } from '../../constants' -import { formatDatetime } from '../../utils' import { measureTime } from '../../utils/measureTime' +import { MONITOR_JOBS_TAB, MONITOR_WORKFLOWS_TAB, SCHEDULE_TAB } from '../../constants' +import { formatDatetime } from 'igz-controls/utils/datetime.util' +import { typesOfJob } from '../../utils/jobs.util' export const getJobsStatistics = (projectCounter, projectName) => { return { @@ -76,7 +77,8 @@ export const getJobsTableData = (jobs, projectName) => { }, type: { value: job[0].metadata.kind ?? job[0].metadata.labels?.kind ?? '', - className: 'section-table__table-cell table-cell_small' + className: 'section-table__table-cell table-cell_small', + types: typesOfJob }, status: { value: job.map(item => item.status.state), diff --git a/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.jsx b/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.jsx index cc18cbb7f1..adebb5e51b 100644 --- a/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.jsx +++ b/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.jsx @@ -33,10 +33,10 @@ import { FormInput, FormOnChange, FormTextarea, - Tip + Tip, + Loader } from 'igz-controls/components' import ChangeOwnerPopUp from '../ChangeOwnerPopUp/ChangeOwnerPopUp' -import Loader from '../../common/Loader/Loader' import projectsApi from '../../api/projects-api' import { @@ -58,15 +58,15 @@ import { setFieldState } from 'igz-controls/utils/form.util' import { FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' -import { getChipOptions } from '../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import { getErrorMsg } from 'igz-controls/utils/common.util' import { getValidationRules, getInternalLabelsValidationRule } from 'igz-controls/utils/validation.util' import { parseChipsData, convertChipsData } from '../../utils/convertChipsData' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { areNodeSelectorsSupported } from './projectSettingsGeneral.utils' import { fetchProject, removeProjectData } from '../../reducers/projectReducer' diff --git a/src/elements/ProjectSettingsMembers/ProjectSettingsMembers.jsx b/src/elements/ProjectSettingsMembers/ProjectSettingsMembers.jsx index c179c176a4..d56b4b79cb 100644 --- a/src/elements/ProjectSettingsMembers/ProjectSettingsMembers.jsx +++ b/src/elements/ProjectSettingsMembers/ProjectSettingsMembers.jsx @@ -21,7 +21,7 @@ import React from 'react' import PropTypes from 'prop-types' import MembersPopUp from '../MembersPopUp/MembersPopUp' -import Loader from '../../common/Loader/Loader' +import { Loader } from 'igz-controls/components' import Users from 'igz-controls/images/users.svg?react' diff --git a/src/elements/ProjectSettingsSecrets/ProjectSettingsSecrets.jsx b/src/elements/ProjectSettingsSecrets/ProjectSettingsSecrets.jsx index ea2d92a942..2a74f1dc08 100644 --- a/src/elements/ProjectSettingsSecrets/ProjectSettingsSecrets.jsx +++ b/src/elements/ProjectSettingsSecrets/ProjectSettingsSecrets.jsx @@ -26,8 +26,7 @@ import { differenceWith, isEmpty, isEqual } from 'lodash' import { useParams } from 'react-router-dom' import arrayMutators from 'final-form-arrays' -import Loader from '../../common/Loader/Loader' -import { FormKeyValueTable } from 'igz-controls/components' +import { FormKeyValueTable, Loader } from 'igz-controls/components' import { ADD_PROJECT_SECRET, @@ -40,7 +39,7 @@ import { areFormValuesChanged, setFieldState } from 'igz-controls/utils/form.uti import { fetchProjectSecrets, removeProjectData } from '../../reducers/projectReducer' import { getErrorMsg } from 'igz-controls/utils/common.util' import { getValidationRules } from 'igz-controls/utils/validation.util' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' const ProjectSettingsSecrets = ({ setNotification }) => { const [modifyingIsInProgress, setModifyingIsInProgress] = useState(false) diff --git a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx index 118079b01e..933bdfab83 100644 --- a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx +++ b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx @@ -21,8 +21,7 @@ import React from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import Loader from '../../common/Loader/Loader' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import Arrow from 'igz-controls/images/arrow.svg?react' diff --git a/src/elements/ProjectSummaryCard/ProjectSummaryCard.jsx b/src/elements/ProjectSummaryCard/ProjectSummaryCard.jsx index 8f0685b0ab..3a7c16b1b3 100644 --- a/src/elements/ProjectSummaryCard/ProjectSummaryCard.jsx +++ b/src/elements/ProjectSummaryCard/ProjectSummaryCard.jsx @@ -21,8 +21,7 @@ import React from 'react' import { useNavigate } from 'react-router-dom' import PropTypes from 'prop-types' -import Loader from '../../common/Loader/Loader' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import StatsCard from '../../common/StatsCard/StatsCard' const ProjectSummaryCard = ({ diff --git a/src/common/TabsSlider/tabsSlider.scss b/src/elements/ProjectTable/ProjectTable.jsx similarity index 100% rename from src/common/TabsSlider/tabsSlider.scss rename to src/elements/ProjectTable/ProjectTable.jsx diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index 629190cf65..a0a29cc3fa 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -22,8 +22,8 @@ import { useNavigate, useParams } from 'react-router-dom' import { useSelector } from 'react-redux' import classNames from 'classnames' -import Loader from '../../common/Loader/Loader' import StatsCard from '../../common/StatsCard/StatsCard' +import { Loader } from 'igz-controls/components' import { generateAlertsStats } from '../../utils/generateAlertsStats' diff --git a/src/elements/ProjectsMonitoringCounters/JobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/JobsCounters.jsx index 4933b0e8ef..8b62ec1362 100644 --- a/src/elements/ProjectsMonitoringCounters/JobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/JobsCounters.jsx @@ -21,9 +21,8 @@ import React, { useMemo } from 'react' import { useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' -import Loader from '../../common/Loader/Loader' import StatsCard from '../../common/StatsCard/StatsCard' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import { generateMonitoringStats } from '../../utils/generateMonitoringData' import { JOBS_MONITORING_JOBS_TAB } from '../../constants' diff --git a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx index 9c3fef251c..28fccda82a 100644 --- a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx @@ -22,7 +22,7 @@ import { useSelector } from 'react-redux' import { useNavigate } from 'react-router-dom' import StatsCard from '../../common/StatsCard/StatsCard' -import Loader from '../../common/Loader/Loader' +import { Loader } from 'igz-controls/components' import { generateMonitoringStats } from '../../utils/generateMonitoringData' import { JOBS_MONITORING_SCHEDULED_TAB } from '../../constants' diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index 1fa047a64c..f859f3a3c3 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -21,9 +21,8 @@ import React, { useMemo } from 'react' import { useNavigate } from 'react-router-dom' import { useSelector } from 'react-redux' -import Loader from '../../common/Loader/Loader' import StatsCard from '../../common/StatsCard/StatsCard' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import { generateMonitoringStats } from '../../utils/generateMonitoringData' import { JOBS_MONITORING_WORKFLOWS_TAB } from '../../constants' diff --git a/src/elements/ReadOnlyChips/ReadOnlyChips.jsx b/src/elements/ReadOnlyChips/ReadOnlyChips.jsx index 7b6e4c839e..ee13d06ad5 100644 --- a/src/elements/ReadOnlyChips/ReadOnlyChips.jsx +++ b/src/elements/ReadOnlyChips/ReadOnlyChips.jsx @@ -20,14 +20,14 @@ such restriction. import React from 'react' import { Form } from 'react-final-form' import { createForm } from 'final-form' +import PropTypes from 'prop-types' import arrayMutators from 'final-form-arrays' import { FormChipCell } from 'igz-controls/components' -import { getChipOptions } from '../../utils/getChipOptions' +import { getChipOptions } from 'igz-controls/utils/chips.util' import { setFieldState } from 'igz-controls/utils/form.util' -import PropTypes from 'prop-types' -import { CHIP_OPTIONS } from '../../types.js' +import { CHIP_OPTIONS } from 'igz-controls/types' const ReadOnlyChips = ({ labels = [], chipOptions = getChipOptions('metrics'), ...args }) => { const formRef = React.useRef( diff --git a/src/elements/RealTimePipelinesTableRow/RealTimePipelinesTableRow.jsx b/src/elements/RealTimePipelinesTableRow/RealTimePipelinesTableRow.jsx index 7f2f4ca325..92183c7d6c 100644 --- a/src/elements/RealTimePipelinesTableRow/RealTimePipelinesTableRow.jsx +++ b/src/elements/RealTimePipelinesTableRow/RealTimePipelinesTableRow.jsx @@ -21,10 +21,9 @@ import React from 'react' import PropTypes from 'prop-types' import { useParams } from 'react-router-dom' -import TableCell from '../TableCell/TableCell' -import ActionsMenu from '../../common/ActionsMenu/ActionsMenu' +import { ActionsMenu, TableCell } from 'igz-controls/components' -import { ACTIONS_MENU } from '../../types' +import { ACTIONS_MENU } from 'igz-controls/types' import { DETAILS_OVERVIEW_TAB } from '../../constants' const RealTimePipelinesTableRow = ({ actionsMenu, rowItem }) => { @@ -36,7 +35,7 @@ const RealTimePipelinesTableRow = ({ actionsMenu, rowItem }) => { return ( !value.hidden && ( { ) return key === 'type' ? ( - + ) : ( {key === 'name' ? ( diff --git a/src/elements/TableCell/TableCell.jsx b/src/elements/TableCell/TableCell.jsx deleted file mode 100644 index 8f8b920f70..0000000000 --- a/src/elements/TableCell/TableCell.jsx +++ /dev/null @@ -1,226 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React, { cloneElement } from 'react' -import PropTypes from 'prop-types' -import { useDispatch } from 'react-redux' -import classnames from 'classnames' -import { useParams } from 'react-router-dom' - -import ChipCell from '../../common/ChipCell/ChipCell' -import CopyToClipboard from '../../common/CopyToClipboard/CopyToClipboard' -import Download from '../../common/Download/Download' -import TableLinkCell from '../TableLinkCell/TableLinkCell' -import TableTypeCell from '../TableTypeCell/TableTypeCell' -import { Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' - -import { BUTTON_COPY_URI_CELL_TYPE, DATASET_TYPE, MODEL_TYPE } from '../../constants' -import { getChipOptions } from '../../utils/getChipOptions' -import { showArtifactsPreview } from '../../reducers/artifactsReducer' -import { truncateUid } from '../../utils' - -import ArtifactView from 'igz-controls/images/eye-icon.svg?react' -import Arrow from 'igz-controls/images/arrow.svg?react' - -const TableCell = ({ - className = '', - data, - firstCell, - item = { - target_path: '', - schema: '' - }, - link = '', - onClick = null, - selectItem = () => {}, - selectedItem = {}, - showExpandButton = false, - toggleRow = null -}) => { - const dispatch = useDispatch() - const params = useParams() - const { value: stateValue, label: stateLabel, className: stateClassName } = item.state ?? {} - const cellClassNames = classnames( - 'table-body__cell', - data.className, - className, - data.bodyCellClassName, - onClick && 'link' - ) - - if (data.template) { - return cloneElement(data.template, { - className - }) - } else if (link && data.type !== 'hidden') { - return ( - - ) - } else if (firstCell && !link) { - return ( - data.value && onClick && onClick(data.value)} className={cellClassNames}> -
      - {data && ( - }> - {data.value} - - )} -
      - {item.state && stateValue && stateLabel && ( - }> - - - )} - {!item.state && item.status && ( - }> - - - )} - {showExpandButton && ( - toggleRow && toggleRow(e, item)} className="expand-arrow" /> - )} - - ) - } else if (data.type === 'type') { - return - } else if (data.type === 'icons') { - return ( - - {data.value.map((valueItem, index) => ( - } - > - {valueItem.icon} - - ))} - - ) - } else if (Array.isArray(data.value)) { - return ( - - - - ) - } else if (data.type === 'buttonPopout') { - return ( - - { - dispatch( - showArtifactsPreview({ - isPreview: true, - selectedItem: item - }) - ) - }} - > - - - - ) - } else if (data.type === 'buttonDownload') { - return ( - - - - ) - } else if (data.type === BUTTON_COPY_URI_CELL_TYPE) { - return ( - - - - ) - } else if (data.type === 'hash') { - return ( - - }> - {truncateUid(data.value)} - - - ) - } else if (data.type === 'hidden') { - return null - } else if (data.type === 'component') { - return ( - - {data.value} - - ) - } else { - return ( - data.value && onClick && onClick(data.value)} - > - } - > - {data.value} - - - ) - } -} - -TableCell.propTypes = { - className: PropTypes.string, - data: PropTypes.object.isRequired, - firstCell: PropTypes.bool, - item: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]), - link: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), - onClick: PropTypes.func, - selectItem: PropTypes.func, - selectedItem: PropTypes.object, - showExpandButton: PropTypes.bool, - toggleRow: PropTypes.func -} - -export default TableCell diff --git a/src/elements/TableLinkCell/TableLinkCell.jsx b/src/elements/TableLinkCell/TableLinkCell.jsx deleted file mode 100644 index 8725530168..0000000000 --- a/src/elements/TableLinkCell/TableLinkCell.jsx +++ /dev/null @@ -1,151 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' -import { Link } from 'react-router-dom' -import PropTypes from 'prop-types' -import classnames from 'classnames' - -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' - -import { formatDatetime, truncateUid } from '../../utils' - -import Arrow from 'igz-controls/images/arrow.svg?react' - -import './tableLinkCell.scss' - -const TableLinkCell = ({ - className = '', - data = {}, - item, - link, - selectItem, - selectedItem = {}, - showExpandButton = false, - toggleRow = null -}) => { - const tableCellClassNames = classnames( - 'table-body__cell', - data.className, - className, - data.bodyCellClassName - ) - const itemNameClassNames = classnames('item-name') - const { value: stateValue, label: stateLabel, className: stateClassName } = item.state ?? {} - - return ( - - {data.linkIsExternal ? ( - - - } - > - {data.value} - - - {data.showStatus && stateValue && stateLabel && ( - }> - - - )} - - - ) : ( - selectItem(item)} className="data-ellipsis"> -
      -
      - } - > - {data.value} - - - {data.showStatus && stateValue && stateLabel && ( - }> - - - )} -
      - {data.showTag && ( - }> - {item.tag} - - )} -
      - {(data.showUidRow || - ((link.match(/functions/) || - link.match(/models/) || - link.match(/files/) || - link.match(/datasets/) || - link.match(/documents/) || - link.match(/llm-prompts/)) && - Object.values(selectedItem).length !== 0)) && ( -
      - {(item.startTime || item.updated) && ( - - {data.type !== 'date' && - (link.match(/functions/) || - link.match(/models/) || - link.match(/files/) || - link.match(/datasets/) || - link.match(/llm-prompts/) - ? formatDatetime(item.updated, 'N/A') - : formatDatetime( - item.startTime || item.created, - stateValue === 'aborted' ? 'N/A' : 'Not yet started' - ))} - - )} - {data.value !== item.uid && data.value !== item.hash && ( - {truncateUid(item.uid || item.hash)} - )} -
      - )} - {data.additionalInfo && Object.values(selectedItem).length !== 0 && ( - {data.additionalInfo} - )} - - )} - {showExpandButton && ( - { - toggleRow && toggleRow(e, item) - }} - className="expand-arrow" - /> - )} - - ) -} - -TableLinkCell.propTypes = { - className: PropTypes.string, - data: PropTypes.object, - item: PropTypes.object.isRequired, - link: PropTypes.string.isRequired, - selectItem: PropTypes.func.isRequired, - selectedItem: PropTypes.object, - showExpandButton: PropTypes.bool, - toggleRow: PropTypes.func -} - -export default TableLinkCell diff --git a/src/elements/TableLinkCell/tableLinkCell.scss b/src/elements/TableLinkCell/tableLinkCell.scss deleted file mode 100644 index 369311c2d6..0000000000 --- a/src/elements/TableLinkCell/tableLinkCell.scss +++ /dev/null @@ -1,66 +0,0 @@ -@use 'igz-controls/scss/colors'; - -.table { - .table-body__cell { - line-height: 20px; - - .name-wrapper { - display: flex; - flex: 1; - flex-wrap: wrap; - align-items: center; - - .item { - &-name { - color: colors.$primary; - font-weight: bold; - - &.function-name { - max-width: 120px; - } - } - - &-tag { - max-width: 150px; - - span { - display: inline; - } - } - } - - .link { - display: flex; - width: 100%; - color: colors.$primary; - } - } - - .link-subtext { - color: colors.$topaz; - } - - .date-uid-row { - display: flex; - align-items: center; - justify-content: space-between; - font-weight: normal; - font-size: 12px; - font-family: Roboto, sans-serif; - font-style: normal; - margin-top: 5px; - width: max-content; - min-width: 100%; - - & > span { - &:not(:last-child) { - margin-right: 10px; - } - } - - span { - width: auto; - } - } - } -} diff --git a/src/elements/TableTypeCell/TableTypeCell.jsx b/src/elements/TableTypeCell/TableTypeCell.jsx deleted file mode 100644 index c03007a971..0000000000 --- a/src/elements/TableTypeCell/TableTypeCell.jsx +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import React from 'react' -import PropTypes from 'prop-types' -import { capitalize } from 'lodash' -import classnames from 'classnames' - -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' - -import Application from 'igz-controls/images/application-icon.svg?react' -import Serving from 'igz-controls/images/serving-icon.svg?react' - -import Code from 'igz-controls/images/code.svg?react' -import DatabricksIcon from 'igz-controls/images/databricks-icon.svg?react' -import Horovod from 'igz-controls/images/horovod.svg?react' -import Jupyter from 'igz-controls/images/jupyter.svg?react' -import Nuclio from 'igz-controls/images/nuclio.svg?react' -import Package from 'igz-controls/images/package.svg?react' -import Remote from 'igz-controls/images/ic_remote.svg?react' -import Spark from 'igz-controls/images/spark.svg?react' -import Workflow from 'igz-controls/images/workflow-icon.svg?react' -import { - FUNCTION_TYPE_APPLICATION, - JOB_KIND_DASK, - JOB_KIND_DATABRICKS, - JOB_KIND_HANDLER, - JOB_KIND_MPIJOB, - JOB_KIND_JOB, - JOB_KIND_LOCAL, - JOB_KIND_REMOTE, - JOB_KIND_NUCLIO, - JOB_KIND_SERVING, - JOB_KIND_SPARK, - JOB_KIND_WORKFLOW -} from '../../constants' - -const TableTypeCell = ({ className = '', data }) => { - const typesOfJob = { - '': { label: 'Local', icon: }, - [FUNCTION_TYPE_APPLICATION]: { label: 'Application', icon: }, - [JOB_KIND_DASK]: { label: 'Dask', icon: null }, - [JOB_KIND_DATABRICKS]: { label: 'Databricks', icon: }, - [JOB_KIND_HANDLER]: { label: 'Handler', icon: }, - [JOB_KIND_JOB]: { label: 'Job', icon: }, - [JOB_KIND_LOCAL]: { label: 'Local', icon: }, - [JOB_KIND_MPIJOB]: { label: 'Horovod', icon: }, - [JOB_KIND_NUCLIO]: { label: 'Nuclio', icon: }, - [JOB_KIND_REMOTE]: { label: 'Remote', icon: }, - [JOB_KIND_SERVING]: { label: 'Serving', icon: }, - [JOB_KIND_SPARK]: { label: 'Spark', icon: }, - [JOB_KIND_WORKFLOW]: { label: 'Workflow', icon: } - } - const cellClassNames = classnames( - 'table-body__cell', - data.className, - data.bodyCellClassName, - className - ) - - return ( - - - } - > - {typesOfJob[data.value]?.icon ?? capitalize(data.value)} - - - ) -} - -TableTypeCell.propTypes = { - className: PropTypes.string, - data: PropTypes.object.isRequired -} - -export default TableTypeCell diff --git a/src/elements/VolumesTable/VolumesTableView.jsx b/src/elements/VolumesTable/VolumesTableView.jsx index 4ab16fa19a..de5fe997a5 100644 --- a/src/elements/VolumesTable/VolumesTableView.jsx +++ b/src/elements/VolumesTable/VolumesTableView.jsx @@ -22,11 +22,10 @@ import { find, has, map } from 'lodash' import classnames from 'classnames' import PropTypes from 'prop-types' -import ActionsMenu from '../../common/ActionsMenu/ActionsMenu' import EditableVolumesRow from '../EditableVolumesRow/EditableVolumesRow' import Input from '../../common/Input/Input' import Select from '../../common/Select/Select' -import { Tip, Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tip, Tooltip, TextTooltipTemplate, ActionsMenu } from 'igz-controls/components' import { getVolumeTypeInput, @@ -36,7 +35,7 @@ import { tableHeaders, V3IO } from './volumesTable.util' -import { joinDataOfArrayOrObject } from '../../utils' +import { joinDataOfArrayOrObject } from 'igz-controls/utils/string.util' import Plus from 'igz-controls/images/plus.svg?react' import Delete from 'igz-controls/images/delete.svg?react' diff --git a/src/elements/WorkflowsTable/WorkflowsTable.jsx b/src/elements/WorkflowsTable/WorkflowsTable.jsx index 8dfcc4e741..6cb668cdb9 100644 --- a/src/elements/WorkflowsTable/WorkflowsTable.jsx +++ b/src/elements/WorkflowsTable/WorkflowsTable.jsx @@ -25,10 +25,10 @@ import { find, isEmpty } from 'lodash' import JobWizard from '../../components/JobWizard/JobWizard' import JobsTableRow from '../JobsTableRow/JobsTableRow' -import Loader from '../../common/Loader/Loader' import NoData from '../../common/NoData/NoData' import Table from '../../components/Table/Table' import Workflow from '../../components/Workflow/Workflow' +import { Loader } from 'igz-controls/components' import { ERROR_STATE, @@ -70,8 +70,8 @@ import { import { openPopUp, getScssVariableValue } from 'igz-controls/utils/common.util' import { parseFunction } from '../../utils/parseFunction' import { parseJob } from '../../utils/parseJob' -import { setNotification } from '../../reducers/notificationReducer' -import { showErrorNotification } from '../../utils/notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { toggleYaml } from '../../reducers/appReducer' import { useSortTable } from '../../hooks/useSortTable.hook' diff --git a/src/hooks/useDetailsHeader.hook.jsx b/src/hooks/useDetailsHeader.hook.jsx new file mode 100644 index 0000000000..238ac0ad62 --- /dev/null +++ b/src/hooks/useDetailsHeader.hook.jsx @@ -0,0 +1,272 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ + +import React, { useCallback, useRef } from 'react' +import PropTypes from 'prop-types' +import { useDispatch, useSelector } from 'react-redux' +import { Link, useLocation, useNavigate, useParams } from 'react-router-dom' + +import { + Button, + RoundedIcon, + TextTooltipTemplate, + Tooltip, + LoadButton, + ActionsMenu +} from 'igz-controls/components' + +import { ACTION_BUTTON, ACTIONS_MENU } from 'igz-controls/types' +import { TERTIARY_BUTTON, VIEW_SEARCH_PARAMETER, FULL_VIEW_MODE } from 'igz-controls/constants' +import { getFilteredSearchParams } from 'igz-controls/utils/filter.util' +import { getViewMode } from 'igz-controls/utils/common.util' + +import Close from 'igz-controls/images/close.svg?react' +import EnlargeIcon from 'igz-controls/images/ml-enlarge.svg?react' +import HistoryIcon from 'igz-controls/images/history.svg?react' +import MinimizeIcon from 'igz-controls/images/ml-minimize.svg?react' +import Refresh from 'igz-controls/images/refresh.svg?react' + +const DetailsHeaderContainer = ({ + actionButton = null, + actionsMenu, + applyChanges, + applyChangesRef, + cancelChanges, + commonDetailsStore, + getCloseDetailsLink = null, + getDefaultCloseDetailsLink, + handleCancelClick, + handleRefresh = null, + headerRef, + isDetailsPopUp = false, + isDetailsScreen, + location, + navigate, + pageData, + params, + renderCustomElements = null, + renderStatus = null, + renderTitle, + selectedItem, + showAllVersions = null, + tab = '', + viewMode = '', + withActionMenu = true, + withToggleViewBtn = false +}) => { + return ( +
      +
      +

      {renderTitle && renderTitle()}

      +
      {renderStatus && renderStatus()}
      +
      +
      + {renderCustomElements && renderCustomElements()} +
      +
      + {commonDetailsStore.changes.counter > 0 && !isDetailsPopUp && ( + <> +
      +
      + ) +} + +DetailsHeaderContainer.propTypes = { + actionButton: ACTION_BUTTON, + actionsMenu: ACTIONS_MENU.isRequired, + applyChanges: PropTypes.func.isRequired, + applyChangesRef: PropTypes.object.isRequired, + cancelChanges: PropTypes.func.isRequired, + commonDetailsStore: PropTypes.object.isRequired, + getCloseDetailsLink: PropTypes.func, + getDefaultCloseDetailsLink: PropTypes.func.isRequired, + handleCancelClick: PropTypes.func.isRequired, + handleRefresh: PropTypes.func, + headerRef: PropTypes.object.isRequired, + isDetailsPopUp: PropTypes.bool, + isDetailsScreen: PropTypes.bool.isRequired, + location: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, + pageData: PropTypes.object.isRequired, + params: PropTypes.object.isRequired, + renderCustomElements: PropTypes.func, + renderStatus: PropTypes.func, + renderTitle: PropTypes.func.isRequired, + selectedItem: PropTypes.object.isRequired, + showAllVersions: PropTypes.func, + tab: PropTypes.string, + viewMode: PropTypes.string, + withActionMenu: PropTypes.bool, + withToggleViewBtn: PropTypes.bool +} + +export const useDetailsHeader = ({ handleCancel, handleShowWarning, isDetailsPopUp, pageData }) => { + const commonDetailsStore = useSelector(store => store.commonDetailsStore) + const params = useParams() + const navigate = useNavigate() + const viewMode = getViewMode(window.location.search) + const { actionButton, withToggleViewBtn, showAllVersions } = pageData.details + const headerRef = useRef() + const location = useLocation() + const dispatch = useDispatch() + + const handleBackClick = useCallback(() => { + if (commonDetailsStore.changes.counter > 0) { + handleShowWarning(true) + } else if (handleCancel) { + handleCancel() + } + }, [commonDetailsStore.changes.counter, handleCancel, handleShowWarning]) + + const handleCancelClick = useCallback(() => { + if (handleCancel && (commonDetailsStore.changes.counter === 0 || isDetailsPopUp)) { + handleCancel() + } + }, [commonDetailsStore.changes.counter, handleCancel, isDetailsPopUp]) + + return { + DetailsHeaderContainer, + actionButton, + commonDetailsStore, + dispatch, + handleBackClick, + handleCancelClick, + headerRef, + location, + navigate, + params, + showAllVersions, + viewMode, + withToggleViewBtn + } +} diff --git a/src/hooks/useJobsPageData.js b/src/hooks/useJobsPageData.js index e2f889ac20..db077b3a86 100644 --- a/src/hooks/useJobsPageData.js +++ b/src/hooks/useJobsPageData.js @@ -39,7 +39,7 @@ import { parseJob } from '../utils/parseJob' import { fetchAllJobRuns, fetchJobs, fetchScheduledJobs } from '../reducers/jobReducer' import { fetchWorkflows } from '../reducers/workflowReducer' import { useFiltersFromSearchParams } from './useFiltersFromSearchParams.hook' -import { getSavedSearchParams } from '../utils/filter.util' +import { getSavedSearchParams } from 'igz-controls/utils/filter.util' import { useRefreshAfterDelete } from './useRefreshAfterDelete.hook' export const useJobsPageData = (initialTabData, selectedTab) => { diff --git a/src/hooks/useVirtualization.hook.js b/src/hooks/useVirtualization.hook.js index 3f8c42d63a..41184a7233 100644 --- a/src/hooks/useVirtualization.hook.js +++ b/src/hooks/useVirtualization.hook.js @@ -19,7 +19,7 @@ such restriction. */ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { isEmpty, isEqual, sum, throttle } from 'lodash' -import { MAIN_TABLE_ID, MAIN_TABLE_BODY_ID } from '../constants' +import { MAIN_TABLE_ID, MAIN_TABLE_BODY_ID } from 'igz-controls/constants' const HIDDEN_RENDER_ITEMS_LENGTH = 5 const virtualizationConfigInitialState = { diff --git a/src/layout/Page/Page.jsx b/src/layout/Page/Page.jsx index 41e2f2f9aa..20ba4df3f2 100644 --- a/src/layout/Page/Page.jsx +++ b/src/layout/Page/Page.jsx @@ -27,7 +27,7 @@ import ModalContainer from 'react-modal-promise' import Navbar from '../Navbar/Navbar' import YamlModal from '../../common/YamlModal/YamlModal' -import Loader from '../../common/Loader/Loader' +import { Loader } from 'igz-controls/components' import { getTransitionEndEventName } from 'igz-controls/utils/common.util' import { fetchFrontendSpec, toggleYaml } from '../../reducers/appReducer' diff --git a/src/reducers/detailsReducer.js b/src/reducers/detailsReducer.js index f8bdf451f4..7911e68adc 100644 --- a/src/reducers/detailsReducer.js +++ b/src/reducers/detailsReducer.js @@ -31,25 +31,18 @@ import { TIME_FRAME_LIMITS } from '../utils/datePicker.util' import { largeResponseCatchHandler } from '../utils/largeResponseCatchHandler' const initialState = { - changes: { - counter: 0, - data: {} - }, dates: { value: DATE_FILTER_ANY_TIME, selectedOptionId: '', isPredefined: false }, - detailsPopUpInfoContent: {}, detailsJobPods: { loading: true, podsList: [], podsPending: [], podsTooltip: [] }, - editMode: false, error: null, - infoContent: {}, iteration: '', iterationOptions: [], loadingCounter: 0, @@ -60,8 +53,6 @@ const initialState = { podsPending: [], podsTooltip: [] }, - filtersWasHandled: false, - showWarning: false, metricsOptions: { all: [], lastSelected: [], @@ -159,45 +150,15 @@ const detailsStoreSlice = createSlice({ removeDetailsPods(state) { state.detailsJobPods = initialState.detailsJobPods }, - removeDetailsPopUpInfoContent(state) { - state.detailsPopUpInfoContent = {} - }, - removeInfoContent(state) { - state.infoContent = {} - }, removeModelFeatureVector(state) { state.modelFeatureVectorData = initialState.modelFeatureVectorData }, removePods(state) { state.pods = initialState.pods }, - resetChanges(state) { - state.changes = initialState.changes - }, - setChanges(state, action) { - state.changes = action.payload - }, - setChangesCounter(state, action) { - state.changes.counter = action.payload - }, - setChangesData(state, action) { - state.changes.data = action.payload - }, setDetailsDates(state, action) { state.dates = action.payload }, - setDetailsPopUpInfoContent(state, action) { - state.detailsPopUpInfoContent = action.payload - }, - setEditMode(state, action) { - state.editMode = action.payload - }, - setFiltersWasHandled(state, action) { - state.filtersWasHandled = action.payload - }, - setInfoContent(state, action) { - state.infoContent = action.payload - }, setIteration(state, action) { state.iteration = action.payload }, @@ -213,9 +174,6 @@ const detailsStoreSlice = createSlice({ [action.payload.endpointUid]: action.payload.metrics } } - }, - showWarning(state, action) { - state.showWarning = action.payload } }, extraReducers: builder => { @@ -307,23 +265,12 @@ const detailsStoreSlice = createSlice({ export const { removeDetailsPods, - removeDetailsPopUpInfoContent, - removeInfoContent, removeModelFeatureVector, removePods, - resetChanges, - setChanges, - setChangesCounter, - setChangesData, setDetailsDates, - setDetailsPopUpInfoContent, - setEditMode, - setFiltersWasHandled, - setInfoContent, setIteration, setIterationOption, - setSelectedMetricsOptions, - showWarning + setSelectedMetricsOptions } = detailsStoreSlice.actions export default detailsStoreSlice.reducer diff --git a/src/reducers/featureStoreReducer.js b/src/reducers/featureStoreReducer.js index 98ac108f81..4e39613ab5 100644 --- a/src/reducers/featureStoreReducer.js +++ b/src/reducers/featureStoreReducer.js @@ -33,7 +33,7 @@ import { largeResponseCatchHandler } from '../utils/largeResponseCatchHandler' import { parseFeatureSets } from '../utils/parseFeatureSets' import { parseFeatureVectors } from '../utils/parseFeatureVectors' import { parseFeatures } from '../utils/parseFeatures' -import { showErrorNotification } from '../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' const initialState = { error: null, diff --git a/src/reducers/functionReducer.js b/src/reducers/functionReducer.js index 55c7b89d39..67bdbfedef 100644 --- a/src/reducers/functionReducer.js +++ b/src/reducers/functionReducer.js @@ -24,7 +24,7 @@ import functionsApi from '../api/functions-api' import { hideLoading, showLoading } from './redux.util' import mlrunNuclioApi from '../api/mlrun-nuclio-api' import yaml from 'js-yaml' -import { showErrorNotification } from '../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { largeResponseCatchHandler } from '../utils/largeResponseCatchHandler' import { generateCategories, generateHubCategories } from '../utils/generateTemplatesCategories' diff --git a/src/reducers/jobReducer.js b/src/reducers/jobReducer.js index 6bca5d0be2..0f8c867ee0 100644 --- a/src/reducers/jobReducer.js +++ b/src/reducers/jobReducer.js @@ -31,7 +31,7 @@ import { } from '../constants' import { largeResponseCatchHandler } from '../utils/largeResponseCatchHandler' import functionsApi from '../api/functions-api' -import { showErrorNotification } from '../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { getNewJobErrorMsg } from '../components/JobWizard/JobWizard.util' const initialState = { diff --git a/src/reducers/notificationReducer.js b/src/reducers/notificationReducer.js deleted file mode 100644 index ee850f1f93..0000000000 --- a/src/reducers/notificationReducer.js +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import { createSlice } from '@reduxjs/toolkit' - -const initialState = { - notification: [] -} - -const notificationSlice = createSlice({ - name: 'notification', - initialState, - reducers: { - setNotification(state, { payload }) { - if (payload.error) { - /* eslint-disable-next-line no-console */ - console.error(payload.error) - } - - state.notification.push(payload) - }, - removeNotification(state, { payload }) { - state.notification = state.notification.filter(item => item.id !== payload) - } - } -}) - -export const { setNotification, removeNotification } = notificationSlice.actions - -export default notificationSlice.reducer diff --git a/src/reducers/projectReducer.js b/src/reducers/projectReducer.js index 5aa109650f..6959d1f581 100644 --- a/src/reducers/projectReducer.js +++ b/src/reducers/projectReducer.js @@ -28,7 +28,7 @@ import { } from 'igz-controls/constants' import { DEFAULT_ABORT_MSG, PROJECT_ONLINE_STATUS, REQUEST_CANCELED } from '../constants' import { parseProjects } from '../utils/parseProjects' -import { showErrorNotification } from '../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' import { parseSummaryData } from '../utils/parseSummaryData' import { mlrunUnhealthyErrors } from '../components/ProjectsPage/projects.util' diff --git a/src/scss/main.scss b/src/scss/main.scss index d851e8c047..b2cb72f875 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -40,310 +40,6 @@ body { } } -/* =========== CONTENT MENU ============= */ - -.content-menu { - display: inline-flex; - align-items: center; - width: 100%; - min-height: 40px; - - &__tabs-wrapper { - overflow-x: hidden; - } - - &__tabs { - display: flex; - flex-direction: row; - align-items: center; - list-style-type: none; - transition: transform 0.2s ease-in-out; - - @include mixins.resetSpaces; - } - - &__tab { - align-items: center; - margin: 0 15px 0 0; - padding: 5px; - color: colors.$topaz; - font-weight: 400; - line-height: 1; - white-space: nowrap; - text-align: center; - text-transform: capitalize; - cursor: pointer; - - &:first-child { - padding-left: 0; - } - - &-xs { - font-size: 16px; - } - - &-sm { - font-size: 16px; - - @media screen and (min-width: 1300px) { - font-size: 18px; - } - } - - &-md { - font-size: 18px; - - @media screen and (min-width: 1300px) { - font-size: 20px; - } - } - - &-lg { - font-size: 20px; - - @media screen and (min-width: 1300px) { - font-size: 22px; - } - } - - &::after { - display: block; - width: 100%; - padding-bottom: 5px; - border-width: 2px; - border-bottom: 2px solid colors.$cornflowerBlue; - transform: scale(0); - opacity: 0; - transition: all 0.3s ease-in-out; - content: ''; - } - - &:hover:not([class*='_active']) { - &::after { - transform: scale(1); - opacity: 0.6; - } - } - - & > * { - position: relative; - display: inline-flex; - align-items: center; - - &.content-menu__tab-tip { - gap: 5px; - } - - &.content-menu__tab-icon { - gap: 5px; - - & > * { - svg { - width: 17px; - height: 17px; - - path { - fill: colors.$topaz; - } - } - } - } - } - - &.content-menu__tab_active { - svg { - path { - fill: colors.$cornflowerBlue; - } - } - } - - &_active { - color: colors.$primary; - font-weight: 700; - pointer-events: none; - - .content-menu__tab-tip { - svg { - pointer-events: auto; - } - } - - &::after { - transform: scale(1); - opacity: 1; - } - - a { - cursor: default; - } - - .content-menu__tab-icon { - svg { - path { - fill: colors.$cornflowerBlue; - } - } - } - } - } - - &_disabled { - pointer-events: none; - - a { - cursor: not-allowed; - } - } - - &__preview { - color: colors.$spunPearl; - font-size: 10px; - } - - .tabs-slider { - &__arrow { - display: flex; - width: 30px; - min-width: fit-content; - max-width: 24px; - border-radius: 8px; - - &_left { - padding-top: 3px; - transform: rotate(180deg); - } - - &_right { - padding-bottom: 3px; - } - - &_hidden { - display: none; - } - - &_disabled { - pointer-events: none; - - & path { - fill: colors.$spunPearl; - } - } - - &:hover:not(.details-menu__arrow_disabled) { - background-color: colors.$mulledWineThree; - cursor: pointer; - } - - svg { - align-self: center; - } - } - } -} - -/* =========== CONTENT ============= */ - -.content { - position: relative; - flex-direction: column; - min-width: 800px; - padding: 15px 24px 10px; - background-color: colors.$white; - - //@include mixins.jobsFlex; - - @media screen and (min-width: 1300px) { - padding: 15px 64px 15px; - } - - &__header { - display: flex; - flex-flow: row nowrap; - align-items: center; - justify-content: space-between; - min-height: 70px; - padding: 14px 24px; - background-color: colors.$white; - box-shadow: shadows.$headerShadow; - - .btn { - &_register { - text-transform: capitalize; - } - } - } - - .table-container { - position: relative; - display: flex; - flex: 1; - flex-direction: column; - background-color: colors.$white; - - .no_data { - margin: auto; - color: colors.$mulledWine; - } - } - - &-wrapper { - display: flex; - flex: 1 1; - flex-direction: column; - min-width: 100%; - } - - &__action-bar-wrapper { - display: flex; - flex-flow: row wrap; - align-items: center; - - &_hidden { - display: none; - } - - .content-menu { - flex: 0; - margin-right: 20px; - margin-bottom: 15px; - - &__item { - white-space: nowrap; - } - } - - .action-bar { - display: flex; - flex: 1; - align-items: flex-start; - justify-content: flex-end; - width: 100%; - margin-bottom: 15px; - - &_hidden { - display: none; - } - - &__filters { - &-item { - &:not(:last-child) { - margin: 0 15px 0 0; - } - } - } - } - } - - &__history-back-link-wrapper { - padding-bottom: 5px; - - .history-back-link__title { - max-width: 100%; - } - } -} - /* =========== MAIN ============= */ main { @@ -418,292 +114,6 @@ main { } } -/* =========== TABLE ============= */ - -.table { - position: relative; - width: 100%; - text-align: left; - border-spacing: 0; - - .table { - &-row { - display: flex; - flex-direction: row; - min-width: 100%; - min-height: 50px; - background-color: inherit; - - &:not(.parent-row_expanded) > * { - position: relative; - display: inline-flex; - flex: 1; - align-items: center; - border-bottom: borders.$tableRowBorder; - - @include mixins.tableDet(8px, 5px, 8px, 10px); - - &:first-child { - padding-left: 30px; - } - - &.table-cell { - &-name { - position: sticky; - left: 0; - z-index: 1; - min-width: 250px; - padding-right: 10px; - } - - &-icon { - position: sticky; - right: 0; - justify-content: center; - max-width: 85px; - padding: 0; - - @include mixins.tableColumnFlex(0, 50px); - - & > :first-child { - padding: 0; - } - - &__run-icon { - margin-bottom: -2px; - transform: rotate(-90deg) scale(1.2); - } - } - } - } - - &.parent-row { - &:not(.parent-row_expanded) { - &:not(.parent-row_without-actions) { - .table-cell-icon { - .actions-menu { - &__container_extended { - &::before { - background: - linear-gradient( - 90deg, - rgba(255, 255, 255, 0) 0%, - rgba(245, 247, 255, 1) 100% - ); - } - } - } - } - - &:hover { - .table-cell-icon { - .actions-menu { - &__container { - display: flex; - - &_extended { - background-color: colors.$ghostWhite; - - &::before { - background: - linear-gradient( - 90deg, - rgba(255, 255, 255, 0) 0%, - rgba(245, 247, 255, 1) 100% - ); - } - } - - .btn { - min-width: 24px; - padding: 0; - border: none; - - &:hover { - background-color: transparent; - } - } - } - } - } - } - } - } - - .expand-arrow { - position: absolute; - left: 5px; - cursor: pointer; - } - - .best-iteration { - position: absolute; - top: auto; - bottom: auto; - left: 5px; - margin-top: 3px; - } - - &_expanded { - flex-direction: column; - border: 0; - - .table-row { - &:hover { - .table-cell-icon { - .actions-menu { - &__container { - display: flex; - } - } - } - } - } - - .row_grouped-by { - position: sticky; - top: #{variables.$headerRowHeight}px; - z-index: 3; - padding: 0; - background-color: colors.$white; - - .expand-arrow { - transform: rotate(90deg); - } - } - } - } - - .checkbox { - position: absolute; - left: 8px; - margin: 0; - } - } - - &-header { - position: sticky; - top: 0; - z-index: 3; - min-width: 100%; - - &-row { - min-height: #{variables.$headerRowHeight}px; - } - - &__cell { - min-width: 75px; - - @include mixins.tableHeader; - - &:first-child { - border-radius: 4px 0 0 0; - } - - &:last-child { - border-radius: 0 4px 0 0; - } - } - } - - &-body { - position: relative; - z-index: 2; - - &__cell { - .status { - display: flex; - flex: 0 1 12px; - align-items: center; - justify-content: center; - min-width: 12px; - margin-left: 5px; - - & > * { - margin: 0; - } - } - } - - .table-row { - background-color: colors.$white; - - &:hover, - &_active { - background-color: colors.$ghostWhite; - } - - & > * { - background-color: inherit; - } - } - } - } - - &-main { - display: flex; - flex: 1; - flex-flow: column nowrap; - overflow-y: auto; - will-change: scroll-position; - } - - &.table-with-details { - .table-cell-name { - min-width: 240px; - max-width: 240px; - } - } - - &-fixed { - table-layout: fixed; - } -} - -/* =========== SORT ============= */ - -.sortable-header { - &-cell { - position: relative; - border: 0; - border-radius: 0; - cursor: pointer; - - .sort-icon { - position: absolute; - top: auto; - right: 2px; - bottom: auto; - display: none; - } - - &_active { - background-color: colors.$alabaster; - - .sort-icon { - display: block; - } - } - - &:hover { - .sort-icon { - display: block; - } - } - - label { - cursor: pointer; - } - } - - &-label { - position: relative; - display: flex; - align-items: center; - padding-right: 25px; - } -} - /* =========== STATE ============= */ [class^='state-active'], @@ -1137,66 +547,3 @@ div[id^='chartjs-tooltip'] { opacity: 1; } } - -/* =========== GENERAL ============= */ - -.d-flex { - display: flex; -} - -.visibility-hidden { - visibility: hidden; -} - -.data-ellipsis { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.cursor-pointer { - cursor: pointer; -} - -.capitalize { - text-transform: capitalize; -} - -.wrap { - white-space: pre-wrap; -} - -iframe { - width: 100%; - height: 100%; -} - -a { - color: inherit; - text-decoration: none; -} - -*, -::after, -::before { - box-sizing: border-box; -} - -::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -::-webkit-scrollbar-track { - background-color: rgba(colors.$black, 0.1); - border-radius: 10px; -} - -::-webkit-scrollbar-thumb { - background-color: rgba(colors.$black, 0.25); - border-radius: 10px; - - &:hover { - background-color: rgba(colors.$black, 0.4); - } -} diff --git a/src/store/toolkitStore.js b/src/store/toolkitStore.js index 8290caada5..901b2b37ee 100644 --- a/src/store/toolkitStore.js +++ b/src/store/toolkitStore.js @@ -29,18 +29,21 @@ import filtersStore from '../reducers/filtersReducer' import functionsStore from '../reducers/functionReducer' import jobsStore from '../reducers/jobReducer' import monitoringApplicationsStore from '../reducers/monitoringApplicationsReducer' -import notificationStore from '../reducers/notificationReducer' import nuclioStore from '../reducers/nuclioReducer' import projectStore from '../reducers/projectReducer' import tableStore from '../reducers/tableReducer' import tasksStore from '../reducers/tasksReducer' import workflowsStore from '../reducers/workflowReducer' +import commonDetailsStore from 'igz-controls/reducers/commonDetailsReducer' +import notificationStore from 'igz-controls/reducers/notificationReducer' + const toolkitStore = configureStore({ reducer: { alertsStore, appStore, artifactsStore, + commonDetailsStore, detailsStore, downloadStore, featureStore, diff --git a/src/types.js b/src/types.js index 7e301d0ae3..dfe6c0400f 100644 --- a/src/types.js +++ b/src/types.js @@ -21,10 +21,6 @@ import PropTypes from 'prop-types' import { BE_PAGE, BE_PAGE_SIZE, - DENSITY_CHUNKY, - DENSITY_DENSE, - DENSITY_MEDIUM, - DENSITY_NORMAL, FE_PAGE, FE_PAGE_SIZE, PANEL_CREATE_MODE, @@ -44,50 +40,6 @@ export const COMBOBOX_MATCHES = PropTypes.arrayOf( }) ) -export const DENSITY_OPTIONS = PropTypes.oneOf([ - DENSITY_DENSE, - DENSITY_NORMAL, - DENSITY_MEDIUM, - DENSITY_CHUNKY -]) - -export const CHIP = PropTypes.shape({ - delimiter: PropTypes.element, - id: PropTypes.string, - value: PropTypes.string.isRequired -}) - -export const CHIP_INPUT_LIST = PropTypes.arrayOf( - PropTypes.shape({ - disabled: PropTypes.bool, - icon: PropTypes.element, - id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - subLabel: PropTypes.string, - ui: PropTypes.object - }) -) - -export const CHIP_OPTIONS = PropTypes.shape({ - background: PropTypes.oneOf([ - 'none', - 'orange', - 'green', - 'purple', - 'grey', - 'sorbus', - 'java', - 'amethyst' - ]), - boldValue: PropTypes.bool, - borderColor: PropTypes.oneOf(['transparent', 'orange', 'green', 'purple', 'grey']), - density: DENSITY_OPTIONS, - font: PropTypes.oneOf(['primary', 'white', 'green', 'purple', 'orange']), - borderRadius: PropTypes.oneOf(['primary', 'secondary']) -}) - -export const CHIPS = PropTypes.arrayOf(CHIP) - export const FUNCTION_PANEL_MODE = PropTypes.oneOf([PANEL_EDIT_MODE, PANEL_CREATE_MODE]) export const SELECT_OPTION = PropTypes.shape({ @@ -118,19 +70,6 @@ export const CONFIRM_DIALOG_BUTTON = PropTypes.shape({ variant: PropTypes.string.isRequired }) -const ACTIONS_MENU_ITEM = PropTypes.shape({ - label: PropTypes.string.isRequired, - icon: PropTypes.object, - onClick: PropTypes.func.isRequired, - disabled: PropTypes.bool, - className: PropTypes.string -}) - -export const ACTIONS_MENU = PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.arrayOf(ACTIONS_MENU_ITEM.isRequired)), - PropTypes.func -]) - export const MAIN_SPLIT_BUTTON = PropTypes.shape({ className: PropTypes.string, icon: PropTypes.element, @@ -158,15 +97,6 @@ export const CONTENT_MENU_TABS = PropTypes.arrayOf( }) ) -export const SLIDER_TABS = PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - tip: PropTypes.string, - hidden: PropTypes.bool - }) -) - export const SCHEDULE_DATA = PropTypes.shape({ cron: PropTypes.string, defaultCron: PropTypes.string, @@ -216,12 +146,6 @@ export const JOB_WIZARD_MODE = PropTypes.oneOf([ PANEL_RERUN_MODE ]) -export const VIRTUALIZATION_CONFIG = PropTypes.shape({ - startIndex: PropTypes.number.isRequired, - endIndex: PropTypes.number.isRequired, - tableBodyPaddingTop: PropTypes.number.isRequired -}) - export const SLIDER_STYLE_1 = 'style1' export const SLIDER_STYLE_2 = 'style2' diff --git a/src/utils/artifacts.util.js b/src/utils/artifacts.util.js index 23a6e34b53..b6bb1b2225 100644 --- a/src/utils/artifacts.util.js +++ b/src/utils/artifacts.util.js @@ -32,9 +32,11 @@ import { LLM_PROMPTS_PAGE, MODEL_TYPE, MODELS_PAGE, - VIEW_SEARCH_PARAMETER + TAG_FILTER_ALL_ITEMS, + TAG_FILTER_LATEST, + ALL_VERSIONS_PATH } from '../constants' -import { TAG_FILTER_ALL_ITEMS, TAG_FILTER_LATEST, ALL_VERSIONS_PATH } from '../constants' +import { VIEW_SEARCH_PARAMETER } from 'igz-controls/constants' import { deleteTag, editTag, @@ -49,8 +51,8 @@ import { getArtifactIdentifier } from './getUniqueIdentifier' import { parseArtifacts } from './parseArtifacts' import { parseIdentifier } from './parseUri' import { setFilters, setModalFiltersValues } from '../reducers/filtersReducer' -import { showErrorNotification } from './notifications.util' -import { getFilteredSearchParams } from './filter.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' +import { getFilteredSearchParams } from 'igz-controls/utils/filter.util' import { generateObjectNotInTheListMessage } from './generateMessage.util' export const applyTagChanges = (changes, artifactItem, projectName, dispatch, setNotification) => { diff --git a/src/utils/copyToClipboard.js b/src/utils/copyToClipboard.js index 6fc648aab1..5ce46b16d1 100644 --- a/src/utils/copyToClipboard.js +++ b/src/utils/copyToClipboard.js @@ -17,8 +17,8 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { setNotification } from '../reducers/notificationReducer' -import { showErrorNotification } from './notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' export const copyToClipboard = (textToCopy, dispatch) => { if (!navigator.clipboard?.writeText) { diff --git a/src/utils/createAlertsContent.jsx b/src/utils/createAlertsContent.jsx index db834034b0..9fefacf2a2 100644 --- a/src/utils/createAlertsContent.jsx +++ b/src/utils/createAlertsContent.jsx @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import { upperFirst } from 'lodash' -import { formatDatetime } from './datetime' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import Application from 'igz-controls/images/entity-type-application.svg?react' import Endpoint from 'igz-controls/images/entity-type-endpoint.svg?react' diff --git a/src/utils/createApplicationContent.jsx b/src/utils/createApplicationContent.jsx index 6530e3f71d..177c3d2181 100644 --- a/src/utils/createApplicationContent.jsx +++ b/src/utils/createApplicationContent.jsx @@ -19,7 +19,7 @@ such restriction. */ import { capitalize } from 'lodash' -import { formatDatetime } from './datetime' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import { generateNuclioLink } from './parseUri' export const createApplicationContent = application => { diff --git a/src/utils/createArtifactsContent.jsx b/src/utils/createArtifactsContent.jsx index 5b2251cc94..c8fd866210 100644 --- a/src/utils/createArtifactsContent.jsx +++ b/src/utils/createArtifactsContent.jsx @@ -32,13 +32,13 @@ import { ALL_VERSIONS_PATH } from '../constants' import { parseKeyValues } from './object' -import { formatDatetime } from './datetime' import prettyBytes from 'pretty-bytes' import { parseUri } from './parseUri' import { generateLinkToDetailsPanel } from './link-helper.util' import { openPopUp } from 'igz-controls/utils/common.util' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import { validateArguments } from './validateArguments' -// import { roundFloats } from './roundFloats' +// import { roundFloats } from 'igz-controls/utils/common.util' import SeverityOk from 'igz-controls/images/severity-ok.svg?react' import SeverityWarning from 'igz-controls/images/severity-warning.svg?react' @@ -138,7 +138,9 @@ export const createModelsRowData = (artifact, project, isAllVersions, metricsCou className: 'table-cell-name', getLink: tab => getArtifactsDetailsLink(artifact, 'models/models', tab, project, isAllVersions), - showTag: true + showTag: true, + showSelectedUid: true, + showUpdatedDate: true }, { id: `labels.${artifact.ui.identifierUnique}`, @@ -269,7 +271,9 @@ export const createFilesRowData = (artifact, project, isAllVersions) => { value: isAllVersions ? artifact.uid : artifact.db_key, className: 'table-cell-name', getLink: tab => getArtifactsDetailsLink(artifact, 'files', tab, project, isAllVersions), - showTag: true + showTag: true, + showSelectedUid: true, + showUpdatedDate: true }, { id: `version.${artifact.ui.identifierUnique}`, @@ -347,7 +351,9 @@ export const createDocumentsRowData = (artifact, project, isAllVersions) => { value: isAllVersions ? artifact.uid : artifact.db_key, className: 'table-cell-name', getLink: tab => getArtifactsDetailsLink(artifact, 'documents', tab, project, isAllVersions), - showTag: true + showTag: true, + showSelectedUid: true, + showUpdatedDate: true }, { id: `updated.${artifact.ui.identifierUnique}`, @@ -557,7 +563,9 @@ export const createDatasetsRowData = (artifact, project, isAllVersions) => { value: isAllVersions ? artifact.uid : artifact.db_key, className: 'table-cell-name', getLink: tab => getArtifactsDetailsLink(artifact, 'datasets', tab, project, isAllVersions), - showTag: true + showTag: true, + showSelectedUid: true, + showUpdatedDate: true }, { id: `labels.${artifact.ui.identifierUnique}`, @@ -629,7 +637,9 @@ export const createLLMPromptsRowData = (artifact, project, isAllVersions) => { className: 'table-cell-name', getLink: tab => getArtifactsDetailsLink(artifact, 'llm-prompts', tab, project, isAllVersions), - showTag: true + showTag: true, + showSelectedUid: true, + showUpdatedDate: true }, { id: `labels.${artifact.ui.identifierUnique}`, diff --git a/src/utils/createFeatureStoreContent.jsx b/src/utils/createFeatureStoreContent.jsx index 9be2785e89..30090aef3c 100644 --- a/src/utils/createFeatureStoreContent.jsx +++ b/src/utils/createFeatureStoreContent.jsx @@ -26,16 +26,16 @@ import FeatureSetPopUp from '../elements/DetailsPopUp/FeatureSetPopUp/FeatureSet import { FEATURE_STORE_PAGE, FEATURE_SETS_TAB, - FEATURE_VECTORS_TAB, - BUTTON_COPY_URI_CELL_TYPE + FEATURE_VECTORS_TAB } from '../constants' -import { parseKeyValues } from './object' -import { formatDatetime } from './datetime' -import { generateUri } from './resources' -import { truncateUid } from '../utils' +import { BUTTON_COPY_URI_CELL_TYPE } from 'igz-controls/constants' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import { generateLinkToDetailsPanel } from './link-helper.util' -import { validateArguments } from './validateArguments' +import { generateUri } from './resources' import { openPopUp } from 'igz-controls/utils/common.util' +import { parseKeyValues } from './object' +import { truncateUid } from 'igz-controls/utils/string.util' +import { validateArguments } from './validateArguments' import Nosql from 'igz-controls/images/nosql.svg?react' import Stream from 'igz-controls/images/stream.svg?react' diff --git a/src/utils/createFunctionsRowData.js b/src/utils/createFunctionsRowData.js index 46e5a3837f..282e6cda9b 100644 --- a/src/utils/createFunctionsRowData.js +++ b/src/utils/createFunctionsRowData.js @@ -17,9 +17,10 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { formatDatetime } from './datetime' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import { getFunctionImage } from '../components/FunctionsPage/functions.util' import { ALL_VERSIONS_PATH } from '../constants' +import { typesOfJob } from './jobs.util' const createFunctionsRowData = (func, projectName, isAllVersions, showExpandButton, oldVersion) => { return { @@ -49,6 +50,8 @@ const createFunctionsRowData = (func, projectName, isAllVersions, showExpandButt showStatus: true }, showTag: true, + showSelectedUid: true, + showUpdatedDate: true, showStatus: true, showExpandButton }, @@ -58,7 +61,8 @@ const createFunctionsRowData = (func, projectName, isAllVersions, showExpandButt headerLabel: 'Kind', value: func.type, className: 'table-cell-small', - type: 'type' + type: 'type', + types: typesOfJob }, { id: `hash.${func.ui.identifierUnique}`, diff --git a/src/utils/createJobsContent.js b/src/utils/createJobsContent.js index 492fe80ad5..410f0119c0 100644 --- a/src/utils/createJobsContent.js +++ b/src/utils/createJobsContent.js @@ -39,13 +39,13 @@ import { getWorkflowMonitoringDetailsLink } from '../components/Workflow/workflow.util' import { measureTime } from './measureTime' -import { formatDatetime } from './datetime' import { generateLinkToDetailsPanel } from './link-helper.util' import { getJobIdentifier, getWorkflowJobIdentifier } from './getUniqueIdentifier' import { parseKeyValues } from './object' import { validateArguments } from './validateArguments' -import { getJobKindFromLabels } from './jobs.util' -import { saveAndTransformSearchParams } from './filter.util' +import { getJobKindFromLabels, typesOfJob } from './jobs.util' +import { saveAndTransformSearchParams } from 'igz-controls/utils/filter.util' +import { formatDatetime } from 'igz-controls/utils/datetime.util' export const createJobsMonitorTabContent = (jobs, jobName, isStagingMode) => { return jobs.map(job => { @@ -94,7 +94,8 @@ export const createJobsMonitorTabContent = (jobs, jobName, isStagingMode) => { type: type === JOB_KIND_WORKFLOW && !isStagingMode ? 'hidden' : 'link', getLink, showStatus: true, - showUidRow: true + showUid: true, + showDate: true }, { headerId: 'type', @@ -102,7 +103,8 @@ export const createJobsMonitorTabContent = (jobs, jobName, isStagingMode) => { id: `type.${identifierUnique}`, value: type, className: 'table-cell-1', - type: 'type' + type: 'type', + types: typesOfJob }, { headerId: 'job.uid', @@ -201,7 +203,8 @@ export const createJobsScheduleTabContent = jobs => { id: `type.${identifierUnique}`, value: job.type, className: 'table-cell-small', - type: 'type' + type: 'type', + types: typesOfJob }, { headerId: 'nextrun', @@ -386,7 +389,8 @@ export const createJobsWorkflowContent = ( ) }, showStatus: true, - showUidRow: true + showUid: true, + showDate: true }, { headerId: 'kind', @@ -395,6 +399,7 @@ export const createJobsWorkflowContent = ( value: job.run_type, className: 'table-cell-1', type: 'type', + types: typesOfJob, hidden: isSelectedItem }, { @@ -477,7 +482,8 @@ export const createJobsMonitoringContent = (jobs, jobName, isStagingMode) => { type: type === JOB_KIND_WORKFLOW && !isStagingMode ? 'hidden' : 'link', getLink, showStatus: true, - showUidRow: true + showUid: true, + showDate: true }, { headerId: 'projectName', @@ -492,7 +498,8 @@ export const createJobsMonitoringContent = (jobs, jobName, isStagingMode) => { id: `type.${identifierUnique}`, value: type, className: 'table-cell-1', - type: 'type' + type: 'type', + types: typesOfJob }, { headerId: 'job.uid', @@ -597,7 +604,8 @@ export const createScheduleJobsMonitoringContent = jobs => { id: `type.${identifierUnique}`, value: job.type, className: 'table-cell-small', - type: 'type' + type: 'type', + types: typesOfJob }, { headerId: 'nextrun', diff --git a/src/utils/createRealTimePipelinesContent.js b/src/utils/createRealTimePipelinesContent.js index 72d60c460f..dd161cafba 100644 --- a/src/utils/createRealTimePipelinesContent.js +++ b/src/utils/createRealTimePipelinesContent.js @@ -19,9 +19,10 @@ such restriction. */ import FunctionPopUp from '../elements/DetailsPopUp/FunctionPopUp/FunctionPopUp' -import { formatDatetime } from './datetime' +import { formatDatetime } from 'igz-controls/utils/datetime.util' import { openPopUp } from 'igz-controls/utils/common.util' import { MODELS_PAGE, REAL_TIME_PIPELINES_TAB } from '../constants' +import { typesOfJob } from './jobs.util' const createRealTimePipelinesContent = (pipelines, projectName) => pipelines.map(pipeline => { @@ -55,7 +56,8 @@ const createRealTimePipelinesContent = (pipelines, projectName) => headerLabel: 'Type', value: pipeline.graph?.kind === 'router' ? 'Router' : 'Flow', className: 'table-cell-small', - type: 'type' + type: 'type', + types: typesOfJob }, { id: `function.${pipeline.ui.identifierUnique}`, diff --git a/src/utils/cutChips.js b/src/utils/cutChips.js deleted file mode 100644 index 78eaf66386..0000000000 --- a/src/utils/cutChips.js +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -export const cutChips = (chips = [], maxLength, delimiter) => { - if (chips.length > maxLength) { - let hiddenChipsNumber = `+ ${chips.length - maxLength}` - const hiddenChips = chips.slice(maxLength).map(value => ({ value, delimiter })) - const visibleChips = chips.slice(0, maxLength).map(value => ({ value, delimiter })) - visibleChips.push({ - value: hiddenChipsNumber, - delimiter - }) - - return { - visibleChips, - hiddenChips - } - } - return { - visibleChips: chips.map(value => ({ value, delimiter })) - } -} diff --git a/src/utils/datetime.js b/src/utils/datetime.js deleted file mode 100755 index e24a345d7f..0000000000 --- a/src/utils/datetime.js +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import moment from 'moment' - -export const formatDatetime = (datetime, invalidDateMessage) => { - if (!datetime) { - return invalidDateMessage - } - - const date = new Date(datetime) - - return typeof date !== 'object' || !(date instanceof Date) || isNaN(date) - ? invalidDateMessage - : new Intl.DateTimeFormat('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - second: '2-digit' - }).format(date) -} - -export const getFormatTime = time => { - const [hour, minute] = time.split(':') - if (!minute) { - return { - hour: '0', - minute: '0' - } - } - return { - hour: hour.replace(/_/g, '0'), - minute: minute.replace(/_/g, '0') - } -} - -export const getTimeElapsedByDate = creationDate => { - moment.updateLocale('en', { - relativeTime: { - future: 'in %s', - past: '%s ago', - s: 'a few seconds', - ss: '%d seconds', - m: 'a minute', - mm: '%d minutes', - h: 'an hour', - hh: '%d hours', - d: 'a day', - dd: '%d days', - w: 'a week', - ww: '%d weeks', - M: 'a month', - MM: '%d months', - y: 'a year', - yy: '%d years' - } - }) - - const time = moment.utc(creationDate) - - return time.fromNow() -} - -export const getDateAndTimeByFormat = (date, dateFormat) => { - return moment(date).format(dateFormat) -} - -export const sortListByDate = (list = [], field, isAscending = true) => { - return [...list].sort((prevElem, nextElem) => { - const prev = Date.parse(prevElem[field]) - const next = Date.parse(nextElem[field]) - - return isAscending ? prev - next : next - prev - }) -} diff --git a/src/utils/filter.util.js b/src/utils/filter.util.js deleted file mode 100644 index b61623c7df..0000000000 --- a/src/utils/filter.util.js +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ - -const SAVED_PARAMS = 'savedParams' - -export const getSavedSearchParams = searchParams => { - return atob(new URLSearchParams(searchParams)?.get(SAVED_PARAMS) ?? '') ?? '' -} - -export const saveAndTransformSearchParams = ( - searchParams, - includeSearchParams = false, - excludeParamsNames = [] -) => { - let newSearchParams = '?' - - if (includeSearchParams) { - const filteredNewSearchParams = getFilteredSearchParams(searchParams, excludeParamsNames) - newSearchParams = filteredNewSearchParams ? `${filteredNewSearchParams}&` : newSearchParams - } - - return searchParams ? `${newSearchParams}${SAVED_PARAMS}=${btoa(searchParams)}` : '' -} - -export const transformSearchParams = params => { - return params ? `${SAVED_PARAMS}=${btoa(params)}` : '' -} - -export const getFilteredSearchParams = (searchParams, excludeParamsNames = []) => { - const params = new URLSearchParams(searchParams) - - excludeParamsNames.forEach(paramName => params.delete(paramName)) - - const newSearchParams = params.toString() - - if (!newSearchParams) return '' - - return `?${newSearchParams}` -} diff --git a/src/utils/getArtifactPreview.jsx b/src/utils/getArtifactPreview.jsx index d30fe9c26d..d9d8ca787d 100644 --- a/src/utils/getArtifactPreview.jsx +++ b/src/utils/getArtifactPreview.jsx @@ -17,8 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { TextTooltipTemplate, Tooltip } from 'igz-controls/components' -import CopyToClipboard from '../common/CopyToClipboard/CopyToClipboard' +import { TextTooltipTemplate, Tooltip, CopyToClipboard } from 'igz-controls/components' import Download from '../common/Download/Download' import api from '../api/artifacts-api' diff --git a/src/utils/getChipLabelAndValue.js b/src/utils/getChipLabelAndValue.js deleted file mode 100644 index a290ad164d..0000000000 --- a/src/utils/getChipLabelAndValue.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -import { roundFloats } from './roundFloats' - -export const getChipLabelAndValue = chip => { - const indexOfDelimiter = chip.value.indexOf(':') - const value = chip.value.slice(indexOfDelimiter + 1) - - return { - chipLabel: indexOfDelimiter > 0 ? chip.value.slice(0, indexOfDelimiter) : chip.value, - chipValue: indexOfDelimiter > 0 ? (Number.isInteger(value) ? roundFloats(value) : value) : '' - } -} diff --git a/src/utils/getChipOptions.js b/src/utils/getChipOptions.js deleted file mode 100644 index c9d9698946..0000000000 --- a/src/utils/getChipOptions.js +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -const chipOptions = [ - { - type: 'labels', - boldValue: false, - background: 'purple', - borderColor: 'transparent', - density: 'dense', - font: 'purple', - borderRadius: 'primary' - }, - { - type: 'metrics', - boldValue: false, - background: 'grey', - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'primary' - }, - { - type: 'parameters', - boldValue: false, - background: 'orange', - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'orange' - }, - { - type: 'results', - boldValue: false, - background: 'grey', - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'primary' - }, - { - type: 'relations', - boldValue: false, - background: 'orange', - borderColor: 'transparent', - borderRadius: 'primary', - density: 'dense', - font: 'orange' - } -] - -export const getChipOptions = variant => chipOptions.find(item => item.type === variant) diff --git a/src/utils/getFunctionLogs.js b/src/utils/getFunctionLogs.js index a96a5ca804..f0db21af84 100644 --- a/src/utils/getFunctionLogs.js +++ b/src/utils/getFunctionLogs.js @@ -23,7 +23,7 @@ import { } from '../components/FunctionsPage/functions.util' import { TAG_LATEST } from '../constants' import { fetchFunctionLogs, fetchFunctionNuclioLogs } from '../reducers/functionReducer' -import { showErrorNotification } from './notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' const isFunctionTransient = response => { return TRANSIENT_FUNCTION_STATUSES.includes(response.headers?.['x-mlrun-function-status']) diff --git a/src/utils/getUniqueIdentifier.js b/src/utils/getUniqueIdentifier.js index 9da4fa4bde..120f1223c2 100644 --- a/src/utils/getUniqueIdentifier.js +++ b/src/utils/getUniqueIdentifier.js @@ -17,6 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import { get } from 'lodash' import { ADD_TO_FEATURE_VECTOR_TAB, ALERTS_PAGE, @@ -116,12 +117,20 @@ export const getFeatureVectorIdentifier = (featureVector, unique) => { return identifier } -export const getV3ioStreamIdentifier = v3ioStream => { - return `${v3ioStream?.consumerGroup || ''}` +export const getV3ioStreamIdentifier = (v3ioStream, consumerGroupIsObject) => { + return get( + v3ioStream, + consumerGroupIsObject ? 'consumerGroup.identifierUnique' : 'consumerGroup', + '' + ) } -export const getV3ioStreamShardLagIdentifier = v3ioStream => { - return `${v3ioStream?.shardLagId || ''}` +export const getV3ioStreamShardLagIdentifier = (v3ioStream, shardLagIdIsObject) => { + return get( + v3ioStream, + shardLagIdIsObject ? 'shardLagId.identifierUnique' : 'shardLagId', + '' + ) } export const getIdentifierMethod = tab => { diff --git a/src/utils/handleDeleteArtifact.js b/src/utils/handleDeleteArtifact.js index 3821b513ca..b8c6d2eed4 100644 --- a/src/utils/handleDeleteArtifact.js +++ b/src/utils/handleDeleteArtifact.js @@ -20,8 +20,8 @@ such restriction. import { capitalize } from 'lodash' import { deleteArtifact } from '../reducers/artifactsReducer' import { deleteArtifacts } from '../reducers/artifactsReducer' -import { setNotification } from '../reducers/notificationReducer' -import { showErrorNotification } from './notifications.util' +import { setNotification } from 'igz-controls/reducers/notificationReducer' +import { showErrorNotification } from 'igz-controls/utils/notification.util' export const handleDeleteArtifact = ( dispatch, diff --git a/src/utils/helper.js b/src/utils/helper.js index 945727eeb5..f60042ef53 100644 --- a/src/utils/helper.js +++ b/src/utils/helper.js @@ -18,7 +18,6 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { VIEW_SEARCH_PARAMETER } from '../constants' import localStorageService from './localStorageService' export const isDemoMode = search => { @@ -29,10 +28,6 @@ export const getUrlMode = search => { return new URLSearchParams(search).get('mode')?.toLowerCase() } -export const getViewMode = search => { - return new URLSearchParams(search).get(VIEW_SEARCH_PARAMETER)?.toLowerCase() -} - export const isPanelOpened = search => { return new URLSearchParams(search).get('openPanel')?.toLowerCase() === 'true' } diff --git a/src/utils/index.js b/src/utils/index.js index a6a16504ba..f86a297497 100755 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -17,7 +17,5 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -export * from './datetime' export * from './object' export * from './parseUri' -export * from './string' diff --git a/src/utils/jobs.util.js b/src/utils/jobs.util.jsx similarity index 80% rename from src/utils/jobs.util.js rename to src/utils/jobs.util.jsx index 4a2b36eac0..32efdf2309 100644 --- a/src/utils/jobs.util.js +++ b/src/utils/jobs.util.jsx @@ -17,6 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import React from 'react' import { cloneDeep, debounce, omit } from 'lodash' import { @@ -25,12 +26,24 @@ import { FE_PAGE, FILTER_ALL_ITEMS, JOBS_MONITORING_JOBS_TAB, + FUNCTION_TYPE_APPLICATION, JOBS_MONITORING_SCHEDULED_TAB, + JOB_KIND_DASK, + JOB_KIND_DATABRICKS, + JOB_KIND_HANDLER, + JOB_KIND_JOB, + JOB_KIND_LOCAL, + JOB_KIND_MPIJOB, + JOB_KIND_NUCLIO, + JOB_KIND_REMOTE, + JOB_KIND_SERVING, + JOB_KIND_SPARK, + JOB_KIND_WORKFLOW, LABELS_FILTER, MONITOR_JOBS_TAB, NAME_FILTER, - PROJECT_FILTER, PROJECTS_FILTER_ALL_ITEMS, + PROJECT_FILTER, STATUS_FILTER, TYPE_FILTER } from '../constants' @@ -48,11 +61,39 @@ import { jobsStatuses, workflowsStatuses } from '../components/FilterMenu/filterMenu.settings' -import { getCloseDetailsLink } from './link-helper.util' -import { parseJob } from './parseJob' import { fetchJob } from '../reducers/jobReducer' -import { showErrorNotification } from './notifications.util' import { generateObjectNotInTheListMessage } from './generateMessage.util' +import { getCloseDetailsLink } from './link-helper.util' +import { parseJob } from './parseJob' +import { showErrorNotification } from 'igz-controls/utils/notification.util' + +import Code from 'igz-controls/images/code.svg?react' +import Application from 'igz-controls/images/application-icon.svg?react' +import DatabricksIcon from 'igz-controls/images/databricks-icon.svg?react' +import Jupyter from 'igz-controls/images/jupyter.svg?react' +import Package from 'igz-controls/images/package.svg?react' +import Horovod from 'igz-controls/images/horovod.svg?react' +import Nuclio from 'igz-controls/images/nuclio.svg?react' +import Remote from 'igz-controls/images/ic_remote.svg?react' +import Serving from 'igz-controls/images/serving-icon.svg?react' +import Spark from 'igz-controls/images/spark.svg?react' +import Workflow from 'igz-controls/images/workflow-icon.svg?react' + +export const typesOfJob = { + '': { label: 'Local', icon: }, + [FUNCTION_TYPE_APPLICATION]: { label: 'Application', icon: }, + [JOB_KIND_DASK]: { label: 'Dask', icon: null }, + [JOB_KIND_DATABRICKS]: { label: 'Databricks', icon: }, + [JOB_KIND_HANDLER]: { label: 'Handler', icon: }, + [JOB_KIND_JOB]: { label: 'Job', icon: }, + [JOB_KIND_LOCAL]: { label: 'Local', icon: }, + [JOB_KIND_MPIJOB]: { label: 'Horovod', icon: }, + [JOB_KIND_NUCLIO]: { label: 'Nuclio', icon: }, + [JOB_KIND_REMOTE]: { label: 'Remote', icon: }, + [JOB_KIND_SERVING]: { label: 'Serving', icon: }, + [JOB_KIND_SPARK]: { label: 'Spark', icon: }, + [JOB_KIND_WORKFLOW]: { label: 'Workflow', icon: } +} export const checkForSelectedJob = debounce( ( diff --git a/src/utils/largeResponseCatchHandler.js b/src/utils/largeResponseCatchHandler.js index eca10eb5e4..86a314d8cd 100644 --- a/src/utils/largeResponseCatchHandler.js +++ b/src/utils/largeResponseCatchHandler.js @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import { DEFAULT_ABORT_MSG, LARGE_REQUEST_CANCELED, REQUEST_CANCELED } from '../constants' -import { showErrorNotification } from './notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' export const largeResponseCatchHandler = ( error, diff --git a/src/utils/link-helper.util.js b/src/utils/link-helper.util.js index d978918a5f..9c711afa9a 100644 --- a/src/utils/link-helper.util.js +++ b/src/utils/link-helper.util.js @@ -17,9 +17,11 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { DETAILS_OVERVIEW_TAB, VIEW_SEARCH_PARAMETER } from '../constants' -import { getFilteredSearchParams } from './filter.util' -import { showErrorNotification } from './notifications.util' +import { DETAILS_OVERVIEW_TAB } from '../constants' +import { VIEW_SEARCH_PARAMETER } from 'igz-controls/constants' +import { generateUrlFromRouterPath } from 'igz-controls/utils/common.util' +import { getFilteredSearchParams } from 'igz-controls/utils/filter.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' export const isPageTabValid = (pageTab, tabs, navigate, location) => { if (!tabs.includes(pageTab)) { @@ -35,19 +37,10 @@ export const isProjectValid = (navigate, projects, currentProjectName, dispatch) !projects.some(project => project?.metadata?.name === currentProjectName) ) { navigate('/projects', { replace: true }) - showErrorNotification( - dispatch, - {}, - '', - 'This project does not exist' - ) + showErrorNotification(dispatch, {}, '', 'This project does not exist') } } -export const generateUrlFromRouterPath = link => { - return new URL(link, window.location.origin).toString() -} - export const getCloseDetailsLink = (paramName, ignoreOrigin) => { let pathname = window.location.pathname diff --git a/src/utils/notifications.util.js b/src/utils/notifications.util.js deleted file mode 100644 index 8ea06709c5..0000000000 --- a/src/utils/notifications.util.js +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ - -import { setNotification } from '../reducers/notificationReducer' -import { getErrorMsg } from 'igz-controls/utils/common.util' -import { FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' - -export const showErrorNotification = ( - dispatch, - error, - defaultErrorMsg, - customErrorMsg, - retryCallback, - showNotificationCallback -) => { - const notificationData = { - status: error?.response?.status || 400, - id: Math.random(), - message: customErrorMsg || getErrorMsg(error, defaultErrorMsg), - error - } - - if (retryCallback && error?.response?.status !== FORBIDDEN_ERROR_STATUS_CODE) { - notificationData.retry = retryCallback - } - - showNotificationCallback?.(defaultErrorMsg) - dispatch(setNotification(notificationData)) -} diff --git a/src/utils/object.js b/src/utils/object.js index f2054233c5..86d3f78b53 100755 --- a/src/utils/object.js +++ b/src/utils/object.js @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import { isNil } from 'lodash' -import { roundFloats } from './roundFloats' +import { roundFloats } from 'igz-controls/utils/common.util' // {key: "value", key2: "value2"} --> ["key: value", "key2: value2"] export const parseKeyValues = (object = {}) => diff --git a/src/utils/roundFloats.js b/src/utils/roundFloats.js deleted file mode 100644 index 717b60557d..0000000000 --- a/src/utils/roundFloats.js +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -export const roundFloats = (value, precision) => { - if ( - ((typeof value === 'string' && value.trim() !== '') || typeof value === 'number') && - !isNaN(value) - ) { - const parsedNum = parseFloat(value) - - return parsedNum % 1 === 0 ? parsedNum : +parsedNum.toFixed(precision ?? 2) - } - - return value -} diff --git a/src/utils/tableRows.util.js b/src/utils/tableRows.util.js index 545a678456..531640f6f7 100644 --- a/src/utils/tableRows.util.js +++ b/src/utils/tableRows.util.js @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { sortListByDate } from './datetime' +import { sortListByDate } from 'igz-controls/utils/datetime.util' export const PARENT_ROW_EXPANDED_CLASS = 'parent-row_expanded' From f038c7d00fade765349eb5e24fd829d460c67749 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 17 Jun 2025 17:38:33 +0300 Subject: [PATCH 013/228] Fix [FS/FV/Datasets] analysis tab stuck on loading when analysis=True (#3290) --- src/components/Datasets/datasets.util.jsx | 9 ++++----- .../DetailsAnalysis/DetailsAnalysis.jsx | 16 ++++++++++++---- .../FeatureStore/FeatureSets/FeatureSets.jsx | 6 ++---- .../FeatureSets/featureSets.util.jsx | 9 ++++----- .../FeatureVectors/FeatureVectors.jsx | 6 ++---- .../FeatureVectors/featureVectors.util.jsx | 9 ++++----- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/components/Datasets/datasets.util.jsx b/src/components/Datasets/datasets.util.jsx index f442249195..97e8dedff7 100644 --- a/src/components/Datasets/datasets.util.jsx +++ b/src/components/Datasets/datasets.util.jsx @@ -63,7 +63,7 @@ export const infoHeaders = [ export const registerDatasetTitle = 'Register dataset' -export const generateDataSetsDetailsMenu = (selectedItem, isDemoMode) => [ +export const generateDataSetsDetailsMenu = (selectedItem) => [ { label: 'overview', id: 'overview' @@ -80,7 +80,7 @@ export const generateDataSetsDetailsMenu = (selectedItem, isDemoMode) => [ { label: 'analysis', id: 'analysis', - hidden: !isDemoMode || !selectedItem?.extra_data + hidden: !selectedItem?.extra_data } ] @@ -88,13 +88,12 @@ export const generatePageData = ( viewMode, selectedItem, params, - isDetailsPopUp = false, - isDemoMode + isDetailsPopUp = false ) => { return { page: DATASETS_PAGE, details: { - menu: generateDataSetsDetailsMenu(selectedItem, isDemoMode), + menu: generateDataSetsDetailsMenu(selectedItem), infoHeaders, type: DATASETS_PAGE, hideBackBtn: viewMode === FULL_VIEW_MODE && !isDetailsPopUp, diff --git a/src/components/DetailsAnalysis/DetailsAnalysis.jsx b/src/components/DetailsAnalysis/DetailsAnalysis.jsx index 5b679f536a..9f94503f86 100644 --- a/src/components/DetailsAnalysis/DetailsAnalysis.jsx +++ b/src/components/DetailsAnalysis/DetailsAnalysis.jsx @@ -20,12 +20,14 @@ such restriction. import React, { useCallback, useEffect, useState, useRef } from 'react' import PropTypes from 'prop-types' import { useParams } from 'react-router-dom' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' +import { isArray, isEmpty, isObject } from 'lodash' import ArtifactsPreview from '../ArtifactsPreview/ArtifactsPreview' import { REQUEST_CANCELED } from '../../constants' import { fetchArtifactPreviewFromPath } from '../../utils/getArtifactPreview' +import { showErrorNotification } from '../../utils/notifications.util' const DetailsAnalysis = ({ artifact }) => { const [preview, setPreview] = useState([]) @@ -34,6 +36,7 @@ const DetailsAnalysis = ({ artifact }) => { const frontendSpec = useSelector(store => store.appStore.frontendSpec) const previewIsFetchedRef = useRef(false) const abortControllersListRef = useRef([]) + const dispatch = useDispatch() const fetchPreviewFromAnalysis = useCallback(() => { Object.entries(artifact.analysis).forEach(([name, path]) => { @@ -56,13 +59,18 @@ const DetailsAnalysis = ({ artifact }) => { useEffect(() => { if (artifact.analysis && preview.length === 0 && !previewIsFetchedRef.current && frontendSpec) { - fetchPreviewFromAnalysis() + if (isObject(artifact.analysis) && !isArray(artifact.analysis)) { + fetchPreviewFromAnalysis() + } else { + showErrorNotification(dispatch, '', '', 'The analysis type is malformed. Expected dict') + setNoData(true) + } previewIsFetchedRef.current = true - } else if (!artifact.analysis) { + } else if (!artifact.analysis || isEmpty(artifact.analysis)) { setNoData(true) } - }, [artifact.analysis, fetchPreviewFromAnalysis, preview.length, frontendSpec]) + }, [artifact.analysis, fetchPreviewFromAnalysis, preview.length, frontendSpec, dispatch]) useEffect(() => { const abortControllersList = abortControllersListRef.current diff --git a/src/components/FeatureStore/FeatureSets/FeatureSets.jsx b/src/components/FeatureStore/FeatureSets/FeatureSets.jsx index afd62585ad..90d5f652ec 100644 --- a/src/components/FeatureStore/FeatureSets/FeatureSets.jsx +++ b/src/components/FeatureStore/FeatureSets/FeatureSets.jsx @@ -65,7 +65,6 @@ import { sortListByDate } from 'igz-controls/utils/datetime.util' import { useFiltersFromSearchParams } from '../../../hooks/useFiltersFromSearchParams.hook' import { useGroupContent } from '../../../hooks/groupContent.hook' import { useInitialTableFetch } from '../../../hooks/useInitialTableFetch.hook' -import { useMode } from '../../../hooks/mode.hook' import { useOpenPanel } from '../../../hooks/openPanel.hook' import { useVirtualization } from '../../../hooks/useVirtualization.hook' @@ -88,7 +87,6 @@ const FeatureSets = () => { const navigate = useNavigate() const location = useLocation() const dispatch = useDispatch() - const { isDemoMode } = useMode() const frontendSpec = useSelector(store => store.appStore.frontendSpec) const detailsFormInitialValues = useMemo( () => ({ @@ -112,8 +110,8 @@ const FeatureSets = () => { [] ) const pageData = useMemo( - () => generatePageData(selectedFeatureSet, isDemoMode), - [isDemoMode, selectedFeatureSet] + () => generatePageData(selectedFeatureSet), + [selectedFeatureSet] ) const actionsMenu = useMemo( () => generateActionsMenu(dispatch, selectedFeatureSet, toggleConvertedYaml), diff --git a/src/components/FeatureStore/FeatureSets/featureSets.util.jsx b/src/components/FeatureStore/FeatureSets/featureSets.util.jsx index 1bddf6a01b..53d6ba26e0 100644 --- a/src/components/FeatureStore/FeatureSets/featureSets.util.jsx +++ b/src/components/FeatureStore/FeatureSets/featureSets.util.jsx @@ -33,7 +33,7 @@ import { fetchFeatureSet } from '../../../reducers/featureStoreReducer' import Yaml from 'igz-controls/images/yaml.svg?react' -export const generateFeatureSetsDetailsMenu = (selectedItem, isDemoMode) => [ +export const generateFeatureSetsDetailsMenu = (selectedItem) => [ { label: 'overview', id: 'overview' @@ -59,8 +59,7 @@ export const generateFeatureSetsDetailsMenu = (selectedItem, isDemoMode) => [ }, { label: 'analysis', - id: 'analysis', - hidden: !isDemoMode + id: 'analysis' } ] @@ -84,12 +83,12 @@ export const filtersConfig = { [LABELS_FILTER]: { label: 'Labels:', initialValue: '', isModal: true } } -export const generatePageData = (selectedFeatureSet, isDemoMode) => { +export const generatePageData = (selectedFeatureSet) => { return { page: FEATURE_STORE_PAGE, details: { type: FEATURE_SETS_TAB, - menu: generateFeatureSetsDetailsMenu(selectedFeatureSet, isDemoMode), + menu: generateFeatureSetsDetailsMenu(selectedFeatureSet), infoHeaders: featureSetsInfoHeaders } } diff --git a/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx b/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx index 44836a5fbb..4cb9aa7cbc 100644 --- a/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx +++ b/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx @@ -65,7 +65,6 @@ import { sortListByDate } from 'igz-controls/utils/datetime.util' import { useFiltersFromSearchParams } from '../../../hooks/useFiltersFromSearchParams.hook' import { useGroupContent } from '../../../hooks/groupContent.hook' import { useInitialTableFetch } from '../../../hooks/useInitialTableFetch.hook' -import { useMode } from '../../../hooks/mode.hook' import { useOpenPanel } from '../../../hooks/openPanel.hook' import { useVirtualization } from '../../../hooks/useVirtualization.hook' @@ -89,7 +88,6 @@ const FeatureVectors = () => { const navigate = useNavigate() const location = useLocation() const dispatch = useDispatch() - const { isDemoMode } = useMode() const { createVectorPopUpIsOpen, @@ -112,8 +110,8 @@ const FeatureVectors = () => { [] ) const pageData = useMemo( - () => generatePageData(selectedFeatureVector, isDemoMode), - [isDemoMode, selectedFeatureVector] + () => generatePageData(selectedFeatureVector), + [selectedFeatureVector] ) const detailsFormInitialValues = useMemo( diff --git a/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx b/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx index 0453d2b350..b17f519d11 100644 --- a/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx +++ b/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx @@ -33,7 +33,7 @@ import { parseChipsData } from '../../../utils/convertChipsData' import Delete from 'igz-controls/images/delete.svg?react' import Yaml from 'igz-controls/images/yaml.svg?react' -export const generateFeatureVectorsDetailsMenu = (selectedItem, isDemoMode) => [ +export const generateFeatureVectorsDetailsMenu = (selectedItem) => [ { label: 'overview', id: 'overview' @@ -59,8 +59,7 @@ export const generateFeatureVectorsDetailsMenu = (selectedItem, isDemoMode) => [ }, { label: 'analysis', - id: 'analysis', - hidden: !isDemoMode + id: 'analysis' } ] @@ -83,12 +82,12 @@ export const filtersConfig = { [LABELS_FILTER]: { label: 'Labels:', initialValue: '', isModal: true } } -export const generatePageData = (selectedFeatureSet, isDemoMode) => { +export const generatePageData = (selectedFeatureSet) => { return { page: FEATURE_STORE_PAGE, details: { type: FEATURE_VECTORS_TAB, - menu: generateFeatureVectorsDetailsMenu(selectedFeatureSet, isDemoMode), + menu: generateFeatureVectorsDetailsMenu(selectedFeatureSet), infoHeaders: featureSetsInfoHeaders } } From f5bf0b85f96ae40d613ebf4c4b23824704a7a83e Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 17 Jun 2025 17:39:10 +0300 Subject: [PATCH 014/228] Mock [UI] Update mock (#3291) Create mock for Editing scheduled jobs [Artifacts] Add mock for artifact overwrite functionality --- tests/mockServer/data/artifacts.json | 1 - tests/mockServer/mock.js | 60 +++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/tests/mockServer/data/artifacts.json b/tests/mockServer/data/artifacts.json index a301c26215..0104899524 100644 --- a/tests/mockServer/data/artifacts.json +++ b/tests/mockServer/data/artifacts.json @@ -36450,7 +36450,6 @@ }, { "kind": "table", - "tag": "latest", "metadata": { "uid": "5a44b12b-9ef3-4239-87e8-e0cbdae-98", "key": "iteration_results", diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 030a64d889..1f0914451a 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -471,6 +471,24 @@ function createProjectsFeatureSet(req, res) { res.send(featureSet) } +function updateProjectsFeatureSet(req, res) { + let featureSet = req.body + + featureSet.metadata.updated = new Date().toISOString() + + const featureSetIndex = featureSets.feature_sets.findIndex( + featureSetItem => + req.params.project === featureSetItem.metadata.project && + req.params.name === featureSetItem.metadata.name && + req.params.tag === featureSetItem.metadata.tag && + featureSet.metadata.uid === featureSetItem.metadata.uid + ) + + featureSets.feature_sets[featureSetIndex] = featureSet + + res.send(featureSet) +} + function deleteFeatureSet(req, res) { const collecledFeatureSet = featureSets.feature_sets .filter(featureSet => featureSet.metadata.project === req.params.project) @@ -1248,6 +1266,18 @@ function invokeSchedule(req, res) { res.send(respTemplate) } +function updateSchedule(req, res) { + const existingScheduledJobIndex = schedules.schedules.find( + schedule => + schedule.name === req.params.schedule && + schedule.project === req.body.scheduled_object.task.metadata.project + ) + + existingScheduledJobIndex.scheduled_object = req.body.scheduled_object + + return res.send() +} + function getProjectsFeaturesEntities(req, res) { const artifact = req.path.substring(req.path.lastIndexOf('/') + 1) let collectedArtifacts = [] @@ -1436,8 +1466,7 @@ function getArtifacts(req, res) { break default: collectedArtifacts = collectedArtifacts.filter( - artifact => - artifact.metadata?.tag === req.query['tag'] || artifact.tag === req.query['tag'] + artifact => artifact.metadata?.tag === req.query['tag'] ) break } @@ -2211,24 +2240,36 @@ function deleteTags(req, res) { function getArtifact(req, res) { let resData - let requestedArtifact = artifacts.artifacts.find( - artifact => + let artifactMatchedByUID = null + let requestedArtifact = artifacts.artifacts.find(artifact => { + if ( + !isNil(req.query.uid) && + (artifact.metadata?.project === req.params.project || + artifact.project === req.params.project) && + (artifact.spec?.db_key === req.params.key || artifact?.db_key === req.params.key) && + artifact.metadata?.uid === req.query.uid + ) { + artifactMatchedByUID = artifact + } + + return ( (artifact.metadata?.project === req.params.project || artifact.project === req.params.project) && (artifact.spec?.db_key === req.params.key || artifact?.db_key === req.params.key) && (isNil(req.query.iter) || +req.query.iter === artifact?.iter || +req.query.iter === artifact.metadata?.iter) && - (isNil(req.query.tag) || - artifact.metadata?.tag === req.query.tag || - artifact?.tag === req.query.tag) && + (isNil(req.query.tag) || artifact.metadata?.tag === req.query.tag) && (isNil(req.query.tree) || artifact.metadata?.tree === req.query.tree || artifact?.tree === req.query.tree) && (isNil(req.query.uid) || artifact.metadata?.uid === req.query.uid || artifact?.uid === req.query.uid) - ) + ) + }) + + requestedArtifact = requestedArtifact ?? artifactMatchedByUID if (requestedArtifact) { resData = requestedArtifact @@ -2755,7 +2796,7 @@ app.get(`${mlrunAPIIngress}/projects/:project/feature-sets`, getFeatureSet) app.post(`${mlrunAPIIngress}/projects/:project/feature-sets`, createProjectsFeatureSet) app.put( `${mlrunAPIIngress}/projects/:project/feature-sets/:name/references/:tag`, - createProjectsFeatureSet + updateProjectsFeatureSet ) app.delete(`${mlrunAPIIngress}/projects/:project/feature-sets/:featureSet`, deleteFeatureSet) @@ -2803,6 +2844,7 @@ app.get(`${mlrunAPIIngress}/projects/*/schedules`, getProjectsSchedules) app.get(`${mlrunAPIIngress}/projects/:project/schedules/:schedule`, getProjectsSchedule) app.delete(`${mlrunAPIIngress}/projects/:project/schedules/:schedule`, deleteSchedule) app.post(`${mlrunAPIIngress}/projects/:project/schedules/:schedule/invoke`, invokeSchedule) +app.put(`${mlrunAPIIngress}/projects/:project/schedules/:schedule/`, updateSchedule) app.get(`${mlrunAPIIngress}/projects/:project/pipelines`, getPipelines) app.get(`${mlrunAPIIngress}/projects/*/pipelines`, getPipelines) From 1f699123ccb531f9fc89d42137f3c75a0ba456d5 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 17 Jun 2025 17:39:40 +0300 Subject: [PATCH 015/228] Fix [Jobs] console error of prop type (#3293) --- src/elements/JobsTable/JobsTable.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elements/JobsTable/JobsTable.jsx b/src/elements/JobsTable/JobsTable.jsx index aab54e4994..e94217e13b 100644 --- a/src/elements/JobsTable/JobsTable.jsx +++ b/src/elements/JobsTable/JobsTable.jsx @@ -62,7 +62,7 @@ const JobsTable = React.forwardRef( context, filters, filtersConfig, - jobs, + jobs = null, jobRuns = null, paginatedJobs, refreshJobs, @@ -448,7 +448,7 @@ JobsTable.propTypes = { filters: PropTypes.object.isRequired, filtersConfig: FILTERS_CONFIG.isRequired, jobRuns: PropTypes.array, - jobs: PropTypes.array.isRequired, + jobs: PropTypes.array, paginatedJobs: PropTypes.array.isRequired, refreshJobs: PropTypes.func.isRequired, requestErrorMessage: PropTypes.string.isRequired, From 6f21b85bfdb0e94387d732ce7f3899a47cca04b1 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 17 Jun 2025 17:39:55 +0300 Subject: [PATCH 016/228] Fix [UI] ESLint reload issue (#3296) --- vite.config.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vite.config.mjs b/vite.config.mjs index b2a3797fcc..184bd5f070 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -9,7 +9,7 @@ export default defineConfig(({ mode }) => { const env = loadEnv(mode, path.resolve(process.cwd()), '') return { - plugins: [commonjs(), react(), svgr(), eslint()], + plugins: [commonjs(), react(), svgr(), eslint({ failOnError: false })], base: env.NODE_ENV === 'production' ? env.VITE_PUBLIC_URL : '/', server: { proxy: { @@ -76,7 +76,7 @@ export default defineConfig(({ mode }) => { ] }, optimizeDeps: { - force: true, + force: true }, build: { sourcemap: true, From a03abada37245c6eb7e842b977650e81fe89d20c Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Wed, 18 Jun 2025 06:52:35 +0900 Subject: [PATCH 017/228] Fix [UI] Docker build error (#3299) --- src/components/DetailsAnalysis/DetailsAnalysis.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DetailsAnalysis/DetailsAnalysis.jsx b/src/components/DetailsAnalysis/DetailsAnalysis.jsx index 9f94503f86..83f91a6eba 100644 --- a/src/components/DetailsAnalysis/DetailsAnalysis.jsx +++ b/src/components/DetailsAnalysis/DetailsAnalysis.jsx @@ -27,7 +27,7 @@ import ArtifactsPreview from '../ArtifactsPreview/ArtifactsPreview' import { REQUEST_CANCELED } from '../../constants' import { fetchArtifactPreviewFromPath } from '../../utils/getArtifactPreview' -import { showErrorNotification } from '../../utils/notifications.util' +import { showErrorNotification } from 'igz-controls/utils/notification.util' const DetailsAnalysis = ({ artifact }) => { const [preview, setPreview] = useState([]) From 1080c1e06bf041a2f131c23598768ec2b35c7f41 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Wed, 18 Jun 2025 11:22:39 +0300 Subject: [PATCH 018/228] Fix [Artifacts] Artifacts without a tag are not being filtered as expected (#3292) --- src/api/artifacts-api.js | 2 +- tests/mockServer/mock.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/artifacts-api.js b/src/api/artifacts-api.js index f63677468e..11b0742399 100644 --- a/src/api/artifacts-api.js +++ b/src/api/artifacts-api.js @@ -146,7 +146,7 @@ const artifactsApi = { }, getArtifact: (projectName, artifactName, uid, tree, tag, iter) => { const newConfig = { - params: { tree, uid } + params: { tree, 'object-uid': uid } } if (tag) { diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 1f0914451a..c49c1fb273 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -2264,8 +2264,8 @@ function getArtifact(req, res) { artifact.metadata?.tree === req.query.tree || artifact?.tree === req.query.tree) && (isNil(req.query.uid) || - artifact.metadata?.uid === req.query.uid || - artifact?.uid === req.query.uid) + artifact.metadata?.uid === req.query['object-uid'] || + artifact?.uid === req.query['object-uid']) ) }) From 12eb3d38dd57f532928f3c8236ffc5abada16b5a Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Wed, 18 Jun 2025 11:22:50 +0300 Subject: [PATCH 019/228] Fix [Feature store] pages crash after creating feature set / vector with specific name (#3289) --- .../FunctionsPageOld/FunctionsOld.jsx | 2 +- .../JobWizardFunctionSelection.jsx | 2 +- src/elements/ProjectJobs/projectJobs.utils.js | 2 +- src/utils/getUniqueIdentifier.js | 24 +++++++++++-------- tests/mockServer/mock.js | 10 +++++--- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/components/FunctionsPageOld/FunctionsOld.jsx b/src/components/FunctionsPageOld/FunctionsOld.jsx index 7e7b12a2c4..0e10744bef 100644 --- a/src/components/FunctionsPageOld/FunctionsOld.jsx +++ b/src/components/FunctionsPageOld/FunctionsOld.jsx @@ -228,7 +228,7 @@ const Functions = () => { return { ...state, [funcIdentifier]: { - content: content[func.name].map(contentItem => + content: content[funcIdentifier].map(contentItem => createFunctionsRowData(contentItem, params.projectName, false, false, true) ) } diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx index 18c36649c9..3c0eeb250b 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx @@ -280,7 +280,7 @@ const JobWizardFunctionSelection = ({ prev[curr.metadata.name].functions.push(curr) return prev - }, {}) + }, Object.create(null)) ) setFunctions(groupedFunctions) diff --git a/src/elements/ProjectJobs/projectJobs.utils.js b/src/elements/ProjectJobs/projectJobs.utils.js index 68b539e55e..2103042c64 100644 --- a/src/elements/ProjectJobs/projectJobs.utils.js +++ b/src/elements/ProjectJobs/projectJobs.utils.js @@ -117,7 +117,7 @@ export const getJobsTableData = (jobs, projectName) => { } export const groupByName = content => { - const groupedItems = {} + const groupedItems = Object.create(null) content.forEach(contentItem => { groupedItems[contentItem.metadata.name] diff --git a/src/utils/getUniqueIdentifier.js b/src/utils/getUniqueIdentifier.js index 120f1223c2..13d609d065 100644 --- a/src/utils/getUniqueIdentifier.js +++ b/src/utils/getUniqueIdentifier.js @@ -42,7 +42,7 @@ export const getArtifactIdentifier = (artifact, unique) => { if (artifact?.metadata?.tag) identifier += `.${artifact?.metadata?.tag}` } - return identifier + return identifier && `id.${identifier}` } export const getFunctionIdentifier = (func, unique) => { @@ -53,13 +53,13 @@ export const getFunctionIdentifier = (func, unique) => { if (func?.tag) identifier += `.${func.tag}` } - return identifier + return identifier && `id.${identifier}` } export const getAlertIdentifier = (alert, unique) => { let identifier = `${alert?.name || ''}` if (unique && alert?.id) identifier += `.${alert.id}` - return identifier + return identifier && `id.${identifier}` } export const getJobIdentifier = (job, unique) => { @@ -67,7 +67,7 @@ export const getJobIdentifier = (job, unique) => { if (unique && job?.uid) identifier += `.${job.uid}` - return identifier + return identifier && `id.${identifier}` } export const getWorkflowJobIdentifier = (job, unique) => { @@ -86,7 +86,7 @@ export const getWorkflowJobIdentifier = (job, unique) => { if (jobId) identifier += `.${jobId}` - return identifier + return identifier && `id.${identifier}` } export const getFeatureIdentifier = (feature, unique) => { @@ -96,7 +96,7 @@ export const getFeatureIdentifier = (feature, unique) => { if (feature.metadata?.name) identifier += `.${feature.metadata.name}` if (feature.ui?.type) identifier += `.${feature.ui.type}` - return identifier + return identifier && `id.${identifier}` } export const getFeatureSetIdentifier = (featureSet, unique) => { @@ -105,7 +105,7 @@ export const getFeatureSetIdentifier = (featureSet, unique) => { if (unique && featureSet?.tag) identifier += `.${featureSet.tag}` if (unique && featureSet?.uid) identifier += `.${featureSet.uid}` - return identifier + return identifier && `id.${identifier}` } export const getFeatureVectorIdentifier = (featureVector, unique) => { @@ -114,23 +114,27 @@ export const getFeatureVectorIdentifier = (featureVector, unique) => { if (unique && featureVector?.tag) identifier += `.${featureVector.tag}` if (unique && featureVector?.uid) identifier += `.${featureVector.uid}` - return identifier + return identifier && `id.${identifier}` } export const getV3ioStreamIdentifier = (v3ioStream, consumerGroupIsObject) => { - return get( + const identifier = get( v3ioStream, consumerGroupIsObject ? 'consumerGroup.identifierUnique' : 'consumerGroup', '' ) + + return consumerGroupIsObject ? identifier : `id.${identifier}` } export const getV3ioStreamShardLagIdentifier = (v3ioStream, shardLagIdIsObject) => { - return get( + const identifier = get( v3ioStream, shardLagIdIsObject ? 'shardLagId.identifierUnique' : 'shardLagId', '' ) + + return shardLagIdIsObject ? identifier : `id.${identifier}` } export const getIdentifierMethod = tab => { diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index c49c1fb273..f65ac7a7c3 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -431,9 +431,13 @@ function getFeatureSet(req, res) { } if (req.query['name']) { - collectedFeatureSets = collectedFeatureSets.filter(featureSet => - featureSet.metadata.name.includes(req.query['name'].slice(1)) - ) + collectedFeatureSets = collectedFeatureSets.filter(featureSet => { + if (req.query['name'].startsWith?.('~')) { + return featureSet.metadata.name.includes(req.query['name'].slice(1)) + } + + return featureSet.metadata.name === req.query['name'] + }) } if (req.query['label']) { From 261d340a00f7ac9d982023b2aae4db3928cea0ab Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:24:32 +0200 Subject: [PATCH 020/228] Tests [QA] v1.10.0-rc4 (#3295) --- tests/features/common-tools/common-consts.js | 22 +- tests/features/common/page-objects.js | 4 + .../common/page-objects/llm-prompts.po.js | 82 ++++ .../common/page-objects/monitoring-app.po.js | 244 +++++++++- tests/features/llmPrompts.feature | 52 ++- tests/features/monitoringApp.feature | 431 +++++++++++++++++- tests/features/projectMonitoring.feature | 1 + tests/features/projectsPage.feature | 2 +- 8 files changed, 830 insertions(+), 8 deletions(-) create mode 100644 tests/features/common/page-objects/llm-prompts.po.js diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index ca180a98be..e2bc5dd593 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -381,10 +381,13 @@ export default { FilterBy_Button: 'Filter', FilterBy_Button_1: 'Filter (1)', Show_All_Versions: 'Show all versions', + Open_Metrics: 'Open metrics', Refresh_Button: 'Refresh', + Back_Button: 'Back', Expand_All_Button: 'Expand all', In_Process_Jobs: 'Aborting, Pending, Running', - In_Process_Workflows: 'Running', + Running_Tip: 'Running', + Failed_Tip: 'Failed', Failed_Jobs: 'Aborted, Error', Failed_Worflows: 'Error, Failed', Succeeded: 'Completed', @@ -524,7 +527,16 @@ export default { ' You can browse them in the Feature store page.', Artifacts_Stats_Tip: 'Each artifact can have multiple versions, produced by multiple runs and given multiple tags.\n' + - ' You can browse them in the Artifacts page.' + ' You can browse them in the Artifacts page.', + Model_Endpoint_With_Detections: + 'This chart displays the number of model endpoints that had at least one detected issue, in any monitoring application, in the relevant time period', + Operating_Functions: 'System functions that are used for the monitoring application operation', + Lag: 'Number of messages currently waiting in the app\'s queue', + Commited_Offset: 'Total number of messages handled by the app', + App_Status_Tip: 'Some tip', + Endpoints_Tip: 'Model endpoints processed by the monitoring app during the selected time frame', + Metrics_Tip: 'Metrics tip', + Shards_Partitions_Status_Tip: 'This table displays the current status of each shard' }, Descriptions: { Archive_Project: @@ -672,6 +684,12 @@ export default { 'Past month', 'Custom range' ], + Date_Picker_Filter_Options_Monitoring_App: [ + 'Past hour', + 'Past 24 hours', + 'Past week', + 'Past month' + ], Scheduled_Date_Picker_Filter_Options: [ 'Any time', 'Next hour', diff --git a/tests/features/common/page-objects.js b/tests/features/common/page-objects.js index 110e36557c..42df075d58 100644 --- a/tests/features/common/page-objects.js +++ b/tests/features/common/page-objects.js @@ -34,6 +34,7 @@ import models from './page-objects/models.po' import documents from './page-objects/documents.po' import alerts from './page-objects/alerts.po' import monitoringApp from './page-objects/monitoring-app.po' +import llmPrompts from './page-objects/llm-prompts.po' export default { Add_To_Feature_Vector_Popup: interactivePopup['addToFeatureVectorPopup'], @@ -45,6 +46,8 @@ export default { Alerts_Endpoint_Info_Pane: infoPane['alertsEndpointInfoPane'], Alerts_Application_Info_Pane: infoPane['alertsApplicationInfoPane'], Analysis_Info_Pane: infoPane['analysisInfoPane'], + Application_Metrics: monitoringApp['applicationMetrics'], + Application_Monitoring: monitoringApp['applicationMonitoring'], Artifact_Preview_Popup: interactivePopup['artifactPreviewPopup'], Artifacts_Info_Pane: infoPane['artifactsInfoPane'], Change_Project_Owner_Popup: interactivePopup['changeProjectOwnerPopup'], @@ -81,6 +84,7 @@ export default { Jobs_Monitoring_Workflows_Tab: jobsMonitoring['crossWorkflowsMonitorTab'], Jobs_Monitoring_Scheduled_Tab: jobsMonitoring['crossScheduledMonitorTab'], Jobs_Monitor_Tab_Info_Pane: infoPane['jobsMonitorTabInfoPane'], + LLM_Prompts: llmPrompts['llmPrompts'], Metrics_Selector_Popup: interactivePopup['metricsSelectorPopup'], ML_Function_Info_Pane: infoPane['mlFunctionInfoPane'], ML_Functions: Functions['mlFunctions'], diff --git a/tests/features/common/page-objects/llm-prompts.po.js b/tests/features/common/page-objects/llm-prompts.po.js new file mode 100644 index 0000000000..9b36a87c0e --- /dev/null +++ b/tests/features/common/page-objects/llm-prompts.po.js @@ -0,0 +1,82 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import { By } from 'selenium-webdriver' +import commonTable from '../components/table.component' +import dropdownComponent from '../components/dropdown.component' +import { + generateInputGroup, + generateDropdownGroup +} from '../../common-tools/common-tools' +import inputGroup from '../components/input-group.component' + +const commonSearchByNameFilterInput = inputGroup( + generateInputGroup( + '[data-testid="name-form-field-input"]', + true, + false + ) +) + +const overallTable = { + root: '.table__content', + header: { + root: '.table-header', + sorters: { + name: '[data-testid="name"] .data-ellipsis', + labels: '[data-testid="labels"] .data-ellipsis', + producer: '[data-testid="producer"] .data-ellipsis', + owner: '[data-testid="owner"] .data-ellipsis', + updated: '[data-testid="updated"] .data-ellipsis', + size: '[data-testid="size"] .data-ellipsis' + } + }, + body: { + root: '.table-body', + row: { + root: '.table-row', + fields: { + name: '[data-testid="name"] a .link', + labels: { + componentType: dropdownComponent, + structure: generateDropdownGroup( + '.table-body__cell:nth-of-type(7)', + '.chip-block span.chips_button', + '.chip-block-hidden_visible .data-ellipsis.tooltip-wrapper', + false, + false + ) + }, + producer: '[data-testid="producer"] .data-ellipsis', + owner: '[data-testid="owner"] .data-ellipsis', + updated: '[data-testid="updated"] .data-ellipsis', + size: '[data-testid="size"] .data-ellipsis' + } + } + } +} + +export default { + llmPrompts: { + Search_By_Name_Filter_Input: commonSearchByNameFilterInput, + Table_FilterBy_Button: By.css('[data-testid="filter-menu-btn-tooltip-wrapper"]'), + Refresh_Button: By.css('[data-testid="refresh"] [data-testid="refresh-tooltip-wrapper"]'), + LLMPrompts_Table: commonTable(overallTable) + } +} diff --git a/tests/features/common/page-objects/monitoring-app.po.js b/tests/features/common/page-objects/monitoring-app.po.js index 87391e4e96..bd3f4d0ab3 100644 --- a/tests/features/common/page-objects/monitoring-app.po.js +++ b/tests/features/common/page-objects/monitoring-app.po.js @@ -21,9 +21,11 @@ import { By } from 'selenium-webdriver' import commonTable from '../components/table.component' import dropdownComponent from '../components/dropdown.component' import { - generateDropdownGroup + generateDropdownGroup, + generateInputGroup } from '../../common-tools/common-tools' import datepicker from '../components/date-picker.component' +import inputGroup from '../components/input-group.component' const commonDatePickerFilter = dropdownComponent( generateDropdownGroup( @@ -113,11 +115,251 @@ const dateTimePickerCalendars = { } // datepicker end +const operatingFunctionsTable = { + root: '.monitoring-apps .monitoring-app__section-item .section-table', + header: { + root: '.section-table__table-header', + sorters: { + name: '.table-cell_big .data-ellipsis', + status: '.table-cell_small(1) .data-ellipsis', + started_at: '.table-cell_medium .data-ellipsis', + lag: '.table-cell_small(2) .data-ellipsis', + commited_offset: '.table-cell_small(3) .data-ellipsis' + } + }, + body: { + root: '.section-table__table-body', + row: { + root: '.section-table__table-row', + fields: { + name: '.table-cell_big a .data-ellipsis', + status: '.table-cell_small:nth-of-type(2) .data-ellipsis', + started_at: '.table-cell_medium .data-ellipsis' + } + } + } +} + +const allApplicationsTable = { + root: '.monitoring-apps #main-table', + header: { + root: '.table-header', + sorters: { + name: '[data-testid="name"] span', + lag: '[data-testid="lag"] span', + commited_offset: '[data-testid="commitedOffset"] span', + detections: '[data-testid="detections"] span', + possible_detections: '[data-testid="possibleDetections"] span', + class: '[data-testid="class"] span', + startedAt: '[data-testid="startedAt"] span', + updated: '[data-testid="updated"] span', + nuclioFunction: '[data-testid="nuclioFunction"] span' + } + }, + body: { + root: '#main-table-body', + row: { + root: '.table-row', + fields: { + name: '[data-testid="name"] a .data-ellipsis', + nuclioFunction: '[data-testid="nuclioFunction"] .link .item-name', + nuclioFunctionStatus: '[data-testid="nuclioFunction"] .link .status', + open_metrics: '[data-testid="quick-link-open-metrics"]' + } + } + } +} + +const artifactsTable = { + root: '.monitoring-app__section:nth-of-type(1) .section-table', + header: { + root: '.section-table__table-header', + sorters: { + name: '.section-table__table-cell:nth-of-type(1) .data-ellipsis' + } + }, + body: { + root: '.section-table__table-body', + row: { + root: '.section-table__table-row', + fields: { + name: '.section-table__table-cell:nth-of-type(1) .data-ellipsis', + labels: { + componentType: dropdownComponent, + structure: generateDropdownGroup( + '.table-cell_medium', + '', + '', + false, + false + ) + } + } + } + } +} + +const resultsTable = { + root: '.monitoring-app__section.section_small:nth-of-type(2) .monitoring-app__section-item:nth-of-type(1) .section-table', + header: { + root: '.section-table__table-header', + sorters: { + name: '.section-table__table-cell:nth-of-type(1) .data-ellipsis' + } + }, + body: { + root: '.section-table__table-body', + row: { + root: '.section-table__table-row', + fields: { + name: '.section-table__table-cell:nth-of-type(1) .data-ellipsis' + } + } + } +} + +const metricsTable = { + root: '.monitoring-app__section.section_small:nth-of-type(2) .monitoring-app__section-item:nth-of-type(2) .section-table', + header: { + root: '.section-table__table-header', + sorters: { + name: '.section-table__table-cell:nth-of-type(1) .data-ellipsis' + } + }, + body: { + root: '.section-table__table-body', + row: { + root: '.section-table__table-row', + fields: { + name: '.section-table__table-cell:nth-of-type(1) .data-ellipsis' + } + } + } +} + +const shardsPartitionsStatusTable = { + root: '.monitoring-app__section.section_small:nth-of-type(3) .monitoring-app__section-item:nth-of-type(1) .section-table', + header: { + root: '.section-table__table-header', + sorters: { + name: '.section-table__table-cell:nth-of-type(1) .data-ellipsis' + } + }, + body: { + root: '.section-table__table-body', + row: { + root: '.section-table__table-row', + fields: { + name: '.section-table__table-cell:nth-of-type(1) .data-ellipsis' + } + } + } +} + +const endpointsListTable = { + root: '.list-view .list-view__section:nth-of-type(1) .list-view__section-list__items-wrapper', + header: {}, + body: { + root: '#LIST_ID', + row: { + root: 'li', + fields: { + name: '.data-ellipsis' + } + } + } +} + +const searchByEndpointFilterInput = inputGroup( + generateInputGroup( + '.application-metrics-container .list-view .list-view__section:nth-of-type(1) .list-view__section-list__search__name-filter', + true, + false + ) +) + export default { monitoringApp: { Refresh_Button: By.css('[data-testid="refresh"] [data-testid="refresh-tooltip-wrapper"]'), Date_Picker_Filter_Dropdown: commonDatePickerFilter, Custom_Range_Filter_Dropdown: commonCustomRangeFilter, Date_Time_Picker: datepicker(dateTimePickerCalendars), + Applications_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__row:nth-of-type(1) .stats-card__title span'), + Applications_Stats_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__row:nth-of-type(2) .stats__counter'), + Apps_Status_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(1) .stats-card__title span'), + Apps_Status_Running_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="running_status"] .stats__subtitle'), + Apps_Status_Failed_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="failed_status"] .stats__subtitle'), + Apps_Status_Running_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-running"] .stats__counter'), + Apps_Status_Failed_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-failed"] .stats__counter'), + Apps_Status_Running_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="running_status"] i'), + Apps_Status_Failed_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="failed_status"] i'), + Endpoints_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(1) .stats-card__title span'), + Endpoints_Batch_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="batch_status"] .stats__subtitle'), + Endpoints_RealTime_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="realTime_status"] .stats__subtitle'), + Endpoints_Batch_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-batch"] .stats__counter'), + Endpoints_RealTime_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-realTime"] .stats__counter'), + RunningFrequency_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__row:nth-of-type(1) .stats-card__title span'), + RunningFrequency_Value_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-undefined"] .stats__counter'), + Model_Endpoint_Detections_Title: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(1) .monitoring-app__section-item:nth-of-type(1) .section-item_title span'), + Model_Endpoint_Detections_Tip: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(1) .monitoring-app__section-item:nth-of-type(1) .section-item_title [data-testid="tip"]'), + Model_Endpoint_Detections_Chart: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(1) .monitoring-app__section-item:nth-of-type(1) .section-item_chart-wrapper .chart-container'), + Operating_Functions_Title: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(1) .monitoring-app__section-item:nth-of-type(2) .section-item_title span'), + Operating_Functions_Tip: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(1) .monitoring-app__section-item:nth-of-type(2) .section-item_title [data-testid="tip"]'), + Operating_Functions_Table: commonTable(operatingFunctionsTable), + Operating_Functions_Lag_Tip: By.css('.monitoring-apps .monitoring-app__section-item .section-table .table-cell_small:nth-of-type(4) [data-testid="tip"] svg'), + Operating_Functions_Commited_Offset_Tip: By.css('.monitoring-apps .monitoring-app__section-item .section-table .table-cell_small:nth-of-type(5) [data-testid="tip"] svg'), + All_Applications_Title: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(2) .section-item_title span'), + All_Applications_Table: commonTable(allApplicationsTable), + All_Applications_Lag_Tip: By.css('.monitoring-apps #main-table [data-testid="lag"] [data-testid="tip"] svg'), + All_Applications_Commited_Offset_Tip: By.css('.monitoring-apps #main-table [data-testid="commitedOffset"] [data-testid="tip"] svg'), + }, + applicationMonitoring: { + Back_Button: By.css('.content__action-bar-wrapper .table-top .link-back__icon button'), + Application_Name: By.css('.content__action-bar-wrapper .table-top .link-back__title .data-ellipsis'), + Date_Picker_Filter_Dropdown: commonDatePickerFilter, + Custom_Range_Filter_Dropdown: commonCustomRangeFilter, + Date_Time_Picker: datepicker(dateTimePickerCalendars), + Application_Metrics_Button: By.css('.action-bar [data-testid="btn"] span'), + Refresh_Button: By.css('.action-bar [data-testid="refresh"] button'), + App_Status_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__title span'), + App_Status_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) [data-testid="tip"] svg'), + App_Status_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) [data-testid="monitoring-app-appStatus"] .stats__counter'), + Endpoints_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__title span'), + Endpoints_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) [data-testid="tip"] svg'), + Endpoints_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) [data-testid="monitoring-app-endpoints"] .stats__counter'), + Detections_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__title span'), + Detections_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) [data-testid="monitoring-app-detections"] .stats__counter'), + Possible_Detections_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__title span'), + Possible_Detections_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) [data-testid="monitoring-app-possibleDetections"] .stats__counter'), + Lag_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(5) .stats-card__title span'), + Lag_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(5) [data-testid="tip"] svg'), + Lag_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(5) [data-testid="monitoring-app-lag"] .stats__counter'), + Commited_Offset_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(6) .stats-card__title span'), + Commited_Offset_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(6) [data-testid="tip"] svg'), + Commited_Offset_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(6) [data-testid="monitoring-app-commitedOffset"] .stats__counter'), + Artifacts_Title: By.css('.monitoring-app__section .section-item_title span'), + Artifacts_Table: commonTable(artifactsTable), + See_All_Link: By.css('.monitoring-app__section-item .monitoring-app__see-all-link'), + Results_Title: By.css('.monitoring-app__section.section_small:nth-of-type(2) .monitoring-app__section-item:nth-of-type(1) .section-item_title span'), + Results_Table: commonTable(resultsTable), + Metrics_Title: By.css('.monitoring-app__section.section_small:nth-of-type(2) .monitoring-app__section-item:nth-of-type(2) .section-item_title span'), + Metrics_Tip: By.css('.monitoring-app__section.section_small:nth-of-type(2) .monitoring-app__section-item:nth-of-type(2) [data-testid="tip"] svg'), + Metrics_Table: commonTable(metricsTable), + Shards_Partitions_Status_Title: By.css('.monitoring-app__section.section_small:nth-of-type(3) .monitoring-app__section-item:nth-of-type(1) .section-item_title span'), + Shards_Partitions_Status_Tip: By.css('.monitoring-app__section.section_small:nth-of-type(3) .monitoring-app__section-item:nth-of-type(1) [data-testid="tip"] svg'), + Shards_Partitions_Status_Table: commonTable(shardsPartitionsStatusTable), + Partitions_Status_Lag_Tip: By.css('.monitoring-app__section.section_small:nth-of-type(3) .monitoring-app__section-item:nth-of-type(1) .section-table .section-table__table-cell:nth-of-type(2) [data-testid="tip"] svg'), + Partitions_Status_Commited_Offset_Tip: By.css('.monitoring-app__section.section_small:nth-of-type(3) .monitoring-app__section-item:nth-of-type(1) .section-table .section-table__table-cell:nth-of-type(3) [data-testid="tip"] svg'), + }, + applicationMetrics: { + Back_Button: By.css('.content__action-bar-wrapper .history-back-link [data-testid="history-back-link-btn"]'), + Applications_Metrics_Title: By.css('.content__action-bar-wrapper .history-back-link .history-back-link__title [data-testid="version-history"]'), + Application_Name: By.css('.content__action-bar-wrapper .history-back-link .history-back-link__title .data-ellipsis'), + Application_Monitoring_Button: By.css('.action-bar [data-testid="btn"] span'), + Refresh_Button: By.css('[data-testid="refresh"] [data-testid="refresh-tooltip-wrapper"]'), + Endpoints_List_Section: By.css('.application-metrics-container .list-view .list-view__section:nth-of-type(1)'), + Search_By_Endpoint_Filter_Input: searchByEndpointFilterInput, + Search_Endpoints_Counter: By.css('.application-metrics-container .list-view .list-view__section:nth-of-type(1) .list-view__section-list__search_endpoints-counter'), + Endpoints_List_Table: commonTable(endpointsListTable), } } diff --git a/tests/features/llmPrompts.feature b/tests/features/llmPrompts.feature index 1874682e0a..ea20a8653e 100644 --- a/tests/features/llmPrompts.feature +++ b/tests/features/llmPrompts.feature @@ -7,6 +7,8 @@ Feature: LLM prompts Page Scenario: MLLP001 - Check components on LLM prompts page Given open url And wait load page + When turn on demo mode with query params "false" + And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page Then verify breadcrumbs "tab" label should be equal "Project monitoring" value @@ -15,7 +17,8 @@ Feature: LLM prompts Page And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard And wait load page - Then verify redirection to "projects/default/llm-prompts" + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/default/llm-prompts?bePage=1&fePage=1" And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Project monitoring" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard @@ -24,4 +27,49 @@ Feature: LLM prompts Page And wait load page And select "tab" with "LLM prompts" value in breadcrumbs menu And wait load page - Then verify redirection to "projects/default/llm-prompts" + Then verify redirection to "projects/default/llm-prompts?bePage=1&fePage=1" + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify "Search_By_Name_Filter_Input" element visibility on "LLM_Prompts" wizard + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then verify "Table_FilterBy_Button" element visibility on "LLM_Prompts" wizard + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + And wait load page + Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Table_Tree_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected attribute option value "latest" + Then verify "Show_Iterations_Checkbox" element visibility on "FilterBy_Popup" wizard + Then "Show_Iterations_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Clear_Button" element on "FilterBy_Popup" wizard is disabled + Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Apply_Button" element on "FilterBy_Popup" wizard is disabled + Then uncheck "Show_Iterations_Checkbox" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Apply_Button" element on "FilterBy_Popup" wizard is enabled + Then verify "Clear_Button" element on "FilterBy_Popup" wizard is enabled + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + And wait load page + Then "Show_Iterations_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then verify "Apply_Button" element on "FilterBy_Popup" wizard is disabled + Then verify "Clear_Button" element on "FilterBy_Popup" wizard is enabled + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + And wait load page + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then verify "Refresh_Button" element visibility on "LLM_Prompts" wizard + Then verify "Refresh_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" + Then verify "BE_Pagination_Navigate_Prev" element visibility on "Pagination_Info_Pane" wizard + Then verify "BE_Pagination_Navigate_Prev" element on "Pagination_Info_Pane" wizard is disabled + Then verify "BE_Pagination_Navigate_Next" element visibility on "Pagination_Info_Pane" wizard + Then verify "BE_Pagination_Navigate_Next" element on "Pagination_Info_Pane" wizard is disabled + Then verify "FE_Pagination_Navigate_Next" element visibility on "Pagination_Info_Pane" wizard + Then verify "FE_Pagination_Navigate_Next" element on "Pagination_Info_Pane" wizard is disabled + Then verify "FE_Pagination_Navigate_Prev" element visibility on "Pagination_Info_Pane" wizard + Then verify "FE_Pagination_Navigate_Prev" element on "Pagination_Info_Pane" wizard is disabled + Then verify "Pagination_Page_Number" element visibility on "Pagination_Info_Pane" wizard + Then "Pagination_Page_Number" element on "Pagination_Info_Pane" should contains "1" value + Then verify "Pagination_Count" element visibility on "Pagination_Info_Pane" wizard + Then "Pagination_Count" element on "Pagination_Info_Pane" should contains "Showing 1 - 3" value diff --git a/tests/features/monitoringApp.feature b/tests/features/monitoringApp.feature index 54c31fca79..8abfaff272 100644 --- a/tests/features/monitoringApp.feature +++ b/tests/features/monitoringApp.feature @@ -4,11 +4,13 @@ Feature: Monitoring app Page @MLMA @smoke - Scenario: MLMA001 - Check components on Monitoring app page + Scenario: MLMA001 - Check action bar components on Monitoring app page Given open url And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page + When turn on demo mode with query params "false" + And wait load page Then verify breadcrumbs "tab" label should be equal "Project monitoring" value Then verify breadcrumbs "project" label should be equal "default" value And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard @@ -27,6 +29,431 @@ Feature: Monitoring app Page And wait load page Then verify "Date_Picker_Filter_Dropdown" element visibility on "Monitoring_App" wizard Then verify "Date_Picker_Filter_Dropdown" dropdown on "Monitoring_App" wizard selected option value "Past 24 hours" - Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Monitoring_App" wizard should contains "Dropdown_Options"."Date_Picker_Filter_Options_Endpoint" + Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Monitoring_App" wizard should contains "Dropdown_Options"."Date_Picker_Filter_Options_Monitoring_App" Then verify "Refresh_Button" element visibility on "Monitoring_App" wizard Then verify "Refresh_Button" element on "Monitoring_App" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + When select "Past hour" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Monitoring_App" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Monitoring_App" wizard selected option value "Past hour" + When select "Past week" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Monitoring_App" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Monitoring_App" wizard selected option value "Past week" + When select "Past month" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Monitoring_App" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Monitoring_App" wizard selected option value "Past month" + + @MLMA + @smoke + Scenario: MLMA002 - Check statistics section components on Monitoring app page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "default" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + Then verify "Applications_Stats_Title" element visibility on "Monitoring_App" wizard + Then "Applications_Stats_Title" element on "Monitoring_App" should contains "Applications" value + Then verify "Applications_Stats_Counter" element visibility on "Monitoring_App" wizard + Then verify "Apps_Status_Title" element visibility on "Monitoring_App" wizard + Then "Apps_Status_Title" element on "Monitoring_App" should contains "Apps Status" value + Then verify "Apps_Status_Running_SubTitle" element visibility on "Monitoring_App" wizard + Then "Apps_Status_Running_SubTitle" element on "Monitoring_App" should contains "Running" value + Then verify "Apps_Status_Running_Counter" element visibility on "Monitoring_App" wizard + Then verify "Apps_Status_Running_Tip" element visibility on "Monitoring_App" wizard + Then verify "Apps_Status_Running_Tip" element on "Monitoring_App" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" + Then verify "Apps_Status_Failed_SubTitle" element visibility on "Monitoring_App" wizard + Then "Apps_Status_Failed_SubTitle" element on "Monitoring_App" should contains "Failed" value + Then verify "Apps_Status_Failed_Counter" element visibility on "Monitoring_App" wizard + Then verify "Apps_Status_Failed_Tip" element visibility on "Monitoring_App" wizard + Then verify "Apps_Status_Failed_Tip" element on "Monitoring_App" wizard should display hover tooltip "Common_Tooltips"."Failed_Tip" + Then verify "Endpoints_Stats_Title" element visibility on "Monitoring_App" wizard + Then "Endpoints_Stats_Title" element on "Monitoring_App" should contains "Endpoints" value + Then verify "Endpoints_Batch_SubTitle" element visibility on "Monitoring_App" wizard + Then "Endpoints_Batch_SubTitle" element on "Monitoring_App" should contains "Batch" value + Then verify "Endpoints_Batch_Counter" element visibility on "Monitoring_App" wizard + Then verify "Endpoints_RealTime_SubTitle" element visibility on "Monitoring_App" wizard + Then "Endpoints_RealTime_SubTitle" element on "Monitoring_App" should contains "Real-time" value + Then verify "Endpoints_RealTime_Counter" element visibility on "Monitoring_App" wizard + Then verify "RunningFrequency_Stats_Title" element visibility on "Monitoring_App" wizard + Then "RunningFrequency_Stats_Title" element on "Monitoring_App" should contains "Running frequency" value + Then verify "RunningFrequency_Value_Title" element visibility on "Monitoring_App" wizard + Then "RunningFrequency_Value_Title" element on "Monitoring_App" should contains "Every 10 minutes" value + + @MLMA + @smoke + Scenario: MLMA003 - Check monitoring-app section components on Monitoring app page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And select "tab" with "Monitoring app" value in breadcrumbs menu + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "Model_Endpoint_Detections_Title" element visibility on "Monitoring_App" wizard + Then "Model_Endpoint_Detections_Title" element on "Monitoring_App" should contains "Model Endpoint with detections" value + Then verify "Model_Endpoint_Detections_Tip" element visibility on "Monitoring_App" wizard + Then verify "Model_Endpoint_Detections_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Model_Endpoint_With_Detections" + Then verify "Model_Endpoint_Detections_Chart" element visibility on "Monitoring_App" wizard + Then verify "Operating_Functions_Title" element visibility on "Monitoring_App" wizard + Then "Operating_Functions_Title" element on "Monitoring_App" should contains "Operating functions" value + Then verify "Operating_Functions_Tip" element visibility on "Monitoring_App" wizard + Then verify "Operating_Functions_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Operating_Functions" + Then verify "Operating_Functions_Table" element visibility on "Monitoring_App" wizard + Then verify "Operating_Functions_Lag_Tip" element visibility on "Monitoring_App" wizard + Then verify "Operating_Functions_Lag_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Lag" + Then verify "Operating_Functions_Commited_Offset_Tip" element visibility on "Monitoring_App" wizard + Then verify "Operating_Functions_Commited_Offset_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Commited_Offset" + + @MLMA + @smoke + Scenario: MLMA004 - Check All Applications section components on Monitoring app page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And select "tab" with "Monitoring app" value in breadcrumbs menu + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then verify "All_Applications_Table" element visibility on "Monitoring_App" wizard + Then verify "All_Applications_Lag_Tip" element visibility on "Monitoring_App" wizard + Then verify "All_Applications_Lag_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Lag" + Then verify "All_Applications_Commited_Offset_Tip" element visibility on "Monitoring_App" wizard + Then verify "All_Applications_Commited_Offset_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Commited_Offset" + Then verify "open_metrics" option is present on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column + Then verify "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column should display hover tooltip "Common_Tooltips"."Open_Metrics" with scroll "false" + Then click on "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column with scroll "false" + And wait load page + Then verify "Application_Monitoring_Button" element visibility on "Application_Metrics" wizard + Then "Application_Monitoring_Button" element on "Application_Metrics" should contains "Application monitoring" value + Then navigate back + And wait load page + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Application_Metrics_Button" element visibility on "Application_Monitoring" wizard + Then "Application_Metrics_Button" element on "Application_Monitoring" should contains "Application metrics" value + + @MLMA + @smoke + Scenario: MLMA005 - Check action bar components on Application monitoring page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Back_Button" element visibility on "Application_Monitoring" wizard + Then verify "Back_Button" element on "Application_Monitoring" wizard should display hover tooltip "Common_Tooltips"."Back_Button" + Then click on "Back_Button" element on "Application_Monitoring" wizard + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv2" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Application_Name" element visibility on "Application_Monitoring" wizard + Then "Application_Name" element on "Application_Monitoring" should contains "monitorAppV2" value + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Application_Monitoring" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Application_Monitoring" wizard selected option value "Past 24 hours" + Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Application_Monitoring" wizard should contains "Dropdown_Options"."Date_Picker_Filter_Options_Monitoring_App" + When select "Past hour" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Application_Monitoring" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Application_Monitoring" wizard selected option value "Past hour" + When select "Past week" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Application_Monitoring" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Application_Monitoring" wizard selected option value "Past week" + When select "Past month" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Application_Monitoring" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Application_Monitoring" wizard selected option value "Past month" + Then verify "Application_Metrics_Button" element visibility on "Application_Monitoring" wizard + Then "Application_Metrics_Button" element on "Application_Monitoring" should contains "Application metrics" value + Then click on "Application_Metrics_Button" element on "Application_Monitoring" wizard + And wait load page + Then verify "Application_Monitoring_Button" element visibility on "Application_Metrics" wizard + Then "Application_Monitoring_Button" element on "Application_Metrics" should contains "Application monitoring" value + Then click on "Application_Monitoring_Button" element on "Application_Metrics" wizard + And wait load page + Then verify "Application_Name" element visibility on "Application_Monitoring" wizard + Then "Application_Name" element on "Application_Monitoring" should contains "monitorAppV2" value + And wait load page + Then verify "Refresh_Button" element visibility on "Application_Monitoring" wizard + Then verify "Refresh_Button" element on "Application_Monitoring" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + And wait load page + Then click on "Refresh_Button" element on "Application_Monitoring" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + Then verify "Back_Button" element visibility on "Application_Monitoring" wizard + Then "Application_Name" element on "Application_Monitoring" should contains "monitorAppV2" value + Then "Application_Metrics_Button" element on "Application_Monitoring" should contains "Application metrics" value + + @MLMA + @smoke + Scenario: MLMA006 - Check statistics section components on Application monitoring page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Back_Button" element visibility on "Application_Monitoring" wizard + Then verify "App_Status_Title" element visibility on "Application_Monitoring" wizard + Then "App_Status_Title" element on "Application_Monitoring" should contains "App Status" value + Then verify "App_Status_Tip" element visibility on "Application_Monitoring" wizard + Then verify "App_Status_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."App_Status_Tip" + Then verify "App_Status_SubTitle" element visibility on "Application_Monitoring" wizard + Then "App_Status_SubTitle" element on "Application_Monitoring" should contains "Ready" value + Then verify "Endpoints_Title" element visibility on "Application_Monitoring" wizard + Then "Endpoints_Title" element on "Application_Monitoring" should contains "Endpoints" value + Then verify "Endpoints_Tip" element visibility on "Application_Monitoring" wizard + Then verify "Endpoints_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."Endpoints_Tip" + Then verify "Endpoints_Counter" element visibility on "Application_Monitoring" wizard + Then verify "Detections_Title" element visibility on "Application_Monitoring" wizard + Then "Detections_Title" element on "Application_Monitoring" should contains "Detections" value + Then verify "Detections_Counter" element visibility on "Application_Monitoring" wizard + Then verify "Possible_Detections_Title" element visibility on "Application_Monitoring" wizard + Then "Possible_Detections_Title" element on "Application_Monitoring" should contains "Possible Detections" value + Then verify "Possible_Detections_Counter" element visibility on "Application_Monitoring" wizard + Then verify "Lag_Title" element visibility on "Application_Monitoring" wizard + Then "Lag_Title" element on "Application_Monitoring" should contains "Lag" value + Then verify "Lag_Tip" element visibility on "Application_Monitoring" wizard + Then verify "Lag_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."Lag" + Then verify "Lag_Counter" element visibility on "Application_Monitoring" wizard + Then verify "Commited_Offset_Title" element visibility on "Application_Monitoring" wizard + Then "Commited_Offset_Title" element on "Application_Monitoring" should contains "Commited Offset" value + Then verify "Commited_Offset_Tip" element visibility on "Application_Monitoring" wizard + Then verify "Commited_Offset_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."Commited_Offset" + Then verify "Commited_Offset_Counter" element visibility on "Application_Monitoring" wizard + + @MLMA + @smoke + Scenario: MLMA007 - Check Artifacts section components on Application monitoring page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Artifacts_Title" element visibility on "Application_Monitoring" wizard + Then "Artifacts_Title" element on "Application_Monitoring" should contains "Artifacts" value + Then verify "Artifacts_Table" element visibility on "Application_Monitoring" wizard + Then verify "See_All_Link" element visibility on "Application_Monitoring" wizard + Then click on "See_All_Link" element on "Application_Monitoring" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Artifacts" value + And wait load page + Then "Table_Name_Filter_Input" element on "Files" should contains "monitorAppV1" attribute value + And wait load page + + @MLMA + @smoke + Scenario: MLMA008 - Check Results section components on Application monitoring page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Results_Title" element visibility on "Application_Monitoring" wizard + Then "Results_Title" element on "Application_Monitoring" should contains "Results" value + Then verify "Results_Table" element visibility on "Application_Monitoring" wizard + + @MLMA + @smoke + Scenario: MLMA009 - Check Metrics section components on Application monitoring page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Metrics_Title" element visibility on "Application_Monitoring" wizard + Then "Metrics_Title" element on "Application_Monitoring" should contains "Metrics" value + Then verify "Metrics_Tip" element visibility on "Application_Monitoring" wizard + Then verify "Metrics_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."Metrics_Tip" + Then verify "Metrics_Table" element visibility on "Application_Monitoring" wizard + + @MLMA + @smoke + #TODO: Scroll to the Shards/partitions status section + Scenario: MLMA010 - Check Shards/partitions status section components on Application monitoring page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Shards_Partitions_Status_Title" element visibility on "Application_Monitoring" wizard + Then "Shards_Partitions_Status_Title" element on "Application_Monitoring" should contains "Shards/partitions status" value + Then verify "Shards_Partitions_Status_Tip" element visibility on "Application_Monitoring" wizard + Then verify "Shards_Partitions_Status_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."Shards_Partitions_Status_Tip" + Then verify "Shards_Partitions_Status_Table" element visibility on "Application_Monitoring" wizard + Then verify "Partitions_Status_Lag_Tip" element visibility on "Application_Monitoring" wizard + Then verify "Partitions_Status_Lag_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."Lag" + Then verify "Partitions_Status_Commited_Offset_Tip" element visibility on "Application_Monitoring" wizard + Then verify "Partitions_Status_Commited_Offset_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."Commited_Offset" + + @MLMA + @smoke + Scenario: MLMA011 - Check action bar components on Applications metrics page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Application_Metrics_Button" element visibility on "Application_Monitoring" wizard + Then "Application_Metrics_Button" element on "Application_Monitoring" should contains "Application metrics" value + Then click on "Application_Metrics_Button" element on "Application_Monitoring" wizard + And wait load page + Then verify "Back_Button" element visibility on "Application_Metrics" wizard + Then verify "Back_Button" element on "Application_Metrics" wizard should display hover tooltip "Common_Tooltips"."Back_Button" + Then click on "Back_Button" element on "Application_Metrics" wizard + And wait load page + Then verify "Back_Button" element visibility on "Application_Monitoring" wizard + Then click on "Back_Button" element on "Application_Monitoring" wizard + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then verify "open_metrics" option is present on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column + Then click on "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column with scroll "false" + And wait load page + Then verify "Applications_Metrics_Title" element visibility on "Application_Metrics" wizard + Then "Applications_Metrics_Title" element on "Application_Metrics" should contains "Applications metrics:" value + Then verify "Application_Name" element visibility on "Application_Metrics" wizard + Then "Application_Name" element on "Application_Metrics" should contains "monitorAppV1" value + Then verify "Application_Monitoring_Button" element visibility on "Application_Metrics" wizard + Then "Application_Monitoring_Button" element on "Application_Metrics" should contains "Application monitoring" value + Then verify "Refresh_Button" element visibility on "Application_Metrics" wizard + Then verify "Refresh_Button" element on "Application_Metrics" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + And wait load page + Then click on "Refresh_Button" element on "Application_Metrics" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + Then verify "Back_Button" element visibility on "Application_Metrics" wizard + Then "Application_Name" element on "Application_Metrics" should contains "monitorAppV1" value + Then "Application_Monitoring_Button" element on "Application_Metrics" should contains "Application monitoring" value + + @MLMA + @smoke + Scenario: MLMA012 - Check Endpoints list section components on Applications metrics page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + And wait load page + Then verify "Application_Metrics_Button" element visibility on "Application_Monitoring" wizard + Then "Application_Metrics_Button" element on "Application_Monitoring" should contains "Application metrics" value + Then click on "Application_Metrics_Button" element on "Application_Monitoring" wizard + And wait load page + Then verify "Applications_Metrics_Title" element visibility on "Application_Metrics" wizard + Then "Applications_Metrics_Title" element on "Application_Metrics" should contains "Applications metrics:" value + Then verify "Endpoints_List_Section" element visibility on "Application_Metrics" wizard + Then verify "Search_Endpoints_Counter" element visibility on "Application_Metrics" wizard + Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "2 endpoints found" value + Then verify "Endpoints_List_Table" element visibility on "Application_Metrics" wizard + Then verify "Search_By_Endpoint_Filter_Input" element visibility on "Application_Metrics" wizard + Then type value "boo" to "Search_By_Endpoint_Filter_Input" field on "Application_Metrics" wizard + And wait load page + Then value in "name" column with "text" in "Endpoints_List_Table" on "Application_Metrics" wizard should contains "GradientBoostingClassifier" + Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "1 endpoint found" value + Then type value "for" to "Search_By_Endpoint_Filter_Input" field on "Application_Metrics" wizard + And wait load page + Then value in "name" column with "text" in "Endpoints_List_Table" on "Application_Metrics" wizard should contains "RandomForestClassifier" + Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "1 endpoint found" value + Then type value "qwe" to "Search_By_Endpoint_Filter_Input" field on "Application_Metrics" wizard + And wait load page + Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "0 endpoints found" value diff --git a/tests/features/projectMonitoring.feature b/tests/features/projectMonitoring.feature index 91afe20084..b97d00ab18 100644 --- a/tests/features/projectMonitoring.feature +++ b/tests/features/projectMonitoring.feature @@ -17,6 +17,7 @@ Feature: Project Monitoring Page Then verify "Jobs_And_Workflows" element visibility on "Project" wizard Then verify "Mono_Values_Cards" element visibility on "Project" wizard Then verify "Model_Stats_Title" element visibility on "Project" wizard + Then "Model_Stats_Title" element on "Project" should contains "Models" value Then verify "Model_Stats_Tip" element visibility on "Project" wizard Then verify "Model_Stats_Tip" element on "Project" wizard should display hover hint "Label_Hint"."Model_Stats_Tip" Then verify "Model_Stats_Counter" element visibility on "Project" wizard diff --git a/tests/features/projectsPage.feature b/tests/features/projectsPage.feature index 753ea893a9..06b3d25482 100644 --- a/tests/features/projectsPage.feature +++ b/tests/features/projectsPage.feature @@ -449,7 +449,7 @@ Feature: Projects Page Then verify "Counter_Running_Status_Subtitle" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Counter_Running_Status_Subtitle" element in "Monitoring_Workflows_Box" on "Projects" should contains "In Process" value Then verify "Counter_Running_Status_Icon" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then verify "Counter_Running_Status_Icon" element in "Monitoring_Workflows_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Workflows" + Then verify "Counter_Running_Status_Icon" element in "Monitoring_Workflows_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then verify "Counter_Failed_Status_Subtitle" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Counter_Failed_Status_Subtitle" element in "Monitoring_Workflows_Box" on "Projects" should contains "Failed" value From 9ff9e4ad1c902e4d4eace8ed4206ada953e40ff7 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Wed, 18 Jun 2025 14:34:42 +0300 Subject: [PATCH 021/228] Fix [ML functions] Uncaught Runtime Error when loading ML functions with large data set (#3278) --- src/components/FunctionsPageOld/FunctionsOld.jsx | 2 ++ .../JobWizardFunctionSelection/JobWizardFunctionSelection.jsx | 3 +++ src/reducers/functionReducer.js | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/FunctionsPageOld/FunctionsOld.jsx b/src/components/FunctionsPageOld/FunctionsOld.jsx index 0e10744bef..dd7061ca82 100644 --- a/src/components/FunctionsPageOld/FunctionsOld.jsx +++ b/src/components/FunctionsPageOld/FunctionsOld.jsx @@ -196,6 +196,8 @@ const Functions = () => { }) } } + }).catch(() => { + setFunctions([]) }) }, [ diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx index 3c0eeb250b..6799395a2d 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx @@ -294,6 +294,9 @@ const JobWizardFunctionSelection = ({ } } }) + .catch(() => { + setFunctions([]) + }) formState.initialValues[FUNCTION_SELECTION_STEP].projectName = currentValue } diff --git a/src/reducers/functionReducer.js b/src/reducers/functionReducer.js index 67bdbfedef..11aca61f73 100644 --- a/src/reducers/functionReducer.js +++ b/src/reducers/functionReducer.js @@ -169,7 +169,7 @@ export const fetchFunctions = createAsyncThunk( thunkAPI.dispatch, setRequestErrorMessageLocal ) - thunkAPI.rejectWithValue(error.message) + return thunkAPI.rejectWithValue(error) }) } ) From dea9bb1b7be06c3d628df3534bbd993e04a13347 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Wed, 18 Jun 2025 14:34:58 +0300 Subject: [PATCH 022/228] Impl [Workflows] Add test IDs for Terminate button (#3300) --- src/components/Workflow/Workflow.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Workflow/Workflow.jsx b/src/components/Workflow/Workflow.jsx index 0b202ead25..f94a43b586 100644 --- a/src/components/Workflow/Workflow.jsx +++ b/src/components/Workflow/Workflow.jsx @@ -260,6 +260,7 @@ const Workflow = ({ {accessibleProjectsMap[projectName] && (
      ] ) From 80232777127a0aac6b6b9162d879229101c91ea3 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:27:48 +0300 Subject: [PATCH 024/228] Fix [Jobs, Projects] Confirmation messages don't appear on pages other than Jobs (#3305) --- src/components/ProjectsPage/Projects.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/ProjectsPage/Projects.jsx b/src/components/ProjectsPage/Projects.jsx index 77c0796ff5..9dc4ce2894 100644 --- a/src/components/ProjectsPage/Projects.jsx +++ b/src/components/ProjectsPage/Projects.jsx @@ -364,11 +364,8 @@ const Projects = () => { }, [refreshProjects]) useEffect(() => { - const terminateRef = terminatePollRef - return () => { abortControllerRef.current.abort() - terminateRef?.current?.() } }, []) From f636c88de9796d8c98041376a8a1049617b47e4f Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:27:58 +0300 Subject: [PATCH 025/228] Fix [Artifacts, Functions] closing details tab for specific item triggers incorrect page redirect (#3304) --- src/common/Pagination/Pagination.jsx | 10 ++++++---- src/components/ActionBar/ActionBar.jsx | 7 +++++-- src/components/Artifacts/Artifacts.jsx | 2 +- src/components/Artifacts/ArtifactsTable.jsx | 8 +++++++- src/components/FunctionsPage/FunctionsView.jsx | 4 +++- src/utils/link-helper.util.js | 9 ++++++--- 6 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/common/Pagination/Pagination.jsx b/src/common/Pagination/Pagination.jsx index 301674ba73..65c0ec1dcf 100644 --- a/src/common/Pagination/Pagination.jsx +++ b/src/common/Pagination/Pagination.jsx @@ -49,7 +49,8 @@ const Pagination = ({ closeParamName = '', disableNextDoubleBtn = false, disabledNextDoubleBtnTooltip = '', - paginationConfig + paginationConfig, + selectedItemName = '', }) => { const [, setSearchParams] = useSearchParams() const navigate = useNavigate() @@ -84,9 +85,9 @@ const Pagination = ({ const handlePageChange = useCallback(() => { if (closeParamName) { - navigate(getCloseDetailsLink(closeParamName, true), { replace: true }) + navigate(getCloseDetailsLink(closeParamName, true, selectedItemName), { replace: true }) } - }, [closeParamName, navigate]) + }, [closeParamName, navigate, selectedItemName]) const paginationItems = useMemo(() => { if (!paginationConfig[FE_PAGE]) return [] @@ -319,7 +320,8 @@ Pagination.propTypes = { closeParamName: PropTypes.string, disableNextDoubleBtn: PropTypes.bool, disabledNextDoubleBtnTooltip: PropTypes.string, - paginationConfig: PAGINATION_CONFIG.isRequired + paginationConfig: PAGINATION_CONFIG.isRequired, + selectedItemName: PropTypes.string } export default Pagination diff --git a/src/components/ActionBar/ActionBar.jsx b/src/components/ActionBar/ActionBar.jsx index 15360caa31..8f9ae6c2b2 100644 --- a/src/components/ActionBar/ActionBar.jsx +++ b/src/components/ActionBar/ActionBar.jsx @@ -75,6 +75,7 @@ const ActionBar = ({ hidden = false, internalAutoRefreshIsEnabled = false, removeSelectedItem = null, + selectedItemName = '', setSearchParams, setSelectedRowData = null, tab = '', @@ -191,7 +192,7 @@ const ActionBar = ({ if (actionCanBePerformed) { if (closeParamName) { - navigate(getCloseDetailsLink(closeParamName, true), { replace: true }) + navigate(getCloseDetailsLink(closeParamName, true, selectedItemName), { replace: true }) } if ( @@ -224,7 +225,8 @@ const ActionBar = ({ setSelectedRowData, toggleAllRows, handleRefresh, - navigate + navigate, + selectedItemName ] ) @@ -512,6 +514,7 @@ ActionBar.propTypes = { hidden: PropTypes.bool, internalAutoRefreshIsEnabled: PropTypes.bool, removeSelectedItem: PropTypes.func, + selectedItemName: PropTypes.string, setSearchParams: PropTypes.func.isRequired, setSelectedRowData: PropTypes.func, tab: PropTypes.string, diff --git a/src/components/Artifacts/Artifacts.jsx b/src/components/Artifacts/Artifacts.jsx index f46f443839..5c14cf45c4 100644 --- a/src/components/Artifacts/Artifacts.jsx +++ b/src/components/Artifacts/Artifacts.jsx @@ -106,7 +106,7 @@ const Artifacts = ({ paginationConfigArtifactVersionsRef, historyBackLink, 'artifacts', - params.id && getCloseDetailsLink(isAllVersions ? ALL_VERSIONS_PATH : tab || page, true), + params.id && getCloseDetailsLink(isAllVersions ? ALL_VERSIONS_PATH : tab || page, true, params.artifactName), isAllVersions ) const pageData = useMemo( diff --git a/src/components/Artifacts/ArtifactsTable.jsx b/src/components/Artifacts/ArtifactsTable.jsx index 7ca8ff0545..cdc5841631 100644 --- a/src/components/Artifacts/ArtifactsTable.jsx +++ b/src/components/Artifacts/ArtifactsTable.jsx @@ -79,6 +79,7 @@ let ArtifactsTable = ({ filtersConfig={filtersConfig} handleRefresh={handleRefreshArtifacts} setSearchParams={setSearchArtifactsParams} + selectedItemName={artifactName} tab={tab} withRefreshButton withoutExpandButton @@ -114,7 +115,11 @@ let ArtifactsTable = ({ applyDetailsChangesCallback={applyDetailsChangesCallback} detailsFormInitialValues={detailsFormInitialValues} getCloseDetailsLink={() => - getCloseDetailsLink(isAllVersions ? ALL_VERSIONS_PATH : tab || page) + getCloseDetailsLink( + isAllVersions ? ALL_VERSIONS_PATH : tab || page, + false, + artifactName + ) } handleCancel={() => setSelectedArtifact({})} pageData={pageData} @@ -139,6 +144,7 @@ let ArtifactsTable = ({ )} diff --git a/src/components/FunctionsPage/FunctionsView.jsx b/src/components/FunctionsPage/FunctionsView.jsx index 4c482b8084..0d86b6d5d8 100644 --- a/src/components/FunctionsPage/FunctionsView.jsx +++ b/src/components/FunctionsPage/FunctionsView.jsx @@ -105,6 +105,7 @@ const FunctionsView = ({ filtersConfig={functionsFiltersConfig} handleRefresh={handleRefreshFunctions} setSearchParams={setSearchFunctionsParams} + selectedItemName={params.funcName} withoutExpandButton > @@ -129,7 +130,7 @@ const FunctionsView = ({ - getCloseDetailsLink(isAllVersions ? ALL_VERSIONS_PATH : FUNCTIONS_PAGE_PATH) + getCloseDetailsLink(isAllVersions ? ALL_VERSIONS_PATH : FUNCTIONS_PAGE_PATH, false, params.funcName) } handleCancel={handleCancel} pageData={pageData} @@ -159,6 +160,7 @@ const FunctionsView = ({ )} diff --git a/src/utils/link-helper.util.js b/src/utils/link-helper.util.js index 9c711afa9a..79064f395a 100644 --- a/src/utils/link-helper.util.js +++ b/src/utils/link-helper.util.js @@ -41,18 +41,21 @@ export const isProjectValid = (navigate, projects, currentProjectName, dispatch) } } -export const getCloseDetailsLink = (paramName, ignoreOrigin) => { +export const getCloseDetailsLink = (paramName, ignoreOrigin, objectName) => { let pathname = window.location.pathname if (ignoreOrigin && pathname.startsWith(import.meta.env.VITE_PUBLIC_URL)) { pathname = pathname.slice(import.meta.env.VITE_PUBLIC_URL.length) } - const link = + let linkParts = pathname .split('/') .splice(0, pathname.split('/').lastIndexOf(paramName) + 1) - .join('/') + getFilteredSearchParams(window.location.search, [VIEW_SEARCH_PARAMETER]) + + if (objectName && paramName === objectName && linkParts[linkParts.length - 1] === objectName) linkParts.pop() + + const link = linkParts.join('/') + getFilteredSearchParams(window.location.search, [VIEW_SEARCH_PARAMETER]) return ignoreOrigin ? link : generateUrlFromRouterPath(link) } From 657c850527bdaa51df93d91ed257d303fd7f19cb Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:28:18 +0300 Subject: [PATCH 026/228] Fix [ProjectStatisticsCounter] Numbers Should not overflow the circle (#3303) --- src/elements/ProjectCard/projectCard.scss | 6 +-- .../ProjectStatisticsCounter.jsx | 38 +++++++++++++++++-- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/elements/ProjectCard/projectCard.scss b/src/elements/ProjectCard/projectCard.scss index 88eb500394..5c2915c839 100644 --- a/src/elements/ProjectCard/projectCard.scss +++ b/src/elements/ProjectCard/projectCard.scss @@ -152,10 +152,10 @@ display: flex; align-items: center; justify-content: center; - width: 65px; - height: 65px; + width: 70px; + height: 70px; margin-bottom: 5px; - font-size: 22px; + font-size: 16px; background-color: colors.$wildSand; border-radius: 50%; diff --git a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx index 443e9104bd..99e4057cff 100644 --- a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx +++ b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React from 'react' +import React, { useMemo } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' @@ -26,20 +26,45 @@ import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import Arrow from 'igz-controls/images/arrow.svg?react' const ProjectStatisticsCounter = ({ counterObject }) => { + const MAX_VISIBLE_COUNTER = 999999 const dataCardStatisticsValueClassNames = classnames( 'project-data-card__statistics-value', `statistics_${counterObject.className}`, typeof counterObject.value !== 'number' && 'project-data-card__statistics-value_not-available' ) + const generatedCountersContent = useMemo(() => { + const displayValue = counterObject.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + + if (Number(counterObject.value) < MAX_VISIBLE_COUNTER) { + return { + value: displayValue + } + } + + const truncatedValue = Math.floor(counterObject.value / 100000) / 10 + + return { + value: (truncatedValue % 1 === 0 ? Math.floor(truncatedValue) : truncatedValue) + 'M', + tooltip: ` (${displayValue})` + } + }, [counterObject.value]) + return counterObject.counterTooltip ? ( - } textShow> + + } + textShow + >
      {counterObject.loading ? ( ) : ( <> - {counterObject.value} + {generatedCountersContent.value} )} @@ -60,7 +85,12 @@ const ProjectStatisticsCounter = ({ counterObject }) => { ) : ( <> - {counterObject.value} + } + > + {generatedCountersContent.value} + )} From cf48ba602fee14b182cb7f312bf0e97b6d4fbca9 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:28:29 +0300 Subject: [PATCH 027/228] Fix [Application Metrics] Searching for a non-existent metric name crashes the UI (#3294) --- src/elements/MetricsSelector/MetricsSelector.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elements/MetricsSelector/MetricsSelector.jsx b/src/elements/MetricsSelector/MetricsSelector.jsx index 3b8ec6efd1..2ac8fdd30c 100644 --- a/src/elements/MetricsSelector/MetricsSelector.jsx +++ b/src/elements/MetricsSelector/MetricsSelector.jsx @@ -261,7 +261,7 @@ const MetricsSelector = ({ const renderMetrics = metricsList => { return (
        - {metricsList.metrics.map(metricItem => { + {metricsList?.metrics?.map(metricItem => { return ( {applicationName - ? renderMetrics(filteredMetrics[0] || []) + ? renderMetrics(filteredMetrics[0] || {}) : filteredMetrics.map(metricsGroup => { return !isEmpty(metricsGroup.metrics) ? ( Date: Thu, 19 Jun 2025 14:28:38 +0300 Subject: [PATCH 028/228] Fix [Documents] Error occurs on enter Documents page (#3288) --- src/components/Documents/Documents.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Documents/Documents.jsx b/src/components/Documents/Documents.jsx index ee749e6d9b..524209128d 100644 --- a/src/components/Documents/Documents.jsx +++ b/src/components/Documents/Documents.jsx @@ -52,7 +52,7 @@ const Documents = ({ isAllVersions = false }) => { isAllVersions={isAllVersions} page={DOCUMENTS_PAGE} removeArtifacts={removeDocuments} - storeArtifactTypeLoading={artifactsStore.documents.modelLoading} + storeArtifactTypeLoading={artifactsStore.documents.documentLoading} /> ) } From 2796c045244639b3fe33fd61d2e9587c511ab36f Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:08:37 +0300 Subject: [PATCH 029/228] Fix [Navbar] Navbar opens on attempt to expand last row (#3287) --- src/layout/Navbar/Navbar.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/layout/Navbar/Navbar.scss b/src/layout/Navbar/Navbar.scss index 408c356510..8d63e91673 100644 --- a/src/layout/Navbar/Navbar.scss +++ b/src/layout/Navbar/Navbar.scss @@ -47,6 +47,7 @@ &__additional { display: flex; flex: 2 0 auto; + overflow: hidden; .navbar-links { margin-bottom: 20px; From 6ce530b4d4b27c1596a796378cdf52448fc8ad19 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Sun, 22 Jun 2025 19:07:25 +0300 Subject: [PATCH 030/228] Impl [Feature Store] align the quick actions menu according to other pages (#3302) --- .../FeatureSets/FeatureSetsView.jsx | 1 + .../FeatureSets/featureSets.util.jsx | 11 +++++++++++ .../FeatureVectors/FeatureVectors.jsx | 4 ++-- .../FeatureVectors/FeatureVectorsView.jsx | 1 + .../FeatureVectors/featureVectors.util.jsx | 12 ++++++++++++ .../FeatureStoreTableRow.jsx | 12 +++++++++--- src/elements/ProjectJobs/projectJobs.utils.js | 2 +- src/utils/createFeatureStoreContent.jsx | 18 ------------------ 8 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/components/FeatureStore/FeatureSets/FeatureSetsView.jsx b/src/components/FeatureStore/FeatureSets/FeatureSetsView.jsx index 3b78f620fa..8609613980 100644 --- a/src/components/FeatureStore/FeatureSets/FeatureSetsView.jsx +++ b/src/components/FeatureStore/FeatureSets/FeatureSetsView.jsx @@ -132,6 +132,7 @@ const FeatureSetsView = React.forwardRef( selectedItem={selectedFeatureSet} selectedRowData={selectedRowData} toggleRow={toggleRow} + withQuickActions={true} /> ) )} diff --git a/src/components/FeatureStore/FeatureSets/featureSets.util.jsx b/src/components/FeatureStore/FeatureSets/featureSets.util.jsx index 53d6ba26e0..891661a938 100644 --- a/src/components/FeatureStore/FeatureSets/featureSets.util.jsx +++ b/src/components/FeatureStore/FeatureSets/featureSets.util.jsx @@ -29,8 +29,11 @@ import { TAG_FILTER_LATEST } from '../../../constants' import { showErrorNotification } from 'igz-controls/utils/notification.util' +import { copyToClipboard } from '../../../utils/copyToClipboard' +import { generateUri } from '../../../utils/resources' import { fetchFeatureSet } from '../../../reducers/featureStoreReducer' +import Copy from 'igz-controls/images/copy-to-clipboard-icon.svg?react' import Yaml from 'igz-controls/images/yaml.svg?react' export const generateFeatureSetsDetailsMenu = (selectedItem) => [ @@ -104,6 +107,14 @@ export const generateActionsMenu = (dispatch, selectedFeatureSet, toggleConverte toggleConvertedYaml ) } + ], + [ + { + label: 'Copy URI', + icon: , + onClick: featureSet => + copyToClipboard(generateUri(featureSet, null, FEATURE_SETS_TAB), dispatch) + } ] ] diff --git a/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx b/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx index 4cb9aa7cbc..495feb9dae 100644 --- a/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx +++ b/src/components/FeatureStore/FeatureVectors/FeatureVectors.jsx @@ -247,8 +247,8 @@ const FeatureVectors = () => { ) const actionsMenu = useMemo( - () => generateActionsMenu(onDeleteFeatureVector, toggleConvertedYaml), - [onDeleteFeatureVector, toggleConvertedYaml] + () => generateActionsMenu(dispatch, onDeleteFeatureVector, toggleConvertedYaml), + [onDeleteFeatureVector, toggleConvertedYaml, dispatch] ) const handleRefresh = useCallback( diff --git a/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.jsx b/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.jsx index 0bfe8edb0c..127a5cbf8e 100644 --- a/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.jsx +++ b/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.jsx @@ -124,6 +124,7 @@ const FeatureVectorsView = React.forwardRef( selectedItem={selectedFeatureVector} selectedRowData={selectedRowData} toggleRow={toggleRow} + withQuickActions={true} /> ) )} diff --git a/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx b/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx index b17f519d11..210ace0b85 100644 --- a/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx +++ b/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx @@ -29,9 +29,12 @@ import { } from '../../../constants' import { parseFeatureTemplate } from '../../../utils/parseFeatureTemplate' import { parseChipsData } from '../../../utils/convertChipsData' +import { copyToClipboard } from '../../../utils/copyToClipboard' +import { generateUri } from '../../../utils/resources' import Delete from 'igz-controls/images/delete.svg?react' import Yaml from 'igz-controls/images/yaml.svg?react' +import Copy from 'igz-controls/images/copy-to-clipboard-icon.svg?react' export const generateFeatureVectorsDetailsMenu = (selectedItem) => [ { @@ -94,6 +97,7 @@ export const generatePageData = (selectedFeatureSet) => { } export const generateActionsMenu = ( + dispatch, onDeleteFeatureVector, toggleConvertedYaml, isDetailsPopUp = false @@ -112,6 +116,14 @@ export const generateActionsMenu = ( onClick: onDeleteFeatureVector, allowLeaveWarning: true } + ], + [ + { + label: 'Copy URI', + icon: , + onClick: featureSet => + copyToClipboard(generateUri(featureSet, null, FEATURE_VECTORS_TAB), dispatch) + } ] ] diff --git a/src/elements/FeatureStoreTableRow/FeatureStoreTableRow.jsx b/src/elements/FeatureStoreTableRow/FeatureStoreTableRow.jsx index 7774004574..cc89ed58d9 100644 --- a/src/elements/FeatureStoreTableRow/FeatureStoreTableRow.jsx +++ b/src/elements/FeatureStoreTableRow/FeatureStoreTableRow.jsx @@ -42,7 +42,8 @@ const FeatureStoreTableRow = ({ rowItem, selectedItem = {}, selectedRowData, - toggleRow = () => {} + toggleRow = () => {}, + withQuickActions = false }) => { const parent = useRef() const params = useParams() @@ -199,7 +200,11 @@ const FeatureStoreTableRow = ({ })} {!hideActionsMenu && (
      )} @@ -218,7 +223,8 @@ FeatureStoreTableRow.propTypes = { rowItem: PropTypes.object.isRequired, selectedItem: PropTypes.object, selectedRowData: PropTypes.object.isRequired, - toggleRow: PropTypes.func + toggleRow: PropTypes.func, + withQuickActions: PropTypes.bool } export default React.memo(FeatureStoreTableRow) diff --git a/src/elements/ProjectJobs/projectJobs.utils.js b/src/elements/ProjectJobs/projectJobs.utils.js index 5d1914947f..9d02b40632 100644 --- a/src/elements/ProjectJobs/projectJobs.utils.js +++ b/src/elements/ProjectJobs/projectJobs.utils.js @@ -20,7 +20,7 @@ such restriction. import { orderBy } from 'lodash' import { measureTime } from '../../utils/measureTime' -import { MONITOR_JOBS_TAB, MONITOR_WORKFLOWS_TAB, SCHEDULE_TAB } from '../../constants' +import { MONITOR_JOBS_TAB } from '../../constants' import { formatDatetime } from 'igz-controls/utils/datetime.util' import { typesOfJob } from '../../utils/jobs.util' diff --git a/src/utils/createFeatureStoreContent.jsx b/src/utils/createFeatureStoreContent.jsx index 30090aef3c..2ad61c1b5b 100644 --- a/src/utils/createFeatureStoreContent.jsx +++ b/src/utils/createFeatureStoreContent.jsx @@ -28,10 +28,8 @@ import { FEATURE_SETS_TAB, FEATURE_VECTORS_TAB } from '../constants' -import { BUTTON_COPY_URI_CELL_TYPE } from 'igz-controls/constants' import { formatDatetime } from 'igz-controls/utils/datetime.util' import { generateLinkToDetailsPanel } from './link-helper.util' -import { generateUri } from './resources' import { openPopUp } from 'igz-controls/utils/common.util' import { parseKeyValues } from './object' import { truncateUid } from 'igz-controls/utils/string.util' @@ -126,14 +124,6 @@ export const createFeatureSetsRowData = (featureSet, project, pageTab, showExpan headerLabel: 'Updated', value: featureSet.updated ? formatDatetime(featureSet.updated, 'N/A') : 'N/A', className: 'table-cell-2' - }, - { - id: `buttonCopy.${featureSet.ui.identifierUnique}`, - headerId: 'copy', - value: '', - className: 'table-cell-icon', - type: BUTTON_COPY_URI_CELL_TYPE, - actionHandler: item => generateUri(item, null, pageTab) } ] } @@ -344,14 +334,6 @@ export const createFeatureVectorsRowData = (featureVector, pageTab, project, sho showTag: true, showStatus: true }, - { - id: `buttonCopy.${featureVector.ui.identifierUnique}`, - headerId: 'copy', - value: '', - className: 'table-cell-icon', - type: BUTTON_COPY_URI_CELL_TYPE, - actionHandler: item => generateUri(item, null, pageTab) - }, { id: `uid.${featureVector.ui.identifierUnique}`, headerId: 'featurevectoruid', From de050599457cfb5cad1498a4e562c7ee9de66d6b Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Sun, 22 Jun 2025 19:19:14 +0300 Subject: [PATCH 031/228] Bump DRC version ;3.1.1; (#3307) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e81320a051..1fa3a536df 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.0", + "iguazio.dashboard-react-controls": "3.1.1", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", From 23dad4bf9ade9ebef4e0499f949c3b9eac80acc8 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Sun, 22 Jun 2025 19:19:42 +0300 Subject: [PATCH 032/228] Impl [LLM Prompt artifact] Align with UI with BE (#3306) --- src/api/artifacts-api.js | 128 +----------------- .../SearchNavigator/SearchNavigator.jsx | 50 +++---- .../SearchNavigator/searchNavigator.util.jsx | 80 +++++++++++ .../DetailsGenerationConfiguration.jsx | 46 +++++++ .../detailsGenerationConfiguration.scss | 21 +++ .../DetailsPromptTemplate/ArgumentsTab.jsx | 67 +++++++++ .../DetailsPromptTemplate.jsx | 48 ++++++- .../DetailsPromptTemplate/PromptTab.jsx | 99 +++++++++----- .../detailsPromptTemplate.scss | 37 ++++- .../DetailsTabsContent/DetailsTabsContent.jsx | 8 +- src/components/Details/details.util.js | 4 +- src/constants.js | 1 + .../TableModelCell/TableModelCell.jsx | 68 ++++++++++ src/utils/createArtifactsContent.jsx | 16 +++ 14 files changed, 478 insertions(+), 195 deletions(-) create mode 100644 src/common/SearchNavigator/searchNavigator.util.jsx create mode 100644 src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx create mode 100644 src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss create mode 100644 src/components/Details/DetailsPromptTemplate/ArgumentsTab.jsx create mode 100644 src/elements/TableModelCell/TableModelCell.jsx diff --git a/src/api/artifacts-api.js b/src/api/artifacts-api.js index 11b0742399..8b221e1893 100644 --- a/src/api/artifacts-api.js +++ b/src/api/artifacts-api.js @@ -23,7 +23,7 @@ import { ARTIFACT_OTHER_TYPE, DATASET_TYPE, DOCUMENT_TYPE, - // LLM_PROMPT_TYPE, + LLM_PROMPT_TYPE, MODEL_TYPE, SHOW_ITERATIONS, TAG_FILTER_ALL_ITEMS, @@ -157,34 +157,6 @@ const artifactsApi = { newConfig.params.iter = iter } - // return Promise.resolve({ - // data: { - // kind: 'dataset', - // metadata: { - // key: 'test3', - // project: 'default', - // tree: '3c9a5fe2-1ffc-4c4c-864b-a712a8899fe0', - // description: '', - // iter: null, - // uid: 'c4dc3113a581a11ed69ef09258fdc0584d590f74', - // updated: '2025-05-06 08:50:01.714000+00:00', - // created: '2025-05-06 08:50:01.714000+00:00', - // tag: 'latest' - // }, - // spec: { - // target_path: 'v3io:///asd/asd', - // producer: { - // kind: 'api', - // name: 'UI', - // uri: 'dashboard.default-tenant.app.vmdev63.lab.iguazeng.com' - // }, - // db_key: 'test3' - // }, - // status: {}, - // project: 'default' - // } - // }) - return mainHttpClientV2.get(`/projects/${projectName}/artifacts/${artifactName}`, newConfig) }, getArtifacts: (project, filters, config, withExactName) => { @@ -214,99 +186,13 @@ const artifactsApi = { return fetchArtifacts(project, filters, newConfig, true) }, - getLLMPrompts: () => { - // const newConfig = { - // ...config, - // params: { ...config.params, category: LLM_PROMPT_TYPE } - // } + getLLMPrompts: (project, filters, config = {}) => { + const newConfig = { + ...config, + params: { ...config.params, category: LLM_PROMPT_TYPE } + } - // return fetchArtifacts(project, filters, newConfig, true) - return Promise.resolve({ - data: { - artifacts: [ - { - kind: 'dataset', - metadata: { - key: 'test3', - project: 'default', - tree: '3c9a5fe2-1ffc-4c4c-864b-a712a8899fe0', - description: '', - iter: null, - uid: 'c4dc3113a581a11ed69ef09258fdc0584d590f74', - updated: '2025-05-06 08:50:01.714000+00:00', - created: '2025-05-06 08:50:01.714000+00:00', - tag: 'latest' - }, - status: {}, - project: 'default', - spec: { - producer: { - kind: 'api', - name: 'UI', - uri: 'dashboard.default-tenant.app.vmdev63.lab.iguazeng.com' - }, - db_key: 'test3', - target_path: 'v3io:///asd/asd' - } - }, - { - kind: 'dataset', - metadata: { - key: 'test2', - project: 'default', - tree: '31fc16e0-ce4d-4076-baf3-53e29553bf44', - description: '', - iter: null, - uid: '28ac191a940dcada5f2c09117416db06c21f0b4a', - updated: '2025-05-06 08:49:15.869000+00:00', - created: '2025-05-06 08:49:15.869000+00:00', - tag: 'latest' - }, - status: {}, - project: 'default', - spec: { - producer: { - kind: 'api', - name: 'UI', - uri: 'dashboard.default-tenant.app.vmdev63.lab.iguazeng.com' - }, - db_key: 'test2', - target_path: 'v3io:///hj/b' - } - }, - { - kind: 'dataset', - metadata: { - key: 'test', - project: 'default', - tree: '10b8405b-366b-428f-a84a-ac1e3caf52e1', - description: '', - iter: null, - uid: '7ef62fca9189261fa2443bd3fd0ebef5f03f182d', - updated: '2025-04-24 09:53:08.584000+00:00', - created: '2025-04-24 09:53:08.584000+00:00', - tag: 'latest' - }, - status: {}, - project: 'default', - spec: { - producer: { - kind: 'api', - name: 'UI', - uri: 'localhost:3000' - }, - db_key: 'test', - target_path: 's3://dfg/fg' - } - } - ], - pagination: { - page: 1, - 'page-size': 1000, - 'page-token': null - } - } - }) + return fetchArtifacts(project, filters, newConfig, true) }, getModels: (project, filters, config = {}) => { const newConfig = { diff --git a/src/common/SearchNavigator/SearchNavigator.jsx b/src/common/SearchNavigator/SearchNavigator.jsx index 8fbd976a20..9af94d3597 100644 --- a/src/common/SearchNavigator/SearchNavigator.jsx +++ b/src/common/SearchNavigator/SearchNavigator.jsx @@ -17,19 +17,21 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { useCallback, useEffect, useState } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import Search from '../Search/Search' import { RoundedIcon } from 'igz-controls/components' +import { highlightMatches } from './searchNavigator.util' + import Arrow from 'igz-controls/images/arrow.svg?react' import Close from 'igz-controls/images/close.svg?react' import './searchNavigator.scss' -const SearchNavigator = ({ promptTemplate, setSearchResult }) => { +const SearchNavigator = ({ promptTemplate, rawPromptString, setSearchResult }) => { const [matchCount, setMatchCount] = useState(0) const [activeMatchIndex, setActiveMatchIndex] = useState(0) const [matches, setMatches] = useState([]) @@ -53,62 +55,45 @@ const SearchNavigator = ({ promptTemplate, setSearchResult }) => { return clearResults() } - const regex = new RegExp(value, 'gi') - const allMatches = [...promptTemplate.matchAll(regex)] - const count = allMatches.length - let index = 0 - - const highlighted = promptTemplate.replace(regex, match => { - const marker = `${match}` - - index++ - - return marker - }) + const regex = new RegExp(`(${value})`, 'gi') + const allMatches = [...rawPromptString.matchAll(regex)] + const highlighted = highlightMatches(promptTemplate, regex, 0) setSearchResult(highlighted) - setMatchCount(count) + setMatchCount(allMatches.length) setMatches(allMatches) setActiveMatchIndex(0) setSearchValue(value) }, - [clearResults, promptTemplate, setSearchResult] + [clearResults, rawPromptString, promptTemplate, setSearchResult] ) const highlightMatch = useCallback( index => { if (!matches.length) return - const regex = new RegExp(promptTemplate.match(matches[0])[0], 'gi') - let current = 0 - - const highlighted = promptTemplate.replace(regex, match => { - const marker = `${match}` - - current++ - - return marker - }) + const regex = new RegExp(`(${searchValue})`, 'gi') + const highlighted = highlightMatches(promptTemplate, regex, index) setSearchResult(highlighted) setActiveMatchIndex(index) }, - [matches, promptTemplate, setSearchResult] + [matches, promptTemplate, searchValue, setSearchResult] ) const goToPrevMatch = () => { if (!matches.length) return + const prevIndex = (activeMatchIndex - 1 + matchCount) % matchCount + highlightMatch(prevIndex) } const goToNextMatch = () => { if (!matches.length) return + const nextIndex = (activeMatchIndex + 1) % matchCount + highlightMatch(nextIndex) } @@ -164,7 +149,8 @@ const SearchNavigator = ({ promptTemplate, setSearchResult }) => { } SearchNavigator.propTypes = { - promptTemplate: PropTypes.string.isRequired, + promptTemplate: PropTypes.array.isRequired, + rawPromptString: PropTypes.string.isRequired, setSearchResult: PropTypes.func.isRequired } diff --git a/src/common/SearchNavigator/searchNavigator.util.jsx b/src/common/SearchNavigator/searchNavigator.util.jsx new file mode 100644 index 0000000000..2131bcaf58 --- /dev/null +++ b/src/common/SearchNavigator/searchNavigator.util.jsx @@ -0,0 +1,80 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React from 'react' + +export function highlightMatches(template, regex, activeIndex = 0) { + let current = 0 + + const processText = (text, keyPrefix = '') => { + const parts = text.split(regex) + + return parts.map((part, index) => { + if (index % 2 === 1) { + const isActive = current === activeIndex + const highlighted = ( + + {part} + + ) + + current++ + + return highlighted + } + + return part + }) + } + + const processElement = (element, keyPrefix = '') => { + if (typeof element === 'string') { + return processText(element, keyPrefix) + } + + if (React.isValidElement(element)) { + const children = element.props.children + + let newChildren + + if (typeof children === 'string') { + newChildren = processText(children, `${keyPrefix}-str`) + } else if (Array.isArray(children)) { + newChildren = children.map((child, index) => processElement(child, `${keyPrefix}-${index}`)) + } else if (React.isValidElement(children)) { + newChildren = processElement(children, `${keyPrefix}-child`) + } else { + newChildren = children + } + + return React.cloneElement(element, { key: keyPrefix }, newChildren) + } + + return element + } + + return template.map((el, index) => processElement(el, `root-${index}`)) +} diff --git a/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx b/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx new file mode 100644 index 0000000000..c05e9386fb --- /dev/null +++ b/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx @@ -0,0 +1,46 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React from 'react' +import PropTypes from 'prop-types' +import { isEmpty } from 'lodash' + +import NoData from '../../../common/NoData/NoData' + +const DetailsGenerationConfiguration = ({ selectedItem }) => { + return ( +
      + {Object.entries(selectedItem.generation_configuration || {}).map(([key, value]) => { + return ( +
      +
      {key}
      +
      {value}
      +
      + ) + })} + {isEmpty(selectedItem.generation_configuration) && } +
      + ) +} + +DetailsGenerationConfiguration.propTypes = { + selectedItem: PropTypes.object.isRequired +} + +export default DetailsGenerationConfiguration diff --git a/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss b/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss new file mode 100644 index 0000000000..52cf710dfb --- /dev/null +++ b/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss @@ -0,0 +1,21 @@ +@use 'igz-controls/scss/borders'; +@use 'igz-controls/scss/colors'; + +.generation-configuration-tab { + &__row { + display: flex; + padding: 10px 0; + font-size: 15px; + line-height: 20px; + border-bottom: borders.$secondaryBorder; + + &-key { + min-width: 150px; + font-weight: 500; + } + + &-value { + color: colors.$topaz; + } + } +} \ No newline at end of file diff --git a/src/components/Details/DetailsPromptTemplate/ArgumentsTab.jsx b/src/components/Details/DetailsPromptTemplate/ArgumentsTab.jsx new file mode 100644 index 0000000000..3b23d852f7 --- /dev/null +++ b/src/components/Details/DetailsPromptTemplate/ArgumentsTab.jsx @@ -0,0 +1,67 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React from 'react' +import PropTypes from 'prop-types' +import classNames from 'classnames' +import { isEmpty } from 'lodash' + +import ContentMenu from '../../../elements/ContentMenu/ContentMenu' +import NoData from '../../../common/NoData/NoData' + +const ArgumentsTab = ({ + handleTabChange, + selectedArgument = {}, + selectedItem, + selectedTab, + tabs +}) => { + return ( +
      +
      + +
      + {selectedItem.prompt_legend?.map(legend => { + const rowClassNames = classNames( + 'arguments-tab__row', + selectedArgument.field + selectedArgument.description === + legend.field + legend.description && 'arguments-tab__row_selected' + ) + + return ( +
      +
      {legend.field}
      +
      {legend.description}
      +
      + ) + })} + {isEmpty(selectedItem.prompt_legend) && } +
      + ) +} + +ArgumentsTab.propTypes = { + handleTabChange: PropTypes.func.isRequired, + selectedArgument: PropTypes.object, + selectedItem: PropTypes.object.isRequired, + selectedTab: PropTypes.string.isRequired, + tabs: PropTypes.array.isRequired +} + +export default ArgumentsTab diff --git a/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx b/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx index 3881824ea8..04d6e0d7c4 100644 --- a/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx +++ b/src/components/Details/DetailsPromptTemplate/DetailsPromptTemplate.jsx @@ -1,13 +1,35 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ import { useCallback, useState } from 'react' +import PropTypes from 'prop-types' import PromptTab from './PromptTab' +import ArgumentsTab from './ArgumentsTab' import { ARGUMENTS_TAB, PROMPT_TAB } from '../../../constants' import './detailsPromptTemplate.scss' -const DetailsPromptTemplate = () => { +const DetailsPromptTemplate = ({ selectedItem }) => { const [selectedTab, setSelectedTab] = useState(PROMPT_TAB) + const [selectedArgument, setSelectedArgument] = useState({}) const tabs = [ { id: PROMPT_TAB, label: 'Prompt' }, { id: ARGUMENTS_TAB, label: 'Arguments' } @@ -15,15 +37,35 @@ const DetailsPromptTemplate = () => { const handleTabChange = useCallback(tabName => { setSelectedTab(tabName) + setSelectedArgument({}) }, []) return (
      {selectedTab === PROMPT_TAB ? ( - - ) : null} + + ) : ( + + )}
      ) } +DetailsPromptTemplate.propTypes = { + selectedItem: PropTypes.object.isRequired +} + export default DetailsPromptTemplate diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx index bd8c739130..e03323716a 100644 --- a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -17,51 +17,84 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { useState } from 'react' +import { useEffect, useState } from 'react' import PropTypes from 'prop-types' +import { isEmpty } from 'lodash' -import { CopyToClipboard } from 'igz-controls/components' +import { CopyToClipboard,Tooltip, TextTooltipTemplate } from 'igz-controls/components' import ContentMenu from '../../../elements/ContentMenu/ContentMenu' import SearchNavigator from '../../../common/SearchNavigator/SearchNavigator' +import { ARGUMENTS_TAB } from '../../../constants' + import Copy from 'igz-controls/images/copy-to-clipboard-icon.svg?react' -const PromptTab = ({ handleTabChange, selectedTab, tabs }) => { - const [promptTemplate] = useState( - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.\n' + - '\n' + - 'Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.' - ) +const PromptTab = ({ + handleTabChange, + selectedItem, + selectedTab, + setSelectedArgument, + setSelectedTab, + tabs +}) => { + const [promptTemplate, setPromptTemplate] = useState([]) const [searchResult, setSearchResult] = useState('') + const [rawPromptString, setRawPromptString] = useState('') + + useEffect(() => { + if (!isEmpty(selectedItem.prompt_string) && !isEmpty(selectedItem.prompt_legend)) { + const legendMap = Object.fromEntries( + selectedItem.prompt_legend.map(({ field, description }) => [field, description]) + ) + + const regex = new RegExp( + `\\b(${selectedItem.prompt_legend.map(l => l.field).join('|')})\\b`, + 'g' + ) + + const jsxContent = selectedItem.prompt_string.split(regex).map((part, index) => { + if (legendMap[part]) { + const currentArgument = selectedItem.prompt_legend.find(legend => legend.field === part) + + return ( + } textShow> + { + setSelectedArgument(currentArgument) + setSelectedTab(ARGUMENTS_TAB) + }} + > + {`{${part}}`} + + + ) + } + + return part + }) - const createMarkup = html => { - return { __html: html } - } + setPromptTemplate(jsxContent) + setRawPromptString(selectedItem.prompt_string) + } else if (!isEmpty(selectedItem.prompt_string)) { + setPromptTemplate([selectedItem.prompt_string]) + setRawPromptString(selectedItem.prompt_string) + } + }, [selectedItem.prompt_string, selectedItem.prompt_legend, setSelectedArgument, setSelectedTab]) return (
      - + @@ -70,10 +103,7 @@ const PromptTab = ({ handleTabChange, selectedTab, tabs }) => {
      -
      +
      {searchResult || promptTemplate}
      ) } @@ -81,6 +111,9 @@ const PromptTab = ({ handleTabChange, selectedTab, tabs }) => { PromptTab.propTypes = { handleTabChange: PropTypes.func.isRequired, selectedTab: PropTypes.string.isRequired, + selectedItem: PropTypes.object.isRequired, + setSelectedArgument: PropTypes.func.isRequired, + setSelectedTab: PropTypes.func.isRequired, tabs: PropTypes.array.isRequired } diff --git a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss index f882c18c44..b3f55221ed 100644 --- a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss +++ b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss @@ -1,4 +1,5 @@ @use 'igz-controls/scss/borders'; +@use 'igz-controls/scss/colors'; .prompt-template { .prompt-tab { @@ -13,9 +14,13 @@ &__template { max-height: 425px; padding: 25px 15px; - overflow-y: scroll; + overflow-y: auto; border: borders.$primaryBorder; border-radius: 4px; + + .tooltip-wrapper { + display: inline; + } } &__copy-btn { @@ -39,4 +44,34 @@ } } } + + .arguments-tab { + &__header { + display: flex; + align-items: center; + margin-top: 20px; + padding-bottom: 10px; + } + + &__row { + display: flex; + padding: 10px 0; + font-size: 15px; + line-height: 20px; + border-bottom: borders.$secondaryBorder; + + &_selected { + background-color: colors.$ghostWhite; + } + + &-key { + min-width: 150px; + font-weight: 500; + } + + &-value { + color: colors.$topaz; + } + } + } } \ No newline at end of file diff --git a/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx b/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx index 91dea08197..e29953bf9d 100644 --- a/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx +++ b/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx @@ -30,14 +30,15 @@ import DetailsCollections from '../../DetailsCollections/DetailsCollections' import DetailsDriftAnalysis from '../../DetailsDriftAnalysis/DetailsDriftAnalysis' import DetailsDrillDownAlert from '../../DetailsDrillDownAlert/DetailsDrillDownAlert' import DetailsFeatureAnalysis from '../../DetailsFeaturesAnalysis/DetailsFeaturesAnalysis' +import DetailsGenerationConfiguration from '../DetailsGenerationConfiguration/DetailsGenerationConfiguration' import DetailsInfo from '../../DetailsInfo/DetailsInfo' import DetailsInputs from '../../DetailsInputs/DetailsInputs' import DetailsLogs from '../../DetailsLogs/DetailsLogs' import DetailsMetadata from '../../DetailsMetadata/DetailsMetadata' import DetailsMetrics from '../../DetailsMetrics/DetailsMetrics' import DetailsPods from '../../DetailsPods/DetailsPods' -import DetailsPreview from '../../DetailsPreview/DetailsPreview' import DetailsPromptTemplate from '../DetailsPromptTemplate/DetailsPromptTemplate' +import DetailsPreview from '../../DetailsPreview/DetailsPreview' import DetailsRequestedFeatures from '../../DetailsRequestedFeatures/DetailsRequestedFeatures' import DetailsResults from '../../DetailsResults/DetailsResults' import DetailsStatistics from '../../DetailsStatistics/DetailsStatistics' @@ -55,6 +56,7 @@ import { DETAILS_DRIFT_ANALYSIS_TAB, DETAILS_FEATURES_ANALYSIS_TAB, DETAILS_FEATURES_TAB, + DETAILS_GENERATION_CONFIGURATION_TAB, DETAILS_INPUTS_TAB, DETAILS_LOGS_TAB, DETAILS_METADATA_TAB, @@ -239,7 +241,9 @@ const DetailsTabsContent = ({ case DETAILS_COLLECTIONS_TAB: return case DETAILS_PROMPT_TEMPLATE_TAB: - return + return + case DETAILS_GENERATION_CONFIGURATION_TAB: + return default: return null } diff --git a/src/components/Details/details.util.js b/src/components/Details/details.util.js index 0d2f37bbd7..8f07067c70 100644 --- a/src/components/Details/details.util.js +++ b/src/components/Details/details.util.js @@ -160,9 +160,7 @@ export const generateArtifactsContent = ( }, kind: { value: - detailsType !== FEATURE_STORE_PAGE && - detailsType !== FILES_PAGE && - detailsType !== DATASETS_PAGE + detailsType !== FILES_PAGE && detailsType !== DATASETS_PAGE ? selectedItem.kind || ' ' : null }, diff --git a/src/constants.js b/src/constants.js index c53108b6b3..1fe2eb71cf 100644 --- a/src/constants.js +++ b/src/constants.js @@ -311,6 +311,7 @@ export const DETAILS_RETURNED_FEATURES_TAB = 'returned-features' export const DETAILS_STATISTICS_TAB = 'statistics' export const DETAILS_TRANSFORMATIONS_TAB = 'transformations' export const DETAILS_PROMPT_TEMPLATE_TAB = 'prompt-template' +export const DETAILS_GENERATION_CONFIGURATION_TAB = 'generation-configuration' export const FETCH_MODEL_FEATURE_VECTOR_BEGIN = 'FETCH_MODEL_FEATURE_VECTOR_BEGIN' export const FETCH_MODEL_FEATURE_VECTOR_FAILURE = 'FETCH_MODEL_FEATURE_VECTOR_FAILURE' export const FETCH_MODEL_FEATURE_VECTOR_SUCCESS = 'FETCH_MODEL_FEATURE_VECTOR_SUCCESS' diff --git a/src/elements/TableModelCell/TableModelCell.jsx b/src/elements/TableModelCell/TableModelCell.jsx new file mode 100644 index 0000000000..fe5e30ef83 --- /dev/null +++ b/src/elements/TableModelCell/TableModelCell.jsx @@ -0,0 +1,68 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React, { useCallback, useMemo } from 'react' +import classnames from 'classnames' +import PropTypes from 'prop-types' + +import { TextTooltipTemplate, Tooltip } from 'igz-controls/components' +import ArtifactPopUp from '../DetailsPopUp/ArtifactPopUp/ArtifactPopUp' + +import { openPopUp } from 'igz-controls/utils/common.util' +import { parseUri } from '../../utils' + +const TableModelCell = ({ id, modelUri, bodyCellClassName = '' }) => { + const cellClassNames = classnames('table-body__cell', bodyCellClassName) + const parsedUri = useMemo(() => { + return parseUri(modelUri) + }, [modelUri]) + + const handleOpenArtifactPopUp = useCallback(() => { + openPopUp(ArtifactPopUp, { + artifactData: parsedUri + }) + }, [parsedUri]) + + return ( + modelUri && ( + + ) + ) +} + +TableModelCell.propTypes = { + id: PropTypes.string.isRequired, + modelUri: PropTypes.string.isRequired, + bodyCellClassName: PropTypes.string +} + +export default TableModelCell diff --git a/src/utils/createArtifactsContent.jsx b/src/utils/createArtifactsContent.jsx index c8fd866210..128a05c205 100644 --- a/src/utils/createArtifactsContent.jsx +++ b/src/utils/createArtifactsContent.jsx @@ -43,6 +43,7 @@ import { validateArguments } from './validateArguments' import SeverityOk from 'igz-controls/images/severity-ok.svg?react' import SeverityWarning from 'igz-controls/images/severity-warning.svg?react' import SeverityError from 'igz-controls/images/severity-error.svg?react' +import TableModelCell from '../elements/TableModelCell/TableModelCell' export const createArtifactsContent = (artifacts, page, pageTab, project, isAllVersions) => { return (artifacts.filter(artifact => !artifact.link_iteration) ?? []).map(artifact => { @@ -641,6 +642,21 @@ export const createLLMPromptsRowData = (artifact, project, isAllVersions) => { showSelectedUid: true, showUpdatedDate: true }, + { + id: `model.${artifact.ui.identifierUnique}`, + headerId: 'modelName', + headerLabel: 'Model name', + value: artifact.parent_uri || '', + template: ( + + ), + className: 'table-cell-1', + type: 'modelName' + }, { id: `labels.${artifact.ui.identifierUnique}`, headerId: 'labels', From 3862aa9ef7620cc0dc81fa421506d4c707b9021d Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Sun, 22 Jun 2025 19:36:49 +0300 Subject: [PATCH 033/228] Impl [LLM Prompt Artifact] Add model filter (#3298) --- src/api/artifacts-api.js | 6 ++ src/components/Artifacts/Artifacts.jsx | 7 +- src/components/Artifacts/ArtifactsTable.jsx | 6 +- src/components/Artifacts/artifacts.util.js | 2 +- .../ArtifactsActionBar/ArtifactsFilters.jsx | 65 ++++++++++++++++--- src/components/LLMPrompts/LLMPrompts.jsx | 8 ++- src/components/LLMPrompts/llmPrompts.util.jsx | 44 +++++++++++-- src/constants.js | 2 + 8 files changed, 123 insertions(+), 17 deletions(-) diff --git a/src/api/artifacts-api.js b/src/api/artifacts-api.js index 8b221e1893..4e2c1887e3 100644 --- a/src/api/artifacts-api.js +++ b/src/api/artifacts-api.js @@ -24,6 +24,8 @@ import { DATASET_TYPE, DOCUMENT_TYPE, LLM_PROMPT_TYPE, + MODEL_NAME_FILTER, + MODEL_TAG_FILTER, MODEL_TYPE, SHOW_ITERATIONS, TAG_FILTER_ALL_ITEMS, @@ -56,6 +58,10 @@ const fetchArtifacts = (project, filters, config = {}, withLatestTag, withExactN params.tree = filters.tree } + if (filters?.[MODEL_NAME_FILTER]) { + params.parent = `${filters[MODEL_NAME_FILTER]}:${filters[MODEL_TAG_FILTER] || '*'}` + } + return mainHttpClientV2.get(`/projects/${project}/artifacts`, { ...config, params: { ...config.params, ...params } diff --git a/src/components/Artifacts/Artifacts.jsx b/src/components/Artifacts/Artifacts.jsx index 5c14cf45c4..2d4f6b89e1 100644 --- a/src/components/Artifacts/Artifacts.jsx +++ b/src/components/Artifacts/Artifacts.jsx @@ -64,6 +64,7 @@ const Artifacts = ({ generateActionsMenu, generateDetailsFormInitialValues, generatePageData, + getArtifactFiltersConfig = null, handleApplyDetailsChanges, handleDeployArtifactFailure = null, isAllVersions = false, @@ -100,7 +101,10 @@ const Artifacts = ({ `/projects/${params.projectName}/${page}${tab ? `/${tab}` : ''}${getSavedSearchParams(location.search)}`, [location.search, page, params.projectName, tab] ) - const filtersConfig = useMemo(() => getFiltersConfig(isAllVersions), [isAllVersions]) + const filtersConfig = useMemo( + () => (getArtifactFiltersConfig || getFiltersConfig)(isAllVersions), + [getArtifactFiltersConfig, isAllVersions] + ) const artifactsFilters = useFiltersFromSearchParams(filtersConfig) const [refreshAfterDeleteCallback, refreshAfterDeleteTrigger] = useRefreshAfterDelete( paginationConfigArtifactVersionsRef, @@ -561,6 +565,7 @@ Artifacts.propTypes = { generateActionsMenu: PropTypes.func.isRequired, generateDetailsFormInitialValues: PropTypes.func.isRequired, generatePageData: PropTypes.func.isRequired, + getArtifactFiltersConfig: PropTypes.func, handleApplyDetailsChanges: PropTypes.func.isRequired, handleDeployArtifactFailure: PropTypes.func, isAllVersions: PropTypes.bool, diff --git a/src/components/Artifacts/ArtifactsTable.jsx b/src/components/Artifacts/ArtifactsTable.jsx index cdc5841631..d4c5005e1f 100644 --- a/src/components/Artifacts/ArtifactsTable.jsx +++ b/src/components/Artifacts/ArtifactsTable.jsx @@ -84,7 +84,11 @@ let ArtifactsTable = ({ withRefreshButton withoutExpandButton > - + {isAllVersions && diff --git a/src/components/Artifacts/artifacts.util.js b/src/components/Artifacts/artifacts.util.js index d147343d62..79e58a65a3 100644 --- a/src/components/Artifacts/artifacts.util.js +++ b/src/components/Artifacts/artifacts.util.js @@ -36,7 +36,7 @@ export const getFiltersConfig = isAllVersions => ({ }, [LABELS_FILTER]: { label: 'Labels:', initialValue: '', isModal: true }, [ITERATIONS_FILTER]: { - label: 'Show best iteration only:', + label: 'Show best iteration only', initialValue: isAllVersions ? '' : SHOW_ITERATIONS, isModal: true } diff --git a/src/components/ArtifactsActionBar/ArtifactsFilters.jsx b/src/components/ArtifactsActionBar/ArtifactsFilters.jsx index e9599c2fd4..e9aa001817 100644 --- a/src/components/ArtifactsActionBar/ArtifactsFilters.jsx +++ b/src/components/ArtifactsActionBar/ArtifactsFilters.jsx @@ -17,51 +17,97 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React from 'react' +import React, { useState } from 'react' import { useForm } from 'react-final-form' import PropTypes from 'prop-types' import { FormInput, FormCheckBox, FormOnChange } from 'igz-controls/components' import FormTagFilter from '../../common/FormTagFilter/FormTagFilter' -import { ITERATIONS_FILTER, LABELS_FILTER, SHOW_ITERATIONS, TAG_FILTER } from '../../constants' +import { + ITERATIONS_FILTER, + LABELS_FILTER, + MODEL_NAME_FILTER, + MODEL_TAG_FILTER, + SHOW_ITERATIONS, + TAG_FILTER +} from '../../constants' + +import SearchIcon from 'igz-controls/images/search.svg?react' import './artifactsFilters.scss' -const ArtifactsFilters = ({ artifacts, isAllVersions }) => { +const ArtifactsFilters = ({ artifacts, filtersConfig, isAllVersions }) => { const form = useForm() + const [modelName, setModelName] = useState(form.getState().values[MODEL_NAME_FILTER] || '') const handleIter = value => { form.change(ITERATIONS_FILTER, value ? SHOW_ITERATIONS : '') } - const handleLabelsChange = value => { - form.change(LABELS_FILTER, value || '') + const handleInputChange = (value, filterName) => { + form.change(filterName, value || '') } return (
      - + handleInputChange(value, LABELS_FILTER)} + />
      + {filtersConfig[MODEL_NAME_FILTER] && ( + <> +
      + } + name={MODEL_NAME_FILTER} + placeholder="Search model name.." + /> + { + handleInputChange(value, MODEL_NAME_FILTER) + setModelName(value) + }} + /> +
      +
      + 0 ? : null} + name={MODEL_TAG_FILTER} + placeholder="All tags" + disabled={modelName.length === 0} + tip={modelName.length === 0 ? 'Enter a model name to enable field.' : null} + /> + handleInputChange(value, MODEL_TAG_FILTER)} + /> +
      + + )}
      @@ -72,6 +118,7 @@ const ArtifactsFilters = ({ artifacts, isAllVersions }) => { ArtifactsFilters.propTypes = { artifacts: PropTypes.arrayOf(PropTypes.object).isRequired, + filtersConfig: PropTypes.object.isRequired, isAllVersions: PropTypes.bool.isRequired } diff --git a/src/components/LLMPrompts/LLMPrompts.jsx b/src/components/LLMPrompts/LLMPrompts.jsx index 29dc82c0f5..3340486212 100644 --- a/src/components/LLMPrompts/LLMPrompts.jsx +++ b/src/components/LLMPrompts/LLMPrompts.jsx @@ -27,7 +27,12 @@ import Artifacts from '../Artifacts/Artifacts' import { LLM_PROMPT_TYPE, LLM_PROMPTS_PAGE } from '../../constants' import { createLLMPromptsRowData } from '../../utils/createArtifactsContent' import { fetchLLMPrompts, removeDataSets } from '../../reducers/artifactsReducer' -import { generateActionsMenu, generatePageData, handleApplyDetailsChanges } from './llmPrompts.util' +import { + generateActionsMenu, + generatePageData, + getFiltersConfig, + handleApplyDetailsChanges +} from './llmPrompts.util' const LLMPrompts = ({ isAllVersions }) => { const artifactsStore = useSelector(store => store.artifactsStore) @@ -47,6 +52,7 @@ const LLMPrompts = ({ isAllVersions }) => { generateActionsMenu={generateActionsMenu} generateDetailsFormInitialValues={generateDetailsFormInitialValues} generatePageData={generatePageData} + getArtifactFiltersConfig={getFiltersConfig} handleApplyDetailsChanges={handleApplyDetailsChanges} isAllVersions={isAllVersions} page={LLM_PROMPTS_PAGE} diff --git a/src/components/LLMPrompts/llmPrompts.util.jsx b/src/components/LLMPrompts/llmPrompts.util.jsx index 492e5cf999..e671b4e839 100644 --- a/src/components/LLMPrompts/llmPrompts.util.jsx +++ b/src/components/LLMPrompts/llmPrompts.util.jsx @@ -23,10 +23,18 @@ import DeleteArtifactPopUp from '../../elements/DeleteArtifactPopUp/DeleteArtifa import { ARTIFACT_MAX_DOWNLOAD_SIZE, + ITERATIONS_FILTER, + LABELS_FILTER, LLM_PROMPT_TYPE, - LLM_PROMPTS_PAGE + LLM_PROMPTS_PAGE, + MODEL_NAME_FILTER, + MODEL_TAG_FILTER, + NAME_FILTER, + SHOW_ITERATIONS, + TAG_FILTER, + TAG_FILTER_ALL_ITEMS, + TAG_FILTER_LATEST } from '../../constants' -import { FULL_VIEW_MODE } from 'igz-controls/constants' import { applyTagChanges, chooseOrFetchArtifact } from '../../utils/artifacts.util' import { copyToClipboard } from '../../utils/copyToClipboard' import { generateUri } from '../../utils/resources' @@ -35,6 +43,7 @@ import { handleDeleteArtifact } from '../../utils/handleDeleteArtifact' import { openDeleteConfirmPopUp, openPopUp } from 'igz-controls/utils/common.util' import { setDownloadItem, setShowDownloadsList } from '../../reducers/downloadReducer' import { showArtifactsPreview } from '../../reducers/artifactsReducer' +import { FULL_VIEW_MODE } from 'igz-controls/constants' import TagIcon from 'igz-controls/images/tag-icon.svg?react' import YamlIcon from 'igz-controls/images/yaml.svg?react' @@ -115,7 +124,7 @@ export const generateActionsMenu = ( isDetailsPopUp = false ) => { const isTargetPathValid = getIsTargetPathValid(llmPromptMin ?? {}, frontendSpec) - const datasetDataCouldBeDeleted = + const llmPromptDataCouldBeDeleted = llmPromptMin?.target_path?.endsWith('.pq') || llmPromptMin?.target_path?.endsWith('.parquet') const getFullLLMPrompt = llmPromptMin => { @@ -174,7 +183,7 @@ export const generateActionsMenu = ( hidden: isDetailsPopUp, className: 'danger', onClick: () => - datasetDataCouldBeDeleted + llmPromptDataCouldBeDeleted ? openPopUp(DeleteArtifactPopUp, { artifact: llmPromptMin, artifactType: LLM_PROMPT_TYPE, @@ -257,3 +266,30 @@ export const generateActionsMenu = ( ] ] } + +export const getFiltersConfig = isAllVersions => ({ + [NAME_FILTER]: { label: 'Name:', initialValue: '', hidden: isAllVersions }, + [TAG_FILTER]: { + label: 'LLM prompt version tag:', + initialValue: isAllVersions ? TAG_FILTER_ALL_ITEMS : TAG_FILTER_LATEST, + isModal: true + }, + [LABELS_FILTER]: { label: 'Labels:', initialValue: '', isModal: true }, + [ITERATIONS_FILTER]: { + label: 'Show best iteration only', + initialValue: isAllVersions ? '' : SHOW_ITERATIONS, + isModal: true + }, + [MODEL_NAME_FILTER]: { + label: 'Model name:', + initialValue: '', + isModal: true, + hidden: isAllVersions + }, + [MODEL_TAG_FILTER]: { + label: 'Model version tag:', + initialValue: '', + isModal: true, + hidden: isAllVersions + } +}) diff --git a/src/constants.js b/src/constants.js index 1fe2eb71cf..30092f97f3 100644 --- a/src/constants.js +++ b/src/constants.js @@ -376,6 +376,8 @@ export const SHOW_UNTAGGED_FILTER = 'showUntagged' export const SORT_BY = 'sortBy' export const STATUS_FILTER = 'state' export const TAG_FILTER = 'tag' +export const MODEL_NAME_FILTER = 'model-name' +export const MODEL_TAG_FILTER = 'model-tag' export const AUTO_REFRESH_ID = 'auto-refresh' export const INTERNAL_AUTO_REFRESH_ID = 'internal-auto-refresh' export const AUTO_REFRESH = 'Auto Refresh' From 7132492573659b59b93208d128b3ca42311eae55 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:44:03 +0300 Subject: [PATCH 034/228] Bump DRC version `3.1.2` (#3313) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1fa3a536df..04be40b60a 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.1", + "iguazio.dashboard-react-controls": "3.1.2", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", From c75be2082376df95ad2112f2be59a8232d7b0615 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:46:23 +0300 Subject: [PATCH 035/228] Impl [UI] Jobs/Runs display retry (#3312) --- src/components/Details/details.util.js | 6 + src/components/Jobs/jobs.util.js | 4 +- src/utils/createJobsContent.js | 14 + src/utils/parseJob.js | 2 + tests/mockServer/data/run.json | 5676 ++++++++++++++++++----- tests/mockServer/data/runs.json | 5687 +++++++++++++++++++----- 6 files changed, 9322 insertions(+), 2067 deletions(-) diff --git a/src/components/Details/details.util.js b/src/components/Details/details.util.js index 8f07067c70..b9e56b4c83 100644 --- a/src/components/Details/details.util.js +++ b/src/components/Details/details.util.js @@ -350,6 +350,12 @@ export const generateJobsContent = selectedItem => { : selectedItem.iterationStats?.length ? selectedItem.iterationStats.length - 1 : 'N/A' + }, + retryCount: { + value: selectedItem.retryCount + }, + maxRetries: { + value: selectedItem.maxRetries } } } diff --git a/src/components/Jobs/jobs.util.js b/src/components/Jobs/jobs.util.js index 1884cc0031..738f548c35 100644 --- a/src/components/Jobs/jobs.util.js +++ b/src/components/Jobs/jobs.util.js @@ -73,7 +73,9 @@ export const getInfoHeaders = (isSpark, selectedJob) => { { label: 'Labels', id: 'labels' }, { label: 'Log level', id: LOG_LEVEL_ID }, { label: 'Output path', id: 'outputPath' }, - { label: 'Total iterations', id: 'iterations' } + { label: 'Total iterations', id: 'iterations' }, + { label: 'Retry count', id: 'retryCount' }, + { label: 'Maximum retries', id: 'maxRetries' } ] if (isSpark) { diff --git a/src/utils/createJobsContent.js b/src/utils/createJobsContent.js index 410f0119c0..26ba504617 100644 --- a/src/utils/createJobsContent.js +++ b/src/utils/createJobsContent.js @@ -162,6 +162,13 @@ export const createJobsMonitorTabContent = (jobs, jobName, isStagingMode) => { value: job.updated || new Date(job.finished_at), className: 'table-cell-1', type: 'hidden' + }, + { + headerId: 'retries', + headerLabel: 'Retries', + id: `retries.${identifierUnique}`, + value: job.maxRetries ? `${job.retryCount} out of ${job.maxRetries}` : '', + className: 'table-cell-1', } ] } @@ -556,6 +563,13 @@ export const createJobsMonitoringContent = (jobs, jobName, isStagingMode) => { value: job.updated || new Date(job.finished_at), className: 'table-cell-1', type: 'hidden' + }, + { + headerId: 'retries', + headerLabel: 'Retries', + id: `retries.${identifierUnique}`, + value: job.maxRetries ? `${job.retryCount} out of ${job.maxRetries}` : '', + className: 'table-cell-1', } ] } diff --git a/src/utils/parseJob.js b/src/utils/parseJob.js index 2803b79726..fa3fbc6b04 100644 --- a/src/utils/parseJob.js +++ b/src/utils/parseJob.js @@ -97,6 +97,8 @@ export const parseJob = (job, tab, customState, customError) => { nodeSelectorChips: parseKeyValues(job.spec?.node_selector || {}), project: job.metadata.project, reason: job.status?.reason ?? '', + retryCount: job.status.retry_count ?? 0, + maxRetries: job.spec?.retry?.count ?? 0, results: job.status?.results || {}, resultsChips: parseKeyValues(job.status?.results || {}), startTime: new Date(job.status?.start_time), diff --git a/tests/mockServer/data/run.json b/tests/mockServer/data/run.json index ae1f6903d6..42720402ea 100644 --- a/tests/mockServer/data/run.json +++ b/tests/mockServer/data/run.json @@ -24,7 +24,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -32,7 +38,8 @@ "start_time": "2021-11-08T16:24:30.312181+00:00", "last_update": "2021-11-08T16:24:30.472758+00:00", "artifacts": [], - "error": "handler dg not found in main.py" + "error": "handler dg not found in main.py", + "retry_count": 2 } }, { @@ -59,7 +66,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -67,7 +80,8 @@ "start_time": "2021-11-08T16:24:30.310633+00:00", "last_update": "2021-11-08T16:24:30.473678+00:00", "artifacts": [], - "error": "handler seg not found in main.py" + "error": "handler seg not found in main.py", + "retry_count": 2 } }, { @@ -94,14 +108,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-08T16:22:18.425595+00:00", "last_update": "2021-11-08T16:23:45.047882+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -127,7 +148,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -135,7 +162,8 @@ "start_time": "2021-10-26T10:23:46.201308+00:00", "last_update": "2021-10-26T10:23:46.326428+00:00", "artifacts": [], - "error": "handler seg not found in main.py" + "error": "handler seg not found in main.py", + "retry_count": 1 } }, { @@ -161,14 +189,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-12T08:24:05.965500+00:00", "last_update": "2021-10-12T08:24:10.599070+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -194,14 +229,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-09-14T09:30:33.692216+00:00", "last_update": "2021-09-14T09:30:45.398626+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -230,14 +272,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-13T12:37:39.890790+00:00", "last_update": "2021-09-13T12:37:47.341825+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -263,7 +312,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -271,7 +326,8 @@ "start_time": "2021-09-10T11:49:26.170358+00:00", "last_update": "2021-09-10T11:49:26.249424+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:49:26 GMT', 'Content-Length': '974'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-sz7vd\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-sz7vd\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:49:26 GMT', 'Content-Length': '974'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-sz7vd\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-sz7vd\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 1 } }, { @@ -297,7 +353,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -305,7 +367,8 @@ "start_time": "2021-09-10T11:46:36.715480+00:00", "last_update": "2021-09-10T11:46:36.768280+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:46:36 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-frtb9\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-frtb9\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:46:36 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-frtb9\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-frtb9\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 0 } }, { @@ -331,7 +394,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -339,7 +408,8 @@ "start_time": "2021-09-10T11:45:54.004341+00:00", "last_update": "2021-09-10T11:45:54.059573+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:45:54 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-bk7xh\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-bk7xh\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:45:54 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-bk7xh\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-bk7xh\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 0 } }, { @@ -365,7 +435,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -373,7 +449,8 @@ "start_time": "2021-09-10T11:45:44.673524+00:00", "last_update": "2021-09-10T11:45:44.804681+00:00", "artifacts": [], - "error": "handler sef not found in main.py" + "error": "handler sef not found in main.py", + "retry_count": 1 } }, { @@ -399,7 +476,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -407,7 +490,8 @@ "start_time": "2021-09-10T11:44:47.606870+00:00", "last_update": "2021-09-10T11:44:47.678370+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:44:47 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-6wpgq\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-6wpgq\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:44:47 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-6wpgq\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-6wpgq\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 1 } }, { @@ -434,14 +518,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:58:12.581215+00:00", "last_update": "2021-09-03T13:58:12.581220+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -468,14 +559,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:58:01.150086+00:00", "last_update": "2021-09-03T13:58:01.150091+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -502,14 +600,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:57:20.120500+00:00", "last_update": "2021-09-03T13:57:20.120505+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -536,14 +641,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:51:21.205831+00:00", "last_update": "2021-09-03T13:51:21.205834+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -571,14 +683,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:51:05.027342+00:00", "last_update": "2021-09-03T13:51:05.027349+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -612,7 +731,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -620,7 +745,8 @@ "start_time": "2021-09-03T13:50:59.748610+00:00", "last_update": "2021-09-03T13:50:59.909427+00:00", "error": "[Errno 2] No such file or directory: ''", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -648,14 +774,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:50:01.211460+00:00", "last_update": "2021-09-03T13:50:01.211465+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -702,7 +835,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -710,7 +849,8 @@ "start_time": "2021-08-29T20:01:45.738537+00:00", "last_update": "2021-08-29T20:02:01.827946+00:00", "artifacts": [], - "error": "2021-08-29 20:01:36.582972: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib:\n2021-08-29 20:01:36.583019: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n2021-08-29 20:01:46.470042: I tensorflow/compiler/jit/xla_cpu_device.cc:41] Not creating XLA devices, tf_xla_enable_xla_devices not set\n2021-08-29 20:01:46.470263: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib:\n2021-08-29 20:01:46.470283: W tensorflow/stream_executor/cuda/cuda_driver.cc:326] failed call to cuInit: UNKNOWN ERROR (303)\n2021-08-29 20:01:46.470306: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (train-1193bacd-worker-0): /proc/driver/nvidia/version does not exist\n2021-08-29 20:01:46.518782: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\nTo enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n2021-08-29 20:01:46.518927: I tensorflow/compiler/jit/xla_gpu_device.cc:99] Not creating XLA devices, tf_xla_enable_xla_devices not set\nSome callbacks may not have access to the averaged metrics, see https://github.com/horovod/horovod/issues/2440\nTraceback (most recent call last):\n File \"/User/demos/image-classification-with-distributed-training/src-tfv2/horovod-training.py\", line 116, in \n hvd.callbacks.LearningRateWarmupCallback(warmup_epochs=5, verbose=1),\nTypeError: __init__() missing 1 required positional argument: 'initial_lr'\n" + "error": "2021-08-29 20:01:36.582972: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib:\n2021-08-29 20:01:36.583019: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n2021-08-29 20:01:46.470042: I tensorflow/compiler/jit/xla_cpu_device.cc:41] Not creating XLA devices, tf_xla_enable_xla_devices not set\n2021-08-29 20:01:46.470263: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib:\n2021-08-29 20:01:46.470283: W tensorflow/stream_executor/cuda/cuda_driver.cc:326] failed call to cuInit: UNKNOWN ERROR (303)\n2021-08-29 20:01:46.470306: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (train-1193bacd-worker-0): /proc/driver/nvidia/version does not exist\n2021-08-29 20:01:46.518782: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\nTo enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n2021-08-29 20:01:46.518927: I tensorflow/compiler/jit/xla_gpu_device.cc:99] Not creating XLA devices, tf_xla_enable_xla_devices not set\nSome callbacks may not have access to the averaged metrics, see https://github.com/horovod/horovod/issues/2440\nTraceback (most recent call last):\n File \"/User/demos/image-classification-with-distributed-training/src-tfv2/horovod-training.py\", line 116, in \n hvd.callbacks.LearningRateWarmupCallback(warmup_epochs=5, verbose=1),\nTypeError: __init__() missing 1 required positional argument: 'initial_lr'\n", + "retry_count": 2 } }, { @@ -746,7 +886,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -764,7 +910,8 @@ "uid": "20-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -795,7 +942,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -813,7 +966,8 @@ "uid": "21-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -865,7 +1019,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1380,7 +1540,8 @@ "uid": "22-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -1416,7 +1577,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1424,7 +1591,8 @@ "start_time": "2021-11-09T15:39:58.595075+00:00", "last_update": "2021-11-09T15:39:58.910192+00:00", "error": "[Errno 2] No such file or directory: '/User/demos/customer-churn-prediction/data/pipeline/eaae138e-439a-47fa-93c6-ba0fe1dc3b79/tenured-test-set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1452,14 +1620,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-09T15:39:25.398562+00:00", "last_update": "2021-11-09T15:39:25.473487+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -1495,7 +1670,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1503,7 +1684,8 @@ "start_time": "2021-11-08T16:26:06.311262+00:00", "last_update": "2021-11-08T16:26:06.600147+00:00", "error": "[Errno 2] No such file or directory: '/User/demos/customer-churn-prediction/data/pipeline/eaae138e-439a-47fa-93c6-ba0fe1dc3b79/tenured-test-set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -1531,14 +1713,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T16:25:34.779339+00:00", "last_update": "2021-11-08T16:25:34.842229+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -1585,7 +1774,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1593,7 +1788,8 @@ "start_time": "2021-11-08T16:25:23.418269+00:00", "last_update": "2021-11-08T16:25:23.647817+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1641,7 +1837,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1649,7 +1851,8 @@ "start_time": "2021-11-08T16:25:23.359533+00:00", "last_update": "2021-11-08T16:25:23.583287+00:00", "error": "'str' object has no attribute 'as_df'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -1687,7 +1890,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1695,7 +1904,8 @@ "start_time": "2021-11-08T16:25:23.359185+00:00", "last_update": "2021-11-08T16:25:23.809551+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -1733,7 +1943,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1741,7 +1957,8 @@ "start_time": "2021-11-08T16:25:23.359144+00:00", "last_update": "2021-11-08T16:25:23.584861+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1779,7 +1996,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1787,7 +2010,8 @@ "start_time": "2021-11-08T16:25:22.232499+00:00", "last_update": "2021-11-08T16:25:22.405691+00:00", "error": "file type unhandled src", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -1825,7 +2049,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1833,7 +2063,8 @@ "start_time": "2021-11-08T16:25:20.324321+00:00", "last_update": "2021-11-08T16:25:20.517116+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -1861,14 +2092,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T16:25:16.966884+00:00", "last_update": "2021-11-08T16:25:17.038745+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1897,7 +2135,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1905,7 +2149,8 @@ "start_time": "2021-11-08T16:23:11.710713+00:00", "last_update": "2021-11-08T16:23:12.129908+00:00", "artifacts": [], - "error": ".run() can only be execute on \"mlrun\" kind, recreate with function kind \"mlrun\"" + "error": ".run() can only be execute on \"mlrun\" kind, recreate with function kind \"mlrun\"", + "retry_count": 2 } }, { @@ -1940,7 +2185,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1948,7 +2199,8 @@ "start_time": "2021-09-16T08:00:05.727520+00:00", "last_update": "2021-09-16T08:00:06.112908+00:00", "error": "[Errno 2] No such file or directory: '/User/demos/customer-churn-prediction/data/pipeline/eaae138e-439a-47fa-93c6-ba0fe1dc3b79/test_set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2005,7 +2257,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2013,7 +2271,8 @@ "start_time": "2021-09-15T13:44:33.718770+00:00", "last_update": "2021-09-15T13:44:34.287133+00:00", "error": "file type unhandled v3io://test/test", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2050,7 +2309,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2058,7 +2323,8 @@ "start_time": "2021-09-03T14:02:21.992537+00:00", "last_update": "2021-09-03T14:02:22.143202+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2095,7 +2361,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2103,7 +2375,8 @@ "start_time": "2021-09-03T14:02:14.813451+00:00", "last_update": "2021-09-03T14:02:14.961434+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -2150,7 +2423,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2158,7 +2437,8 @@ "start_time": "2021-09-03T14:02:06.911466+00:00", "last_update": "2021-09-03T14:02:07.047657+00:00", "error": "'str' object has no attribute 'as_df'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2195,7 +2475,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2203,7 +2489,8 @@ "start_time": "2021-09-03T14:01:57.400446+00:00", "last_update": "2021-09-03T14:01:57.593225+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2249,7 +2536,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2257,7 +2550,8 @@ "start_time": "2021-09-03T14:01:41.039404+00:00", "last_update": "2021-09-03T14:01:41.302859+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -2294,7 +2588,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2302,7 +2602,8 @@ "start_time": "2021-09-03T14:01:25.207451+00:00", "last_update": "2021-09-03T14:01:25.372461+00:00", "error": "file type unhandled src", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2349,7 +2650,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2357,7 +2664,8 @@ "start_time": "2021-09-03T13:56:21.373049+00:00", "last_update": "2021-09-03T13:56:21.517709+00:00", "error": "'str' object has no attribute 'as_df'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2394,7 +2702,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2402,7 +2716,8 @@ "start_time": "2021-09-03T13:56:21.206337+00:00", "last_update": "2021-09-03T13:56:21.342459+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2439,7 +2754,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2447,7 +2768,8 @@ "start_time": "2021-09-03T13:56:19.700627+00:00", "last_update": "2021-09-03T13:56:19.856594+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2493,7 +2815,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2501,7 +2829,8 @@ "start_time": "2021-09-03T13:56:19.515710+00:00", "last_update": "2021-09-03T13:56:19.665883+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -2538,7 +2867,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2546,7 +2881,8 @@ "start_time": "2021-09-03T13:56:16.478536+00:00", "last_update": "2021-09-03T13:56:16.600809+00:00", "error": "file type unhandled src", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2583,7 +2919,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2591,7 +2933,8 @@ "start_time": "2021-09-03T13:55:42.511622+00:00", "last_update": "2021-09-03T13:55:42.712944+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2628,7 +2971,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -2719,7 +3068,8 @@ "uid": "49-4", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -2756,7 +3106,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -3580,7 +3936,8 @@ "uid": "50-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -3643,7 +4000,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -5812,7 +6175,8 @@ "uid": "51-6", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -5847,7 +6211,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -5972,7 +6342,8 @@ "uid": "52-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -6023,7 +6394,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -9552,7 +9929,8 @@ "uid": "53-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -9590,7 +9968,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -12200,7 +12584,8 @@ "uid": "54-4", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -12232,7 +12617,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -14842,7 +15233,8 @@ "uid": "55-4", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -14887,7 +15279,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -14895,7 +15293,8 @@ "start_time": "2021-11-25T15:20:04.626994+00:00", "last_update": "2021-11-25T15:20:04.869705+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -14940,7 +15339,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -14948,7 +15353,8 @@ "start_time": "2021-11-25T15:10:04.547356+00:00", "last_update": "2021-11-25T15:10:04.740772+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -14993,7 +15399,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15001,7 +15413,8 @@ "start_time": "2021-11-25T15:00:04.530198+00:00", "last_update": "2021-11-25T15:00:04.778945+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15046,7 +15459,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15054,7 +15473,8 @@ "start_time": "2021-11-25T14:50:04.689049+00:00", "last_update": "2021-11-25T14:50:04.876507+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15099,7 +15519,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15107,7 +15533,8 @@ "start_time": "2021-11-25T14:40:04.591290+00:00", "last_update": "2021-11-25T14:40:04.779383+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15152,7 +15579,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15160,7 +15593,8 @@ "start_time": "2021-11-25T14:30:04.478111+00:00", "last_update": "2021-11-25T14:30:04.671986+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15205,7 +15639,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15213,7 +15653,8 @@ "start_time": "2021-11-25T14:20:04.413115+00:00", "last_update": "2021-11-25T14:20:04.602205+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15258,7 +15699,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15266,7 +15713,8 @@ "start_time": "2021-11-25T14:10:04.748113+00:00", "last_update": "2021-11-25T14:10:04.936987+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15311,7 +15759,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15319,7 +15773,8 @@ "start_time": "2021-11-25T14:00:04.499287+00:00", "last_update": "2021-11-25T14:00:04.748608+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15364,7 +15819,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15372,7 +15833,8 @@ "start_time": "2021-11-25T13:50:04.460226+00:00", "last_update": "2021-11-25T13:50:04.663531+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15417,7 +15879,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15425,7 +15893,8 @@ "start_time": "2021-11-25T13:40:04.616903+00:00", "last_update": "2021-11-25T13:40:05.070431+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15470,7 +15939,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15478,7 +15953,8 @@ "start_time": "2021-11-25T13:30:04.482084+00:00", "last_update": "2021-11-25T13:30:04.682436+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15523,7 +15999,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15531,7 +16013,8 @@ "start_time": "2021-11-25T13:20:04.619182+00:00", "last_update": "2021-11-25T13:20:04.821367+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15576,7 +16059,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15584,7 +16073,8 @@ "start_time": "2021-11-25T13:10:04.530025+00:00", "last_update": "2021-11-25T13:10:04.725068+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15629,7 +16119,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15637,7 +16133,8 @@ "start_time": "2021-11-25T13:00:04.554031+00:00", "last_update": "2021-11-25T13:00:04.800899+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15682,7 +16179,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15690,7 +16193,8 @@ "start_time": "2021-11-25T12:50:04.498226+00:00", "last_update": "2021-11-25T12:50:04.692993+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15735,7 +16239,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15743,7 +16253,8 @@ "start_time": "2021-11-25T12:40:04.664771+00:00", "last_update": "2021-11-25T12:40:04.859887+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15788,7 +16299,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15796,7 +16313,8 @@ "start_time": "2021-11-25T12:30:04.506004+00:00", "last_update": "2021-11-25T12:30:04.697277+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15841,7 +16359,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15849,7 +16373,8 @@ "start_time": "2021-11-25T12:20:04.678686+00:00", "last_update": "2021-11-25T12:20:04.872209+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15894,7 +16419,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15902,7 +16433,8 @@ "start_time": "2021-11-25T12:10:04.672087+00:00", "last_update": "2021-11-25T12:10:04.889989+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15947,7 +16479,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15955,7 +16493,8 @@ "start_time": "2021-11-25T12:00:04.755738+00:00", "last_update": "2021-11-25T12:00:05.093911+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -16000,7 +16539,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16008,7 +16553,8 @@ "start_time": "2021-11-25T11:50:04.480850+00:00", "last_update": "2021-11-25T11:50:04.677429+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16053,7 +16599,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16061,7 +16613,8 @@ "start_time": "2021-11-25T11:40:04.602256+00:00", "last_update": "2021-11-25T11:40:04.850283+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16106,7 +16659,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16114,7 +16673,8 @@ "start_time": "2021-11-25T11:30:04.426377+00:00", "last_update": "2021-11-25T11:30:04.636503+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16159,7 +16719,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16167,7 +16733,8 @@ "start_time": "2021-11-25T11:20:04.516140+00:00", "last_update": "2021-11-25T11:20:04.735509+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16212,7 +16779,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16220,7 +16793,8 @@ "start_time": "2021-11-25T11:10:04.472037+00:00", "last_update": "2021-11-25T11:10:04.664942+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16265,7 +16839,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16273,7 +16853,8 @@ "start_time": "2021-11-25T11:00:04.657896+00:00", "last_update": "2021-11-25T11:00:04.883672+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -16318,7 +16899,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16326,7 +16913,8 @@ "start_time": "2021-11-25T10:50:04.647522+00:00", "last_update": "2021-11-25T10:50:04.836197+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16371,7 +16959,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16379,7 +16973,8 @@ "start_time": "2021-11-25T10:40:04.569781+00:00", "last_update": "2021-11-25T10:40:04.770749+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16424,7 +17019,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16432,7 +17033,8 @@ "start_time": "2021-11-25T10:30:04.676500+00:00", "last_update": "2021-11-25T10:30:04.860678+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16477,7 +17079,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16485,7 +17093,8 @@ "start_time": "2021-11-25T10:20:04.709992+00:00", "last_update": "2021-11-25T10:20:04.906660+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16530,7 +17139,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16538,7 +17153,8 @@ "start_time": "2021-11-25T10:10:04.654881+00:00", "last_update": "2021-11-25T10:10:04.877279+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16583,7 +17199,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16591,7 +17213,8 @@ "start_time": "2021-11-25T10:00:04.655647+00:00", "last_update": "2021-11-25T10:00:04.922516+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16636,7 +17259,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16644,7 +17273,8 @@ "start_time": "2021-11-25T09:50:05.301473+00:00", "last_update": "2021-11-25T09:50:05.506318+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16689,7 +17319,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16697,7 +17333,8 @@ "start_time": "2021-11-25T09:40:04.688485+00:00", "last_update": "2021-11-25T09:40:04.885575+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16742,7 +17379,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16750,7 +17393,8 @@ "start_time": "2021-11-25T09:30:04.526432+00:00", "last_update": "2021-11-25T09:30:04.714181+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16795,7 +17439,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16803,7 +17453,8 @@ "start_time": "2021-11-25T09:20:04.628475+00:00", "last_update": "2021-11-25T09:20:04.872881+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16848,7 +17499,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16856,7 +17513,8 @@ "start_time": "2021-11-25T09:10:04.450469+00:00", "last_update": "2021-11-25T09:10:04.777839+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16901,7 +17559,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16909,7 +17573,8 @@ "start_time": "2021-11-25T09:00:04.766381+00:00", "last_update": "2021-11-25T09:00:05.025565+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -16954,7 +17619,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16962,7 +17633,8 @@ "start_time": "2021-11-25T08:50:04.418181+00:00", "last_update": "2021-11-25T08:50:04.595812+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17007,7 +17679,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17015,7 +17693,8 @@ "start_time": "2021-11-25T08:40:04.569381+00:00", "last_update": "2021-11-25T08:40:04.759896+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17060,7 +17739,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17068,7 +17753,8 @@ "start_time": "2021-11-25T08:30:04.600599+00:00", "last_update": "2021-11-25T08:30:04.848873+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17113,7 +17799,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17121,7 +17813,8 @@ "start_time": "2021-11-25T08:20:04.519720+00:00", "last_update": "2021-11-25T08:20:04.819565+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17166,7 +17859,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17174,7 +17873,8 @@ "start_time": "2021-11-25T08:10:04.578285+00:00", "last_update": "2021-11-25T08:10:04.758011+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17219,7 +17919,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17227,7 +17933,8 @@ "start_time": "2021-11-25T08:00:04.433436+00:00", "last_update": "2021-11-25T08:00:04.694042+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17272,7 +17979,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17280,7 +17993,8 @@ "start_time": "2021-11-25T07:50:04.643860+00:00", "last_update": "2021-11-25T07:50:04.894175+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17325,7 +18039,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17333,7 +18053,8 @@ "start_time": "2021-11-25T07:40:04.621111+00:00", "last_update": "2021-11-25T07:40:04.847086+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17378,7 +18099,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17386,7 +18113,8 @@ "start_time": "2021-11-25T07:30:04.433519+00:00", "last_update": "2021-11-25T07:30:04.623295+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17431,7 +18159,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17439,7 +18173,8 @@ "start_time": "2021-11-25T07:20:04.851092+00:00", "last_update": "2021-11-25T07:20:05.072058+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17484,7 +18219,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17492,7 +18233,8 @@ "start_time": "2021-11-25T07:10:04.701725+00:00", "last_update": "2021-11-25T07:10:04.891876+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17537,7 +18279,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17545,7 +18293,8 @@ "start_time": "2021-11-25T07:00:04.730707+00:00", "last_update": "2021-11-25T07:00:04.959567+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17590,7 +18339,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17598,7 +18353,8 @@ "start_time": "2021-11-25T06:50:04.389233+00:00", "last_update": "2021-11-25T06:50:04.570853+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17643,7 +18399,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17651,7 +18413,8 @@ "start_time": "2021-11-25T06:40:04.779848+00:00", "last_update": "2021-11-25T06:40:04.993553+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17696,7 +18459,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17704,7 +18473,8 @@ "start_time": "2021-11-25T06:30:04.427263+00:00", "last_update": "2021-11-25T06:30:04.614687+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17749,7 +18519,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17757,7 +18533,8 @@ "start_time": "2021-11-25T06:20:04.434939+00:00", "last_update": "2021-11-25T06:20:04.618174+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17802,7 +18579,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17810,7 +18593,8 @@ "start_time": "2021-11-25T06:10:04.633692+00:00", "last_update": "2021-11-25T06:10:04.845108+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17855,7 +18639,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17863,7 +18653,8 @@ "start_time": "2021-11-25T06:00:04.609640+00:00", "last_update": "2021-11-25T06:00:04.912946+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17908,7 +18699,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17916,7 +18713,8 @@ "start_time": "2021-11-25T05:50:04.449949+00:00", "last_update": "2021-11-25T05:50:04.635722+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17961,7 +18759,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17969,7 +18773,8 @@ "start_time": "2021-11-25T05:40:04.515533+00:00", "last_update": "2021-11-25T05:40:04.736425+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18014,7 +18819,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18022,7 +18833,8 @@ "start_time": "2021-11-25T05:30:04.577631+00:00", "last_update": "2021-11-25T05:30:04.863501+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18067,7 +18879,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18075,7 +18893,8 @@ "start_time": "2021-11-25T05:20:04.455804+00:00", "last_update": "2021-11-25T05:20:04.634993+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18120,7 +18939,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18128,7 +18953,8 @@ "start_time": "2021-11-25T05:10:04.414843+00:00", "last_update": "2021-11-25T05:10:04.629374+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18173,7 +18999,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18181,7 +19013,8 @@ "start_time": "2021-11-25T05:00:04.813068+00:00", "last_update": "2021-11-25T05:00:05.113562+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18226,7 +19059,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18234,7 +19073,8 @@ "start_time": "2021-11-25T04:50:04.587135+00:00", "last_update": "2021-11-25T04:50:04.779001+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18279,7 +19119,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18287,7 +19133,8 @@ "start_time": "2021-11-25T04:40:04.432340+00:00", "last_update": "2021-11-25T04:40:04.693033+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18332,7 +19179,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18340,7 +19193,8 @@ "start_time": "2021-11-25T04:30:04.785460+00:00", "last_update": "2021-11-25T04:30:04.974252+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18385,7 +19239,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18393,7 +19253,8 @@ "start_time": "2021-11-25T04:20:04.487176+00:00", "last_update": "2021-11-25T04:20:04.689088+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18438,7 +19299,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18446,7 +19313,8 @@ "start_time": "2021-11-25T04:10:04.525230+00:00", "last_update": "2021-11-25T04:10:04.804950+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18491,7 +19359,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18499,7 +19373,8 @@ "start_time": "2021-11-25T04:00:04.434934+00:00", "last_update": "2021-11-25T04:00:04.684001+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18544,7 +19419,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18552,7 +19433,8 @@ "start_time": "2021-11-25T03:50:04.404080+00:00", "last_update": "2021-11-25T03:50:04.721225+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18597,7 +19479,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18605,7 +19493,8 @@ "start_time": "2021-11-25T03:40:04.494475+00:00", "last_update": "2021-11-25T03:40:04.780123+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18650,7 +19539,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18658,7 +19553,8 @@ "start_time": "2021-11-25T03:30:04.696343+00:00", "last_update": "2021-11-25T03:30:04.898417+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18703,7 +19599,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18711,7 +19613,8 @@ "start_time": "2021-11-25T03:20:04.805759+00:00", "last_update": "2021-11-25T03:20:04.984463+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18756,7 +19659,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18764,7 +19673,8 @@ "start_time": "2021-11-25T03:10:04.538969+00:00", "last_update": "2021-11-25T03:10:04.807798+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18809,7 +19719,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18817,7 +19733,8 @@ "start_time": "2021-11-25T03:00:04.573902+00:00", "last_update": "2021-11-25T03:00:04.835497+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18862,7 +19779,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18870,7 +19793,8 @@ "start_time": "2021-11-25T02:50:04.776007+00:00", "last_update": "2021-11-25T02:50:04.956215+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18915,7 +19839,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18923,7 +19853,8 @@ "start_time": "2021-11-25T02:40:04.477586+00:00", "last_update": "2021-11-25T02:40:04.665052+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18968,7 +19899,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18976,7 +19913,8 @@ "start_time": "2021-11-25T02:30:04.474322+00:00", "last_update": "2021-11-25T02:30:04.663125+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19021,7 +19959,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19029,7 +19973,8 @@ "start_time": "2021-11-25T02:20:04.518030+00:00", "last_update": "2021-11-25T02:20:04.854487+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19074,7 +20019,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19082,7 +20033,8 @@ "start_time": "2021-11-25T02:10:04.644281+00:00", "last_update": "2021-11-25T02:10:04.827435+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19127,7 +20079,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19135,7 +20093,8 @@ "start_time": "2021-11-25T02:00:04.631916+00:00", "last_update": "2021-11-25T02:00:04.879130+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19180,7 +20139,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19188,7 +20153,8 @@ "start_time": "2021-11-25T01:50:04.616606+00:00", "last_update": "2021-11-25T01:50:04.799437+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19233,7 +20199,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19241,7 +20213,8 @@ "start_time": "2021-11-25T01:40:04.559437+00:00", "last_update": "2021-11-25T01:40:04.750553+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19286,7 +20259,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19294,7 +20273,8 @@ "start_time": "2021-11-25T01:30:04.941823+00:00", "last_update": "2021-11-25T01:30:05.134506+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19339,7 +20319,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19347,7 +20333,8 @@ "start_time": "2021-11-25T01:20:04.596188+00:00", "last_update": "2021-11-25T01:20:04.782960+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19392,7 +20379,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19400,7 +20393,8 @@ "start_time": "2021-11-25T01:10:04.491352+00:00", "last_update": "2021-11-25T01:10:04.667277+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19445,7 +20439,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19453,7 +20453,8 @@ "start_time": "2021-11-25T01:00:04.644596+00:00", "last_update": "2021-11-25T01:00:04.873300+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19498,7 +20499,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19506,7 +20513,8 @@ "start_time": "2021-11-25T00:50:04.982616+00:00", "last_update": "2021-11-25T00:50:05.168071+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19551,7 +20559,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19559,7 +20573,8 @@ "start_time": "2021-11-25T00:40:04.603050+00:00", "last_update": "2021-11-25T00:40:04.891375+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19604,7 +20619,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19612,7 +20633,8 @@ "start_time": "2021-11-25T00:30:04.551138+00:00", "last_update": "2021-11-25T00:30:04.740014+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19657,7 +20679,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19665,7 +20693,8 @@ "start_time": "2021-11-25T00:20:04.463810+00:00", "last_update": "2021-11-25T00:20:04.814736+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19710,7 +20739,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19718,7 +20753,8 @@ "start_time": "2021-11-25T00:10:04.738628+00:00", "last_update": "2021-11-25T00:10:05.017899+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19763,7 +20799,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19771,7 +20813,8 @@ "start_time": "2021-11-25T00:00:04.544586+00:00", "last_update": "2021-11-25T00:00:05.005375+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19816,7 +20859,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19824,7 +20873,8 @@ "start_time": "2021-11-24T23:50:04.516034+00:00", "last_update": "2021-11-24T23:50:04.708996+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19869,7 +20919,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19877,7 +20933,8 @@ "start_time": "2021-11-24T23:40:04.527184+00:00", "last_update": "2021-11-24T23:40:04.794158+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19922,7 +20979,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19930,7 +20993,8 @@ "start_time": "2021-11-24T23:30:04.532170+00:00", "last_update": "2021-11-24T23:30:04.726453+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19975,7 +21039,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19983,7 +21053,8 @@ "start_time": "2021-11-24T23:20:04.469606+00:00", "last_update": "2021-11-24T23:20:04.756696+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -20028,7 +21099,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20036,7 +21113,8 @@ "start_time": "2021-11-24T23:10:04.438960+00:00", "last_update": "2021-11-24T23:10:04.654338+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -20081,7 +21159,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20089,7 +21173,8 @@ "start_time": "2021-11-24T23:00:04.699017+00:00", "last_update": "2021-11-24T23:00:05.044694+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20134,7 +21219,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20142,7 +21233,8 @@ "start_time": "2021-11-24T22:50:04.479638+00:00", "last_update": "2021-11-24T22:50:04.668838+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20187,7 +21279,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20195,7 +21293,8 @@ "start_time": "2021-11-24T22:40:04.504226+00:00", "last_update": "2021-11-24T22:40:04.695845+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20240,7 +21339,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20248,7 +21353,8 @@ "start_time": "2021-11-24T22:30:04.458818+00:00", "last_update": "2021-11-24T22:30:04.711903+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20293,7 +21399,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20301,7 +21413,8 @@ "start_time": "2021-11-24T22:20:04.418897+00:00", "last_update": "2021-11-24T22:20:04.607711+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20346,7 +21459,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20354,7 +21473,8 @@ "start_time": "2021-11-24T22:10:04.538668+00:00", "last_update": "2021-11-24T22:10:04.734232+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20399,7 +21519,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20407,7 +21533,8 @@ "start_time": "2021-11-24T22:00:04.539921+00:00", "last_update": "2021-11-24T22:00:04.781730+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20452,7 +21579,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20460,7 +21593,8 @@ "start_time": "2021-11-24T21:50:04.510394+00:00", "last_update": "2021-11-24T21:50:04.691104+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20505,7 +21639,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20513,7 +21653,8 @@ "start_time": "2021-11-24T21:40:04.550718+00:00", "last_update": "2021-11-24T21:40:04.749227+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -20558,7 +21699,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20566,7 +21713,8 @@ "start_time": "2021-11-24T21:30:04.409693+00:00", "last_update": "2021-11-24T21:30:04.598307+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20611,7 +21759,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20619,7 +21773,8 @@ "start_time": "2021-11-24T21:20:04.621030+00:00", "last_update": "2021-11-24T21:20:04.810078+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20664,7 +21819,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20672,7 +21833,8 @@ "start_time": "2021-11-24T21:10:04.375332+00:00", "last_update": "2021-11-24T21:10:04.626326+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -20717,7 +21879,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20725,7 +21893,8 @@ "start_time": "2021-11-24T21:00:04.870989+00:00", "last_update": "2021-11-24T21:00:05.112089+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20770,7 +21939,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20778,7 +21953,8 @@ "start_time": "2021-11-24T20:50:04.507278+00:00", "last_update": "2021-11-24T20:50:04.686896+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20823,7 +21999,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20831,7 +22013,8 @@ "start_time": "2021-11-24T20:40:04.546515+00:00", "last_update": "2021-11-24T20:40:04.731933+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20876,7 +22059,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20884,7 +22073,8 @@ "start_time": "2021-11-24T20:30:04.298374+00:00", "last_update": "2021-11-24T20:30:04.511135+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20929,7 +22119,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20937,7 +22133,8 @@ "start_time": "2021-11-24T20:20:04.870619+00:00", "last_update": "2021-11-24T20:20:05.159143+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20982,7 +22179,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20990,7 +22193,8 @@ "start_time": "2021-11-24T20:10:04.611475+00:00", "last_update": "2021-11-24T20:10:04.839482+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21035,7 +22239,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21043,7 +22253,8 @@ "start_time": "2021-11-24T20:00:04.475649+00:00", "last_update": "2021-11-24T20:00:04.795051+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21088,7 +22299,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21096,7 +22313,8 @@ "start_time": "2021-11-24T19:50:04.568253+00:00", "last_update": "2021-11-24T19:50:04.759309+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21141,7 +22359,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21149,7 +22373,8 @@ "start_time": "2021-11-24T19:40:04.520061+00:00", "last_update": "2021-11-24T19:40:04.722499+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21194,7 +22419,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21202,7 +22433,8 @@ "start_time": "2021-11-24T19:30:04.429974+00:00", "last_update": "2021-11-24T19:30:04.643339+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21247,7 +22479,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21255,7 +22493,8 @@ "start_time": "2021-11-24T19:20:04.682369+00:00", "last_update": "2021-11-24T19:20:04.987412+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21300,7 +22539,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21308,7 +22553,8 @@ "start_time": "2021-11-24T19:10:04.798406+00:00", "last_update": "2021-11-24T19:10:04.987420+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21353,7 +22599,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21361,7 +22613,8 @@ "start_time": "2021-11-24T19:00:04.611443+00:00", "last_update": "2021-11-24T19:00:04.904232+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21406,7 +22659,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21414,7 +22673,8 @@ "start_time": "2021-11-24T18:50:04.615771+00:00", "last_update": "2021-11-24T18:50:04.798803+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21459,7 +22719,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21467,7 +22733,8 @@ "start_time": "2021-11-24T18:40:04.599586+00:00", "last_update": "2021-11-24T18:40:04.795373+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21512,7 +22779,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21520,7 +22793,8 @@ "start_time": "2021-11-24T18:30:04.433271+00:00", "last_update": "2021-11-24T18:30:04.641423+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21565,7 +22839,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21573,7 +22853,8 @@ "start_time": "2021-11-24T18:20:04.349454+00:00", "last_update": "2021-11-24T18:20:04.527202+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21618,7 +22899,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21626,7 +22913,8 @@ "start_time": "2021-11-24T18:10:04.801067+00:00", "last_update": "2021-11-24T18:10:05.109504+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21671,7 +22959,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21679,7 +22973,8 @@ "start_time": "2021-11-24T18:00:04.470012+00:00", "last_update": "2021-11-24T18:00:04.699333+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21724,7 +23019,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21732,7 +23033,8 @@ "start_time": "2021-11-24T17:50:04.767415+00:00", "last_update": "2021-11-24T17:50:04.958676+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21777,7 +23079,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21785,7 +23093,8 @@ "start_time": "2021-11-24T17:40:04.565225+00:00", "last_update": "2021-11-24T17:40:04.758722+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21830,7 +23139,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21838,7 +23153,8 @@ "start_time": "2021-11-24T17:30:04.542465+00:00", "last_update": "2021-11-24T17:30:04.726922+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21883,7 +23199,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21891,7 +23213,8 @@ "start_time": "2021-11-24T17:20:04.558157+00:00", "last_update": "2021-11-24T17:20:04.747969+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21936,7 +23259,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21944,7 +23273,8 @@ "start_time": "2021-11-24T17:10:04.510999+00:00", "last_update": "2021-11-24T17:10:04.741880+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21989,7 +23319,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21997,7 +23333,8 @@ "start_time": "2021-11-24T17:00:04.637790+00:00", "last_update": "2021-11-24T17:00:04.914986+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22042,7 +23379,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22050,7 +23393,8 @@ "start_time": "2021-11-24T16:50:04.532151+00:00", "last_update": "2021-11-24T16:50:04.707283+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -22095,7 +23439,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22103,7 +23453,8 @@ "start_time": "2021-11-24T16:40:04.654448+00:00", "last_update": "2021-11-24T16:40:04.857622+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22148,7 +23499,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22156,7 +23513,8 @@ "start_time": "2021-11-24T16:30:04.726833+00:00", "last_update": "2021-11-24T16:30:04.915715+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22201,7 +23559,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22209,7 +23573,8 @@ "start_time": "2021-11-24T16:20:04.765431+00:00", "last_update": "2021-11-24T16:20:04.995627+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -22254,7 +23619,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22262,7 +23633,8 @@ "start_time": "2021-11-24T16:10:04.475159+00:00", "last_update": "2021-11-24T16:10:04.707052+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22307,7 +23679,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22315,7 +23693,8 @@ "start_time": "2021-11-24T16:00:04.513842+00:00", "last_update": "2021-11-24T16:00:04.798010+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22360,7 +23739,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22368,7 +23753,8 @@ "start_time": "2021-11-24T15:50:04.436252+00:00", "last_update": "2021-11-24T15:50:04.625205+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22413,7 +23799,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22421,7 +23813,8 @@ "start_time": "2021-11-24T15:40:04.481903+00:00", "last_update": "2021-11-24T15:40:04.663438+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -22466,7 +23859,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22474,7 +23873,8 @@ "start_time": "2021-11-24T15:30:04.446758+00:00", "last_update": "2021-11-24T15:30:04.620499+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -22519,7 +23919,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22527,7 +23933,8 @@ "start_time": "2021-11-24T15:20:04.612123+00:00", "last_update": "2021-11-24T15:20:04.796937+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22572,7 +23979,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22580,7 +23993,8 @@ "start_time": "2021-11-24T15:10:04.476532+00:00", "last_update": "2021-11-24T15:10:04.690365+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22625,7 +24039,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22633,7 +24053,8 @@ "start_time": "2021-11-24T15:00:04.661578+00:00", "last_update": "2021-11-24T15:00:04.888075+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22678,7 +24099,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22686,7 +24113,8 @@ "start_time": "2021-11-24T14:50:04.475653+00:00", "last_update": "2021-11-24T14:50:04.661629+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22731,7 +24159,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22739,7 +24173,8 @@ "start_time": "2021-11-24T14:40:04.698078+00:00", "last_update": "2021-11-24T14:40:04.874743+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22784,7 +24219,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22792,7 +24233,8 @@ "start_time": "2021-11-24T14:30:04.539611+00:00", "last_update": "2021-11-24T14:30:04.795622+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22837,7 +24279,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22845,7 +24293,8 @@ "start_time": "2021-11-24T14:20:04.446140+00:00", "last_update": "2021-11-24T14:20:04.626509+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22890,7 +24339,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22898,7 +24353,8 @@ "start_time": "2021-11-24T14:10:04.852408+00:00", "last_update": "2021-11-24T14:10:05.035730+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22943,7 +24399,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22951,7 +24413,8 @@ "start_time": "2021-11-24T14:00:04.645034+00:00", "last_update": "2021-11-24T14:00:04.878150+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22996,7 +24459,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23004,7 +24473,8 @@ "start_time": "2021-11-24T13:50:04.477657+00:00", "last_update": "2021-11-24T13:50:04.662831+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23049,7 +24519,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23057,7 +24533,8 @@ "start_time": "2021-11-24T13:40:04.670473+00:00", "last_update": "2021-11-24T13:40:04.861574+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23102,7 +24579,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23110,7 +24593,8 @@ "start_time": "2021-11-24T13:30:04.495716+00:00", "last_update": "2021-11-24T13:30:04.694276+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23155,7 +24639,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23163,7 +24653,8 @@ "start_time": "2021-11-24T13:20:04.449564+00:00", "last_update": "2021-11-24T13:20:04.665086+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23208,7 +24699,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23216,7 +24713,8 @@ "start_time": "2021-11-24T13:10:04.511729+00:00", "last_update": "2021-11-24T13:10:04.694280+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23261,7 +24759,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23269,7 +24773,8 @@ "start_time": "2021-11-24T13:00:04.465753+00:00", "last_update": "2021-11-24T13:00:04.702928+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23314,7 +24819,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23322,7 +24833,8 @@ "start_time": "2021-11-24T12:50:04.505712+00:00", "last_update": "2021-11-24T12:50:04.716717+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23367,7 +24879,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23375,7 +24893,8 @@ "start_time": "2021-11-24T12:40:04.529680+00:00", "last_update": "2021-11-24T12:40:04.723592+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23420,7 +24939,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23428,7 +24953,8 @@ "start_time": "2021-11-24T12:30:04.591878+00:00", "last_update": "2021-11-24T12:30:04.767677+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23473,7 +24999,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23481,7 +25013,8 @@ "start_time": "2021-11-24T12:20:04.506881+00:00", "last_update": "2021-11-24T12:20:04.707187+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23526,7 +25059,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23534,7 +25073,8 @@ "start_time": "2021-11-24T12:10:04.455195+00:00", "last_update": "2021-11-24T12:10:04.662142+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23579,7 +25119,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23587,7 +25133,8 @@ "start_time": "2021-11-24T12:00:04.474861+00:00", "last_update": "2021-11-24T12:00:04.712058+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23632,7 +25179,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23640,7 +25193,8 @@ "start_time": "2021-11-24T11:50:04.465545+00:00", "last_update": "2021-11-24T11:50:04.643853+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23685,7 +25239,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23693,7 +25253,8 @@ "start_time": "2021-11-24T11:40:04.518707+00:00", "last_update": "2021-11-24T11:40:04.714892+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23738,7 +25299,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23746,7 +25313,8 @@ "start_time": "2021-11-24T11:30:04.439386+00:00", "last_update": "2021-11-24T11:30:04.606311+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23791,7 +25359,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23799,7 +25373,8 @@ "start_time": "2021-11-24T11:20:04.553954+00:00", "last_update": "2021-11-24T11:20:04.741887+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23844,7 +25419,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23852,7 +25433,8 @@ "start_time": "2021-11-24T11:10:04.512320+00:00", "last_update": "2021-11-24T11:10:04.692293+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23897,7 +25479,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23905,7 +25493,8 @@ "start_time": "2021-11-24T11:00:04.783589+00:00", "last_update": "2021-11-24T11:00:05.027705+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23950,7 +25539,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23958,7 +25553,8 @@ "start_time": "2021-11-24T10:50:04.460250+00:00", "last_update": "2021-11-24T10:50:04.637607+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24003,7 +25599,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24011,7 +25613,8 @@ "start_time": "2021-11-24T10:40:04.872549+00:00", "last_update": "2021-11-24T10:40:05.055488+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24056,7 +25659,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24064,7 +25673,8 @@ "start_time": "2021-11-24T10:30:04.447723+00:00", "last_update": "2021-11-24T10:30:04.657345+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24109,7 +25719,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24117,7 +25733,8 @@ "start_time": "2021-11-24T10:20:04.460217+00:00", "last_update": "2021-11-24T10:20:04.672371+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24162,7 +25779,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24170,7 +25793,8 @@ "start_time": "2021-11-24T10:10:04.461257+00:00", "last_update": "2021-11-24T10:10:04.644618+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24215,7 +25839,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24223,7 +25853,8 @@ "start_time": "2021-11-24T10:00:04.573863+00:00", "last_update": "2021-11-24T10:00:04.798016+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24268,7 +25899,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24276,7 +25913,8 @@ "start_time": "2021-11-24T09:50:04.512501+00:00", "last_update": "2021-11-24T09:50:04.695227+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24321,7 +25959,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24329,7 +25973,8 @@ "start_time": "2021-11-24T09:40:04.629863+00:00", "last_update": "2021-11-24T09:40:04.834239+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24374,7 +26019,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24382,7 +26033,8 @@ "start_time": "2021-11-24T09:30:04.415640+00:00", "last_update": "2021-11-24T09:30:04.602695+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24427,7 +26079,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24435,7 +26093,8 @@ "start_time": "2021-11-24T09:20:04.389076+00:00", "last_update": "2021-11-24T09:20:04.627217+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24480,7 +26139,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24488,7 +26153,8 @@ "start_time": "2021-11-24T09:10:04.487116+00:00", "last_update": "2021-11-24T09:10:04.670124+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24533,7 +26199,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24541,7 +26213,8 @@ "start_time": "2021-11-24T09:00:04.719912+00:00", "last_update": "2021-11-24T09:00:04.905482+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24586,7 +26259,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24594,7 +26273,8 @@ "start_time": "2021-11-24T08:50:04.761983+00:00", "last_update": "2021-11-24T08:50:04.929543+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24639,7 +26319,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24647,7 +26333,8 @@ "start_time": "2021-11-24T08:40:04.705636+00:00", "last_update": "2021-11-24T08:40:04.897900+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24692,7 +26379,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24700,7 +26393,8 @@ "start_time": "2021-11-24T08:30:04.927018+00:00", "last_update": "2021-11-24T08:30:05.101610+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24745,7 +26439,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24753,7 +26453,8 @@ "start_time": "2021-11-24T08:20:04.573076+00:00", "last_update": "2021-11-24T08:20:04.769617+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24798,7 +26499,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24806,7 +26513,8 @@ "start_time": "2021-11-24T08:10:04.640802+00:00", "last_update": "2021-11-24T08:10:04.829147+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24851,7 +26559,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24859,7 +26573,8 @@ "start_time": "2021-11-24T08:00:04.604561+00:00", "last_update": "2021-11-24T08:00:04.847589+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24904,7 +26619,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24912,7 +26633,8 @@ "start_time": "2021-11-24T07:50:04.475602+00:00", "last_update": "2021-11-24T07:50:04.652628+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24957,7 +26679,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24965,7 +26693,8 @@ "start_time": "2021-11-24T07:40:04.577226+00:00", "last_update": "2021-11-24T07:40:04.759757+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25010,7 +26739,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25018,7 +26753,8 @@ "start_time": "2021-11-24T07:30:04.628014+00:00", "last_update": "2021-11-24T07:30:04.842011+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25063,7 +26799,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25071,7 +26813,8 @@ "start_time": "2021-11-24T07:20:04.572949+00:00", "last_update": "2021-11-24T07:20:04.745549+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25116,7 +26859,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25124,7 +26873,8 @@ "start_time": "2021-11-24T07:10:04.502879+00:00", "last_update": "2021-11-24T07:10:04.764787+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25169,7 +26919,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25177,7 +26933,8 @@ "start_time": "2021-11-24T07:00:04.531331+00:00", "last_update": "2021-11-24T07:00:04.813165+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25222,7 +26979,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25230,7 +26993,8 @@ "start_time": "2021-11-24T06:50:04.460491+00:00", "last_update": "2021-11-24T06:50:04.656143+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25275,7 +27039,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25283,7 +27053,8 @@ "start_time": "2021-11-24T06:40:04.504154+00:00", "last_update": "2021-11-24T06:40:04.742584+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25328,7 +27099,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25336,7 +27113,8 @@ "start_time": "2021-11-24T06:30:04.491594+00:00", "last_update": "2021-11-24T06:30:04.725370+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25381,7 +27159,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25389,7 +27173,8 @@ "start_time": "2021-11-24T06:20:04.519788+00:00", "last_update": "2021-11-24T06:20:04.734958+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25434,7 +27219,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25442,7 +27233,8 @@ "start_time": "2021-11-24T06:10:04.532763+00:00", "last_update": "2021-11-24T06:10:04.823954+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25487,7 +27279,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25495,7 +27293,8 @@ "start_time": "2021-11-24T06:00:04.831518+00:00", "last_update": "2021-11-24T06:00:05.063036+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25540,7 +27339,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25548,7 +27353,8 @@ "start_time": "2021-11-24T05:50:04.921557+00:00", "last_update": "2021-11-24T05:50:05.106362+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25593,7 +27399,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25601,7 +27413,8 @@ "start_time": "2021-11-24T05:40:04.639983+00:00", "last_update": "2021-11-24T05:40:04.822973+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25646,7 +27459,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25654,7 +27473,8 @@ "start_time": "2021-11-24T05:30:04.552970+00:00", "last_update": "2021-11-24T05:30:04.758206+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25699,7 +27519,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25707,7 +27533,8 @@ "start_time": "2021-11-24T05:20:04.568293+00:00", "last_update": "2021-11-24T05:20:04.766989+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25752,7 +27579,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25760,7 +27593,8 @@ "start_time": "2021-11-24T05:10:04.425638+00:00", "last_update": "2021-11-24T05:10:04.610183+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25805,7 +27639,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25813,7 +27653,8 @@ "start_time": "2021-11-24T05:00:04.659651+00:00", "last_update": "2021-11-24T05:00:04.878540+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25858,7 +27699,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25866,7 +27713,8 @@ "start_time": "2021-11-24T04:50:04.525809+00:00", "last_update": "2021-11-24T04:50:04.698016+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25911,7 +27759,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25919,7 +27773,8 @@ "start_time": "2021-11-24T04:40:04.553894+00:00", "last_update": "2021-11-24T04:40:04.748205+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25964,7 +27819,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25972,7 +27833,8 @@ "start_time": "2021-11-24T04:30:04.505059+00:00", "last_update": "2021-11-24T04:30:04.694984+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26017,7 +27879,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26025,7 +27893,8 @@ "start_time": "2021-11-24T04:20:04.444087+00:00", "last_update": "2021-11-24T04:20:04.674675+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26070,7 +27939,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26078,7 +27953,8 @@ "start_time": "2021-11-24T04:10:04.502094+00:00", "last_update": "2021-11-24T04:10:04.693319+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26123,7 +27999,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26131,7 +28013,8 @@ "start_time": "2021-11-24T04:00:04.463193+00:00", "last_update": "2021-11-24T04:00:04.701626+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26176,7 +28059,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26184,7 +28073,8 @@ "start_time": "2021-11-24T03:50:04.567814+00:00", "last_update": "2021-11-24T03:50:04.753820+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26229,7 +28119,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26237,7 +28133,8 @@ "start_time": "2021-11-24T03:40:04.602754+00:00", "last_update": "2021-11-24T03:40:04.796732+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26282,7 +28179,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26290,7 +28193,8 @@ "start_time": "2021-11-24T03:30:04.418104+00:00", "last_update": "2021-11-24T03:30:04.601174+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26335,7 +28239,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26343,7 +28253,8 @@ "start_time": "2021-11-24T03:20:04.461566+00:00", "last_update": "2021-11-24T03:20:04.660232+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26388,7 +28299,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26396,7 +28313,8 @@ "start_time": "2021-11-24T03:10:04.632882+00:00", "last_update": "2021-11-24T03:10:04.841486+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26441,7 +28359,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26449,7 +28373,8 @@ "start_time": "2021-11-24T03:00:04.532402+00:00", "last_update": "2021-11-24T03:00:04.777504+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26494,7 +28419,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26502,7 +28433,8 @@ "start_time": "2021-11-24T02:50:04.500997+00:00", "last_update": "2021-11-24T02:50:04.679010+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26547,7 +28479,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26555,7 +28493,8 @@ "start_time": "2021-11-24T02:40:04.528901+00:00", "last_update": "2021-11-24T02:40:04.721345+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26600,7 +28539,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26608,7 +28553,8 @@ "start_time": "2021-11-24T02:30:04.720846+00:00", "last_update": "2021-11-24T02:30:05.074548+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26653,7 +28599,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26661,7 +28613,8 @@ "start_time": "2021-11-24T02:20:04.612354+00:00", "last_update": "2021-11-24T02:20:04.794415+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26706,7 +28659,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26714,7 +28673,8 @@ "start_time": "2021-11-24T02:10:04.489593+00:00", "last_update": "2021-11-24T02:10:04.713319+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26759,7 +28719,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26767,7 +28733,8 @@ "start_time": "2021-11-24T02:00:04.538137+00:00", "last_update": "2021-11-24T02:00:04.755615+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26812,7 +28779,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26820,7 +28793,8 @@ "start_time": "2021-11-24T01:50:04.546914+00:00", "last_update": "2021-11-24T01:50:04.747734+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26865,7 +28839,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26873,7 +28853,8 @@ "start_time": "2021-11-24T01:40:04.433153+00:00", "last_update": "2021-11-24T01:40:04.626096+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26918,7 +28899,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26926,7 +28913,8 @@ "start_time": "2021-11-24T01:30:04.510443+00:00", "last_update": "2021-11-24T01:30:04.692919+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26971,7 +28959,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26979,7 +28973,8 @@ "start_time": "2021-11-24T01:20:05.295062+00:00", "last_update": "2021-11-24T01:20:05.497610+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27024,7 +29019,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27032,7 +29033,8 @@ "start_time": "2021-11-24T01:10:04.688801+00:00", "last_update": "2021-11-24T01:10:04.883373+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27077,7 +29079,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27085,7 +29093,8 @@ "start_time": "2021-11-24T01:00:04.939719+00:00", "last_update": "2021-11-24T01:00:05.178464+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27130,7 +29139,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27138,7 +29153,8 @@ "start_time": "2021-11-24T00:50:04.468549+00:00", "last_update": "2021-11-24T00:50:04.701356+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27183,7 +29199,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27191,7 +29213,8 @@ "start_time": "2021-11-24T00:40:04.815652+00:00", "last_update": "2021-11-24T00:40:05.000489+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27236,7 +29259,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27244,7 +29273,8 @@ "start_time": "2021-11-24T00:30:04.598658+00:00", "last_update": "2021-11-24T00:30:04.774050+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27289,7 +29319,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27297,7 +29333,8 @@ "start_time": "2021-11-24T00:20:04.517762+00:00", "last_update": "2021-11-24T00:20:04.706307+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27342,7 +29379,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27350,7 +29393,8 @@ "start_time": "2021-11-24T00:10:04.545462+00:00", "last_update": "2021-11-24T00:10:04.727941+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27395,7 +29439,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27403,7 +29453,8 @@ "start_time": "2021-11-24T00:00:04.535371+00:00", "last_update": "2021-11-24T00:00:04.746612+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27448,7 +29499,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27456,7 +29513,8 @@ "start_time": "2021-11-23T23:50:04.643566+00:00", "last_update": "2021-11-23T23:50:04.826637+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27501,7 +29559,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27509,7 +29573,8 @@ "start_time": "2021-11-23T23:40:04.589647+00:00", "last_update": "2021-11-23T23:40:04.791146+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27554,7 +29619,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27562,7 +29633,8 @@ "start_time": "2021-11-23T23:30:04.528050+00:00", "last_update": "2021-11-23T23:30:04.734943+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27607,7 +29679,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27615,7 +29693,8 @@ "start_time": "2021-11-23T23:20:04.551632+00:00", "last_update": "2021-11-23T23:20:04.738770+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27660,7 +29739,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27668,7 +29753,8 @@ "start_time": "2021-11-23T23:10:04.450823+00:00", "last_update": "2021-11-23T23:10:04.652075+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27713,7 +29799,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27721,7 +29813,8 @@ "start_time": "2021-11-23T23:00:04.869365+00:00", "last_update": "2021-11-23T23:00:05.128497+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27766,7 +29859,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27774,7 +29873,8 @@ "start_time": "2021-11-23T22:50:04.634188+00:00", "last_update": "2021-11-23T22:50:04.810555+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27819,7 +29919,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27827,7 +29933,8 @@ "start_time": "2021-11-23T22:40:04.569522+00:00", "last_update": "2021-11-23T22:40:04.769561+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27872,7 +29979,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27880,7 +29993,8 @@ "start_time": "2021-11-23T22:30:04.434236+00:00", "last_update": "2021-11-23T22:30:04.623421+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27925,7 +30039,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27933,7 +30053,8 @@ "start_time": "2021-11-23T22:20:04.379221+00:00", "last_update": "2021-11-23T22:20:04.571849+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27978,7 +30099,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27986,7 +30113,8 @@ "start_time": "2021-11-23T22:10:04.424226+00:00", "last_update": "2021-11-23T22:10:04.606574+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28031,7 +30159,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28039,7 +30173,8 @@ "start_time": "2021-11-23T22:00:04.584191+00:00", "last_update": "2021-11-23T22:00:04.802213+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28084,7 +30219,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28092,7 +30233,8 @@ "start_time": "2021-11-23T21:50:04.332475+00:00", "last_update": "2021-11-23T21:50:04.660638+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28137,7 +30279,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28145,7 +30293,8 @@ "start_time": "2021-11-23T21:40:04.437659+00:00", "last_update": "2021-11-23T21:40:04.653196+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28190,7 +30339,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28198,7 +30353,8 @@ "start_time": "2021-11-23T21:30:04.453384+00:00", "last_update": "2021-11-23T21:30:04.654010+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28243,7 +30399,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28251,7 +30413,8 @@ "start_time": "2021-11-23T21:20:04.442566+00:00", "last_update": "2021-11-23T21:20:04.625930+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28296,7 +30459,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28304,7 +30473,8 @@ "start_time": "2021-11-23T21:10:04.532801+00:00", "last_update": "2021-11-23T21:10:04.771198+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28349,7 +30519,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28357,7 +30533,8 @@ "start_time": "2021-11-23T21:00:04.543551+00:00", "last_update": "2021-11-23T21:00:04.762114+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28402,7 +30579,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28410,7 +30593,8 @@ "start_time": "2021-11-23T20:50:04.599458+00:00", "last_update": "2021-11-23T20:50:04.810958+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28455,7 +30639,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28463,7 +30653,8 @@ "start_time": "2021-11-23T20:40:04.375137+00:00", "last_update": "2021-11-23T20:40:04.549978+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28508,7 +30699,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28516,7 +30713,8 @@ "start_time": "2021-11-23T20:30:04.725045+00:00", "last_update": "2021-11-23T20:30:04.910512+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28561,7 +30759,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28569,7 +30773,8 @@ "start_time": "2021-11-23T20:20:04.650462+00:00", "last_update": "2021-11-23T20:20:04.826445+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28614,7 +30819,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28622,7 +30833,8 @@ "start_time": "2021-11-23T20:10:04.516348+00:00", "last_update": "2021-11-23T20:10:04.854112+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28667,7 +30879,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28675,7 +30893,8 @@ "start_time": "2021-11-23T20:00:04.707833+00:00", "last_update": "2021-11-23T20:00:04.908904+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28720,7 +30939,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28728,7 +30953,8 @@ "start_time": "2021-11-23T19:50:04.421833+00:00", "last_update": "2021-11-23T19:50:04.632400+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28773,7 +30999,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28781,7 +31013,8 @@ "start_time": "2021-11-23T19:40:04.418991+00:00", "last_update": "2021-11-23T19:40:04.591359+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28826,7 +31059,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28834,7 +31073,8 @@ "start_time": "2021-11-23T19:30:04.517543+00:00", "last_update": "2021-11-23T19:30:04.705190+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28879,7 +31119,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28887,7 +31133,8 @@ "start_time": "2021-11-23T19:20:04.559188+00:00", "last_update": "2021-11-23T19:20:04.744737+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28932,7 +31179,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28940,7 +31193,8 @@ "start_time": "2021-11-23T19:10:04.590607+00:00", "last_update": "2021-11-23T19:10:04.789711+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28985,7 +31239,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28993,7 +31253,8 @@ "start_time": "2021-11-23T19:00:04.581072+00:00", "last_update": "2021-11-23T19:00:04.821969+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29038,7 +31299,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29046,7 +31313,8 @@ "start_time": "2021-11-23T18:50:04.699860+00:00", "last_update": "2021-11-23T18:50:04.931051+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29091,7 +31359,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29099,7 +31373,8 @@ "start_time": "2021-11-23T18:40:05.087681+00:00", "last_update": "2021-11-23T18:40:05.261694+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29144,7 +31419,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29152,7 +31433,8 @@ "start_time": "2021-11-23T18:30:04.418439+00:00", "last_update": "2021-11-23T18:30:04.598008+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29197,7 +31479,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29205,7 +31493,8 @@ "start_time": "2021-11-23T18:20:04.498606+00:00", "last_update": "2021-11-23T18:20:04.694717+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29250,7 +31539,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29258,7 +31553,8 @@ "start_time": "2021-11-23T18:10:04.694077+00:00", "last_update": "2021-11-23T18:10:04.877956+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29303,7 +31599,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29311,7 +31613,8 @@ "start_time": "2021-11-23T18:00:04.451190+00:00", "last_update": "2021-11-23T18:00:04.685289+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29356,7 +31659,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29364,7 +31673,8 @@ "start_time": "2021-11-23T17:50:04.409692+00:00", "last_update": "2021-11-23T17:50:04.574748+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29409,7 +31719,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29417,7 +31733,8 @@ "start_time": "2021-11-23T17:40:04.803186+00:00", "last_update": "2021-11-23T17:40:05.024504+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29462,7 +31779,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29470,7 +31793,8 @@ "start_time": "2021-11-23T17:30:04.458452+00:00", "last_update": "2021-11-23T17:30:04.643441+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29515,7 +31839,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29523,7 +31853,8 @@ "start_time": "2021-11-23T17:20:04.389008+00:00", "last_update": "2021-11-23T17:20:04.559117+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29568,7 +31899,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29576,7 +31913,8 @@ "start_time": "2021-11-23T17:10:04.429827+00:00", "last_update": "2021-11-23T17:10:04.697423+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29621,7 +31959,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29629,7 +31973,8 @@ "start_time": "2021-11-23T17:00:04.636519+00:00", "last_update": "2021-11-23T17:00:04.852019+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29674,7 +32019,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29682,7 +32033,8 @@ "start_time": "2021-11-23T16:50:04.469691+00:00", "last_update": "2021-11-23T16:50:04.638176+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29727,7 +32079,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29735,7 +32093,8 @@ "start_time": "2021-11-23T16:40:04.793124+00:00", "last_update": "2021-11-23T16:40:04.979396+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29780,7 +32139,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29788,7 +32153,8 @@ "start_time": "2021-11-23T16:30:04.511592+00:00", "last_update": "2021-11-23T16:30:04.701880+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29833,7 +32199,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29841,7 +32213,8 @@ "start_time": "2021-11-23T16:20:04.441622+00:00", "last_update": "2021-11-23T16:20:04.616568+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29886,7 +32259,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29894,7 +32273,8 @@ "start_time": "2021-11-23T16:10:04.297534+00:00", "last_update": "2021-11-23T16:10:04.488367+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29921,14 +32301,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-23T16:01:58.107788+00:00", "last_update": "2021-11-23T16:01:58.227436+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29973,7 +32360,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29981,7 +32374,8 @@ "start_time": "2021-11-23T16:00:04.725458+00:00", "last_update": "2021-11-23T16:00:04.968356+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30026,7 +32420,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30034,7 +32434,8 @@ "start_time": "2021-11-23T15:50:04.422576+00:00", "last_update": "2021-11-23T15:50:04.635788+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30079,7 +32480,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30087,7 +32494,8 @@ "start_time": "2021-11-23T15:40:04.641266+00:00", "last_update": "2021-11-23T15:40:04.882666+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30132,7 +32540,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30140,7 +32554,8 @@ "start_time": "2021-11-23T15:30:04.378826+00:00", "last_update": "2021-11-23T15:30:04.565072+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30185,7 +32600,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30193,7 +32614,8 @@ "start_time": "2021-11-23T15:20:04.559525+00:00", "last_update": "2021-11-23T15:20:04.758667+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -30238,7 +32660,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30246,7 +32674,8 @@ "start_time": "2021-11-23T15:10:04.536833+00:00", "last_update": "2021-11-23T15:10:04.726331+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30291,7 +32720,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30299,7 +32734,8 @@ "start_time": "2021-11-23T15:00:04.563670+00:00", "last_update": "2021-11-23T15:00:04.784840+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -30344,7 +32780,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30352,7 +32794,8 @@ "start_time": "2021-11-23T14:50:04.460492+00:00", "last_update": "2021-11-23T14:50:04.649701+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30397,7 +32840,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30405,7 +32854,8 @@ "start_time": "2021-11-23T14:40:04.553734+00:00", "last_update": "2021-11-23T14:40:04.854853+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30450,7 +32900,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30458,7 +32914,8 @@ "start_time": "2021-11-23T14:30:04.626953+00:00", "last_update": "2021-11-23T14:30:04.806765+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30503,7 +32960,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30511,7 +32974,8 @@ "start_time": "2021-11-23T14:20:04.478122+00:00", "last_update": "2021-11-23T14:20:04.710932+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30556,7 +33020,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30564,7 +33034,8 @@ "start_time": "2021-11-23T14:10:04.510030+00:00", "last_update": "2021-11-23T14:10:04.734683+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30609,7 +33080,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30617,7 +33094,8 @@ "start_time": "2021-11-23T14:00:04.692590+00:00", "last_update": "2021-11-23T14:00:04.913319+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30662,7 +33140,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30670,7 +33154,8 @@ "start_time": "2021-11-23T13:50:04.486524+00:00", "last_update": "2021-11-23T13:50:04.707908+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30715,7 +33200,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30723,7 +33214,8 @@ "start_time": "2021-11-23T13:40:04.695802+00:00", "last_update": "2021-11-23T13:40:04.864555+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -30768,7 +33260,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30776,7 +33274,8 @@ "start_time": "2021-11-23T13:30:04.466982+00:00", "last_update": "2021-11-23T13:30:04.645016+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30821,7 +33320,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30829,7 +33334,8 @@ "start_time": "2021-11-23T13:20:04.432215+00:00", "last_update": "2021-11-23T13:20:04.593066+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30874,7 +33380,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30882,7 +33394,8 @@ "start_time": "2021-11-23T13:10:04.377343+00:00", "last_update": "2021-11-23T13:10:04.562248+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30927,7 +33440,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30935,7 +33454,8 @@ "start_time": "2021-11-23T13:00:04.757717+00:00", "last_update": "2021-11-23T13:00:04.976383+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30980,7 +33500,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30988,7 +33514,8 @@ "start_time": "2021-11-23T12:50:04.510481+00:00", "last_update": "2021-11-23T12:50:04.694038+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31033,7 +33560,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31041,7 +33574,8 @@ "start_time": "2021-11-23T12:40:04.381615+00:00", "last_update": "2021-11-23T12:40:04.572676+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31086,7 +33620,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31094,7 +33634,8 @@ "start_time": "2021-11-23T12:30:04.503862+00:00", "last_update": "2021-11-23T12:30:04.678147+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31139,7 +33680,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31147,7 +33694,8 @@ "start_time": "2021-11-23T12:20:04.559097+00:00", "last_update": "2021-11-23T12:20:04.737203+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31192,7 +33740,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31200,7 +33754,8 @@ "start_time": "2021-11-23T12:10:04.449115+00:00", "last_update": "2021-11-23T12:10:04.625507+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31245,7 +33800,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31253,7 +33814,8 @@ "start_time": "2021-11-23T12:00:04.486243+00:00", "last_update": "2021-11-23T12:00:04.698411+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31298,7 +33860,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31306,7 +33874,8 @@ "start_time": "2021-11-23T11:50:04.723311+00:00", "last_update": "2021-11-23T11:50:04.932266+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31351,7 +33920,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31359,7 +33934,8 @@ "start_time": "2021-11-23T11:40:04.649386+00:00", "last_update": "2021-11-23T11:40:04.869518+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31404,7 +33980,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31412,7 +33994,8 @@ "start_time": "2021-11-23T11:30:04.532380+00:00", "last_update": "2021-11-23T11:30:04.711271+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31457,7 +34040,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31465,7 +34054,8 @@ "start_time": "2021-11-23T11:20:04.501966+00:00", "last_update": "2021-11-23T11:20:04.698149+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31510,7 +34100,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31518,7 +34114,8 @@ "start_time": "2021-11-23T11:10:04.480587+00:00", "last_update": "2021-11-23T11:10:04.666382+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31563,7 +34160,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31571,7 +34174,8 @@ "start_time": "2021-11-23T11:00:04.482799+00:00", "last_update": "2021-11-23T11:00:04.712377+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31616,7 +34220,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31624,7 +34234,8 @@ "start_time": "2021-11-23T10:50:04.458809+00:00", "last_update": "2021-11-23T10:50:04.633174+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31669,7 +34280,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31677,7 +34294,8 @@ "start_time": "2021-11-23T10:40:04.415844+00:00", "last_update": "2021-11-23T10:40:04.582542+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31722,7 +34340,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31730,7 +34354,8 @@ "start_time": "2021-11-23T10:30:04.376510+00:00", "last_update": "2021-11-23T10:30:04.568037+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31775,7 +34400,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31783,7 +34414,8 @@ "start_time": "2021-11-23T10:20:04.393940+00:00", "last_update": "2021-11-23T10:20:04.599562+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31828,7 +34460,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31836,7 +34474,8 @@ "start_time": "2021-11-23T10:10:04.602995+00:00", "last_update": "2021-11-23T10:10:04.792896+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31884,7 +34523,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31892,7 +34537,8 @@ "start_time": "2021-11-23T10:04:11.101928+00:00", "last_update": "2021-11-23T10:04:11.277613+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31919,14 +34565,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-23T10:03:38.156539+00:00", "last_update": "2021-11-23T10:03:52.050684+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31954,14 +34607,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-23T10:03:35.393063+00:00", "last_update": "2021-11-23T10:03:35.483063+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31988,14 +34648,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T11:46:51.227805+00:00", "last_update": "2021-11-08T11:46:51.296237+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32022,14 +34689,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T11:45:22.064287+00:00", "last_update": "2021-11-08T11:45:22.145479+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32064,7 +34738,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -32072,7 +34752,8 @@ "start_time": "2021-11-08T11:43:51.387325+00:00", "last_update": "2021-11-08T11:43:51.660572+00:00", "error": "Columns must be same length as key", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32115,14 +34796,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-11-08T11:42:59.089848+00:00", "last_update": "2021-11-08T11:43:07.483195+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32169,14 +34857,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-08T11:40:08.223207+00:00", "last_update": "2021-11-08T11:40:36.453731+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32219,14 +34914,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-08T11:39:43.558424+00:00", "last_update": "2021-11-08T11:40:06.182841+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32273,14 +34975,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-08T11:39:35.083703+00:00", "last_update": "2021-11-08T11:39:35.895469+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32308,14 +35017,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T11:36:03.228032+00:00", "last_update": "2021-11-08T11:36:03.301501+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32343,14 +35059,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-02T08:47:57.208326+00:00", "last_update": "2021-11-02T08:47:57.328639+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32378,14 +35101,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-01T00:00:08.999400+00:00", "last_update": "2021-11-01T00:00:09.211607+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32411,14 +35141,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-28T18:12:56.106520+00:00", "last_update": "2021-10-28T18:13:17.198567+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32444,14 +35181,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-28T14:18:37.228925+00:00", "last_update": "2021-10-28T14:19:06.426608+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32479,14 +35223,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-28T13:46:21.225458+00:00", "last_update": "2021-10-28T13:46:21.294035+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32537,7 +35288,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -32545,7 +35302,8 @@ "start_time": "2021-10-28T13:43:30.968141+00:00", "last_update": "2021-10-28T13:43:31.647120+00:00", "error": "file type unhandled v3io:///test/test", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32587,14 +35345,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-28T08:40:35.739139+00:00", "last_update": "2021-10-28T08:41:05.600456+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32640,14 +35405,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-21T18:14:19.099271+00:00", "last_update": "2021-10-21T18:14:46.228065+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32673,14 +35445,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-19T07:46:06.654759+00:00", "last_update": "2021-10-19T07:46:36.553501+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32706,14 +35485,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-19T07:32:37.765470+00:00", "last_update": "2021-10-19T07:32:56.606738+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32739,14 +35525,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-15T14:54:55.118884+00:00", "last_update": "2021-10-15T14:55:06.696436+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32773,14 +35566,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T19:58:01.299873+00:00", "last_update": "2021-10-13T19:58:01.374021+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32807,14 +35607,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T19:41:12.462796+00:00", "last_update": "2021-10-13T19:41:12.541077+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32840,14 +35647,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-13T19:23:24.084989+00:00", "last_update": "2021-10-13T19:23:24.472745+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32873,14 +35687,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-13T19:22:17.420518+00:00", "last_update": "2021-10-13T19:22:24.018887+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32906,14 +35727,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-13T15:55:43.092290+00:00", "last_update": "2021-10-13T15:56:04.828883+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32940,14 +35768,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T15:14:29.209667+00:00", "last_update": "2021-10-13T15:14:29.271307+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32974,14 +35809,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T14:12:55.122657+00:00", "last_update": "2021-10-13T14:12:55.188855+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33008,14 +35850,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T14:02:19.750855+00:00", "last_update": "2021-10-13T14:02:19.839795+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33041,14 +35890,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-10T10:27:23.881911+00:00", "last_update": "2021-10-10T10:27:24.616015+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33074,14 +35930,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-10T10:22:23.551995+00:00", "last_update": "2021-10-10T10:22:29.710206+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33107,14 +35970,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-10T10:22:01.460726+00:00", "last_update": "2021-10-10T10:22:06.341668+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33140,14 +36010,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-10T10:21:34.872124+00:00", "last_update": "2021-10-10T10:21:44.400075+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33183,14 +36060,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-06T14:10:00.438518+00:00", "last_update": "2021-10-06T14:10:16.259616+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33217,14 +36101,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-01T00:00:00.235989+00:00", "last_update": "2021-10-01T00:00:12.308235+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33250,14 +36141,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-30T12:03:14.421289+00:00", "last_update": "2021-09-30T12:03:33.039369+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33283,14 +36181,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-30T12:00:57.901153+00:00", "last_update": "2021-09-30T12:01:01.851605+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33316,14 +36221,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-09-17T15:08:47.936899+00:00", "last_update": "2021-09-17T15:09:07.462131+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33380,7 +36292,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33388,7 +36306,8 @@ "start_time": "2021-09-17T15:08:29.202452+00:00", "last_update": "2021-09-17T15:08:30.072691+00:00", "error": "unable to connect to account for Must provide either a connection_string or account_name with credentials!!", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33445,7 +36364,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33453,7 +36378,8 @@ "start_time": "2021-09-17T12:53:31.183995+00:00", "last_update": "2021-09-17T12:53:31.818200+00:00", "error": "file type unhandled v3io://hhhhjjjjkkkk", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33510,7 +36436,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33518,7 +36450,8 @@ "start_time": "2021-09-17T12:50:53.673923+00:00", "last_update": "2021-09-17T12:50:54.305932+00:00", "error": "file type unhandled v3io://hhhhhhh", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33575,7 +36508,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33583,7 +36522,8 @@ "start_time": "2021-09-17T12:44:47.158478+00:00", "last_update": "2021-09-17T12:44:47.738459+00:00", "error": "file type unhandled v3io://test", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33640,7 +36580,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33648,7 +36594,8 @@ "start_time": "2021-09-17T12:15:35.974230+00:00", "last_update": "2021-09-17T12:15:36.567922+00:00", "error": "file type unhandled v3io://sdadsada", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33705,7 +36652,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33713,7 +36666,8 @@ "start_time": "2021-09-17T12:14:22.653559+00:00", "last_update": "2021-09-17T12:14:23.294026+00:00", "error": "file type unhandled v3io://ss", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33770,7 +36724,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33778,7 +36738,8 @@ "start_time": "2021-09-17T12:13:17.761118+00:00", "last_update": "2021-09-17T12:13:18.502005+00:00", "error": "file type unhandled v3io://yy", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33835,7 +36796,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33843,7 +36810,8 @@ "start_time": "2021-09-17T12:12:48.401039+00:00", "last_update": "2021-09-17T12:12:49.044854+00:00", "error": "file type unhandled v3io://tt", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33900,7 +36868,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33908,7 +36882,8 @@ "start_time": "2021-09-17T12:09:10.806047+00:00", "last_update": "2021-09-17T12:09:11.364692+00:00", "error": "file type unhandled v3io://ewqewq", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33965,7 +36940,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33973,7 +36954,8 @@ "start_time": "2021-09-17T11:59:50.920646+00:00", "last_update": "2021-09-17T11:59:51.576888+00:00", "error": "file type unhandled v3io://asd", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34030,7 +37012,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34038,7 +37026,8 @@ "start_time": "2021-09-17T11:59:01.285243+00:00", "last_update": "2021-09-17T11:59:04.051728+00:00", "error": "file type unhandled s3://asd", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34095,7 +37084,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34103,7 +37098,8 @@ "start_time": "2021-09-17T11:57:57.036076+00:00", "last_update": "2021-09-17T11:57:57.905590+00:00", "error": "file type unhandled v3io://qweewqqwwwwwwww", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34129,14 +37125,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-17T11:34:04.948045+00:00", "last_update": "2021-09-17T11:34:11.649796+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34193,7 +37196,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34201,7 +37210,8 @@ "start_time": "2021-09-17T08:01:55.544559+00:00", "last_update": "2021-09-17T08:01:56.622206+00:00", "error": "unable to connect to account for Must provide either a connection_string or account_name with credentials!!", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34258,7 +37268,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34266,7 +37282,8 @@ "start_time": "2021-09-16T15:34:11.324884+00:00", "last_update": "2021-09-16T15:34:11.938806+00:00", "error": "file type unhandled v3io://asd", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34323,7 +37340,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34331,7 +37354,8 @@ "start_time": "2021-09-15T11:11:23.310455+00:00", "last_update": "2021-09-15T11:11:23.886661+00:00", "error": "file type unhandled v3io://aa", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34357,7 +37381,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34365,7 +37395,8 @@ "start_time": "2021-09-10T08:07:55.696888+00:00", "last_update": "2021-09-10T08:07:55.747261+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 08:07:55 GMT', 'Content-Length': '1026'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-vmghw\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"volume_test__name\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-vmghw\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"volume_test__name\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 08:07:55 GMT', 'Content-Length': '1026'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-vmghw\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"volume_test__name\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-vmghw\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"volume_test__name\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 0 } }, { @@ -34391,7 +37422,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34399,7 +37436,8 @@ "start_time": "2021-09-10T08:07:27.992706+00:00", "last_update": "2021-09-10T08:07:28.071778+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 08:07:28 GMT', 'Content-Length': '1026'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-d2x69\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"volume_test__name\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-d2x69\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"volume_test__name\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 08:07:28 GMT', 'Content-Length': '1026'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-d2x69\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"volume_test__name\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-d2x69\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"volume_test__name\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 0 } }, { @@ -34425,14 +37463,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-08T16:01:00.020724+00:00", "last_update": "2021-09-08T16:01:28.024926+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34458,14 +37503,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-08T15:51:02.734809+00:00", "last_update": "2021-09-08T15:51:23.296887+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34491,14 +37543,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-08T15:37:29.504427+00:00", "last_update": "2021-09-08T15:37:47.727633+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34544,14 +37603,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-07T11:42:54.171035+00:00", "last_update": "2021-09-07T11:42:56.512443+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34577,14 +37643,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-07T11:20:14.154220+00:00", "last_update": "2021-09-07T11:20:16.663883+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34610,14 +37683,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-07T09:03:37.071417+00:00", "last_update": "2021-09-07T09:04:05.569790+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34668,7 +37748,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -34677,7 +37763,8 @@ }, "start_time": "2021-09-04T08:13:13.409154+00:00", "last_update": "2021-09-04T08:13:14.808015+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34711,7 +37798,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34719,7 +37812,8 @@ "start_time": "2021-09-03T13:53:56.088502+00:00", "last_update": "2021-09-03T13:53:56.318914+00:00", "error": "Columns must be same length as key", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34746,14 +37840,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-09-03T13:53:50.030505+00:00", "last_update": "2021-09-03T13:53:50.099756+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34800,7 +37901,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34808,7 +37915,8 @@ "start_time": "2021-09-03T13:53:35.470383+00:00", "last_update": "2021-09-03T13:53:35.716754+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34835,14 +37943,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-09-03T13:52:40.749944+00:00", "last_update": "2021-09-03T13:52:40.810108+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34869,14 +37984,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-09-03T12:02:52.273993+00:00", "last_update": "2021-09-03T12:02:52.335681+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34911,7 +38033,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34919,7 +38047,8 @@ "start_time": "2021-09-03T12:02:03.774104+00:00", "last_update": "2021-09-03T12:02:03.936616+00:00", "error": "[Errno 2] No such file or directory: 'message_file'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34966,7 +38095,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34974,7 +38109,8 @@ "start_time": "2021-09-01T13:32:53.361949+00:00", "last_update": "2021-09-01T13:32:53.519516+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35000,7 +38136,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35008,7 +38150,8 @@ "start_time": "2021-08-31T19:07:10.627886+00:00", "last_update": "2021-08-31T19:07:10.683889+00:00", "artifacts": [], - "error": "cannot import from ''" + "error": "cannot import from ''", + "retry_count": 2 } }, { @@ -35034,14 +38177,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-04T06:43:00.974008+00:00", "last_update": "2021-10-04T06:43:07.566741+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35079,7 +38229,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -35088,7 +38244,8 @@ }, "start_time": "2021-08-29T19:45:14.995282+00:00", "last_update": "2021-08-29T19:45:18.516911+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35119,14 +38276,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-23T10:00:00.059030+00:00", "last_update": "2021-11-23T10:00:20.339115+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35156,14 +38320,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-23T09:58:33.718204+00:00", "last_update": "2021-11-23T09:58:49.667649+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35195,7 +38366,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35203,7 +38380,8 @@ "start_time": "2021-11-08T16:26:31.029770+00:00", "last_update": "2021-11-08T16:27:42.496061+00:00", "error": "401 received while accessing 'getting-started-tutorial-admin/artifacts/data/test_set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35238,7 +38416,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35246,7 +38430,8 @@ "start_time": "2021-11-08T16:26:21.976983+00:00", "last_update": "2021-11-08T16:28:41.537143+00:00", "error": "401 received while accessing 'getting-started-tutorial-admin/artifacts/pipeline/dd5972cb-cbc2-4998-ab0e-705dba1b307d/data/test_set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35279,7 +38464,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35287,7 +38478,8 @@ "start_time": "2021-11-08T16:24:23.377270+00:00", "last_update": "2021-11-08T16:24:23.642837+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35320,7 +38512,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35328,7 +38526,8 @@ "start_time": "2021-11-08T16:24:03.601835+00:00", "last_update": "2021-11-08T16:24:03.787381+00:00", "error": "file type unhandled source_url", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35370,7 +38569,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35378,7 +38583,8 @@ "start_time": "2021-11-08T16:21:59.747369+00:00", "last_update": "2021-11-08T16:21:59.925727+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35416,7 +38622,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35424,7 +38636,8 @@ "start_time": "2021-11-08T16:21:43.033778+00:00", "last_update": "2021-11-08T16:21:43.242064+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35451,7 +38664,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35459,7 +38678,8 @@ "start_time": "2021-11-08T16:21:00.729828+00:00", "last_update": "2021-11-08T16:21:00.772223+00:00", "artifacts": [], - "error": ".run() can only be execute on \"mlrun\" kind, recreate with function kind \"mlrun\"" + "error": ".run() can only be execute on \"mlrun\" kind, recreate with function kind \"mlrun\"", + "retry_count": 1 } }, { @@ -35495,7 +38715,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -36144,7 +39370,8 @@ "uid": "460-3", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -36181,7 +39408,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -37283,7 +40516,8 @@ "uid": "461-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -37319,7 +40553,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -37835,7 +41075,8 @@ "uid": "462-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -37868,7 +41109,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -38517,7 +41764,8 @@ "uid": "463-3", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -38548,7 +41796,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -38658,7 +41912,8 @@ "uid": "464-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -38689,7 +41944,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -39791,7 +43052,8 @@ "uid": "465-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -39820,7 +43082,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -40336,7 +43604,8 @@ "uid": "466-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -40365,7 +43634,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -40881,7 +44156,8 @@ "uid": "467-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -40910,7 +44186,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -41426,7 +44708,8 @@ "uid": "468-0", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -41455,14 +44738,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-08-31T19:47:38.497611+00:00", "last_update": "2021-08-31T19:47:53.564737+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -41493,14 +44783,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-08-29T20:05:25.859281+00:00", "last_update": "2021-08-29T20:07:09.961262+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41526,14 +44823,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-10T11:40:10.676831+00:00", "last_update": "2021-09-10T11:40:27.194590+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41559,14 +44863,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-08T12:58:23.170389+00:00", "last_update": "2021-09-08T12:58:43.526754+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41601,7 +44912,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -41609,7 +44926,8 @@ "start_time": "2021-09-06T15:18:24.118044+00:00", "last_update": "2021-09-06T15:18:24.379177+00:00", "error": "unsupported archive type in archive_url", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -41655,7 +44973,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -41663,7 +44987,8 @@ "start_time": "2021-09-06T13:47:42.720200+00:00", "last_update": "2021-09-06T13:47:42.859183+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -41709,7 +45034,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -41717,7 +45048,8 @@ "start_time": "2021-09-06T13:45:12.800502+00:00", "last_update": "2021-09-06T13:45:12.929041+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41763,14 +45095,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-09-03T11:09:10.722682+00:00", "last_update": "2021-09-03T11:09:31.085216+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -41794,14 +45133,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-11-16T07:37:26.003124+00:00", "last_update": "2021-11-16T07:37:26.003133+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41825,14 +45171,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-11-16T07:37:26.001892+00:00", "last_update": "2021-11-16T07:37:26.001899+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -41856,14 +45209,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-11-16T07:37:25.723971+00:00", "last_update": "2021-11-16T07:37:25.723978+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -41887,14 +45247,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-11-16T07:37:25.667003+00:00", "last_update": "2021-11-16T07:37:25.667009+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41938,7 +45305,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -41991,7 +45364,8 @@ "uid": "481-2", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -42015,14 +45389,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-08-29T20:28:59.571945+00:00", "last_update": "2021-08-29T20:28:59.571951+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -42046,14 +45427,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-08-29T20:28:59.571725+00:00", "last_update": "2021-08-29T20:28:59.571731+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -42091,7 +45479,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -42120,7 +45514,8 @@ "uid": "484-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -42144,14 +45539,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-08-29T20:28:11.410654+00:00", "last_update": "2021-08-29T20:28:11.410660+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -42175,14 +45577,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-08-29T20:28:11.397877+00:00", "last_update": "2021-08-29T20:28:11.397882+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -42220,7 +45629,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -42891,7 +46306,8 @@ "uid": "487-5", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -42939,7 +46355,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -44032,7 +47454,8 @@ "uid": "488-7", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -44080,7 +47503,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -45173,7 +48602,8 @@ "uid": "489-7", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -45221,7 +48651,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -46314,7 +49750,8 @@ "uid": "490-7", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -46362,7 +49799,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -47455,7 +50898,8 @@ "uid": "491-7", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -47499,7 +50943,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -47609,7 +51059,8 @@ "uid": "492-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -47649,7 +51100,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -50174,7 +53631,8 @@ "uid": "493-9", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -50219,7 +53677,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -50357,7 +53821,8 @@ "uid": "494-5", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -50409,7 +53874,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -53291,7 +56762,8 @@ "uid": "495-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -53330,7 +56802,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -53468,7 +56946,8 @@ "uid": "496-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -53519,7 +56998,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -56401,7 +59886,8 @@ "uid": "497-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -56439,7 +59925,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -56549,7 +60041,8 @@ "uid": "498-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -56573,7 +60066,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", @@ -57158,7 +60657,8 @@ "uid": "499-0", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -57203,14 +60703,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-01T00:00:00.277689+00:00", "last_update": "2021-10-01T00:00:12.345881+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -57258,7 +60765,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -57266,7 +60779,8 @@ "start_time": "2021-09-01T00:00:07.362502+00:00", "last_update": "2021-09-01T00:00:07.556686+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -57303,7 +60817,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -57311,7 +60831,8 @@ "start_time": "2021-08-31T12:28:09.838061+00:00", "last_update": "2021-08-31T12:28:10.003381+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -57347,7 +60868,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -57376,7 +60903,8 @@ "uid": "503-0", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -57412,7 +60940,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -58031,7 +61565,8 @@ "uid": "504-4", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -58078,7 +61613,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -59048,7 +62589,8 @@ "uid": "505-6", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -59095,7 +62637,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -60065,7 +63613,8 @@ "uid": "506-6", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -60112,7 +63661,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -61082,7 +64637,8 @@ "uid": "507-6", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -61117,7 +64673,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -61227,7 +64789,8 @@ "uid": "508-5", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -61274,7 +64837,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -62244,7 +65813,8 @@ "uid": "509-6", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -62278,7 +65848,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -62792,7 +66368,8 @@ "uid": "510-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -62823,7 +66400,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -62933,7 +66516,8 @@ "uid": "511-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -62960,14 +66544,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-08-30T05:19:49.379677+00:00", "last_update": "2021-08-30T05:19:49.578198+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -62999,14 +66590,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", "results": {}, "start_time": "2021-10-28T13:52:42.987115+00:00", "last_update": "2021-10-28T13:52:55.115320+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -63052,7 +66650,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -67847,7 +71451,8 @@ "uid": "514-7", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -67884,7 +71489,13 @@ "node_selector": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "results": {}, @@ -67892,7 +71503,8 @@ "last_update": "2024-10-08T14:34:12.621378+00:00", "state": "aborted", "abort_task_id": "74be3e06-56fb-4bc9-9ece-b77f7f818373", - "status_text": "aborted" + "status_text": "aborted", + "retry_count": 0 } } ] diff --git a/tests/mockServer/data/runs.json b/tests/mockServer/data/runs.json index 678aa482b9..ed49bb6a5c 100644 --- a/tests/mockServer/data/runs.json +++ b/tests/mockServer/data/runs.json @@ -24,7 +24,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -32,7 +38,8 @@ "start_time": "2021-11-08T16:24:30.312181+00:00", "last_update": "2021-11-08T16:24:30.472758+00:00", "artifacts": [], - "error": "handler dg not found in main.py" + "error": "handler dg not found in main.py", + "retry_count": 0 } }, { @@ -59,7 +66,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -67,7 +80,8 @@ "start_time": "2021-11-08T16:24:30.312181+00:00", "last_update": "2021-11-08T16:24:30.472758+00:00", "artifacts": [], - "error": "handler dg not found in main.py" + "error": "handler dg not found in main.py", + "retry_count": 2 } }, { @@ -94,7 +108,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -102,7 +122,8 @@ "start_time": "2021-11-08T16:24:30.310633+00:00", "last_update": "2021-11-08T16:24:30.473678+00:00", "artifacts": [], - "error": "handler seg not found in main.py" + "error": "handler seg not found in main.py", + "retry_count": 2 } }, { @@ -129,14 +150,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-08T16:22:18.425595+00:00", "last_update": "2021-11-08T16:23:45.047882+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -162,7 +190,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -170,7 +204,8 @@ "start_time": "2021-10-26T10:23:46.201308+00:00", "last_update": "2021-10-26T10:23:46.326428+00:00", "artifacts": [], - "error": "handler seg not found in main.py" + "error": "handler seg not found in main.py", + "retry_count": 0 } }, { @@ -196,14 +231,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-12T08:24:05.965500+00:00", "last_update": "2021-10-12T08:24:10.599070+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -229,14 +271,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-09-14T09:30:33.692216+00:00", "last_update": "2021-09-14T09:30:45.398626+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -265,14 +314,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-13T12:37:39.890790+00:00", "last_update": "2021-09-13T12:37:47.341825+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -298,7 +354,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -306,7 +368,8 @@ "start_time": "2021-09-10T11:49:26.170358+00:00", "last_update": "2021-09-10T11:49:26.249424+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:49:26 GMT', 'Content-Length': '974'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-sz7vd\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-sz7vd\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:49:26 GMT', 'Content-Length': '974'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-sz7vd\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-sz7vd\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 1 } }, { @@ -332,7 +395,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -340,7 +409,8 @@ "start_time": "2021-09-10T11:46:36.715480+00:00", "last_update": "2021-09-10T11:46:36.768280+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:46:36 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-frtb9\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-frtb9\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:46:36 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-frtb9\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-frtb9\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 2 } }, { @@ -366,7 +436,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -374,7 +450,8 @@ "start_time": "2021-09-10T11:45:54.004341+00:00", "last_update": "2021-09-10T11:45:54.059573+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:45:54 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-bk7xh\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-bk7xh\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:45:54 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-bk7xh\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-bk7xh\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 2 } }, { @@ -400,7 +477,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -408,7 +491,8 @@ "start_time": "2021-09-10T11:45:44.673524+00:00", "last_update": "2021-09-10T11:45:44.804681+00:00", "artifacts": [], - "error": "handler sef not found in main.py" + "error": "handler sef not found in main.py", + "retry_count": 1 } }, { @@ -434,7 +518,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -442,7 +532,8 @@ "start_time": "2021-09-10T11:44:47.606870+00:00", "last_update": "2021-09-10T11:44:47.678370+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:44:47 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-6wpgq\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-6wpgq\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:44:47 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-6wpgq\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-6wpgq\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 0 } }, { @@ -469,14 +560,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:58:12.581215+00:00", "last_update": "2021-09-03T13:58:12.581220+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -503,14 +601,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:58:01.150086+00:00", "last_update": "2021-09-03T13:58:01.150091+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -537,14 +642,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:57:20.120500+00:00", "last_update": "2021-09-03T13:57:20.120505+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -571,14 +683,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:51:21.205831+00:00", "last_update": "2021-09-03T13:51:21.205834+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -606,14 +725,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:51:05.027342+00:00", "last_update": "2021-09-03T13:51:05.027349+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -647,7 +773,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -655,7 +787,8 @@ "start_time": "2021-09-03T13:50:59.748610+00:00", "last_update": "2021-09-03T13:50:59.909427+00:00", "error": "[Errno 2] No such file or directory: ''", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -683,14 +816,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-09-03T13:50:01.211460+00:00", "last_update": "2021-09-03T13:50:01.211465+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -737,7 +877,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -745,7 +891,8 @@ "start_time": "2021-08-29T20:01:45.738537+00:00", "last_update": "2021-08-29T20:02:01.827946+00:00", "artifacts": [], - "error": "2021-08-29 20:01:36.582972: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib:\n2021-08-29 20:01:36.583019: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n2021-08-29 20:01:46.470042: I tensorflow/compiler/jit/xla_cpu_device.cc:41] Not creating XLA devices, tf_xla_enable_xla_devices not set\n2021-08-29 20:01:46.470263: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib:\n2021-08-29 20:01:46.470283: W tensorflow/stream_executor/cuda/cuda_driver.cc:326] failed call to cuInit: UNKNOWN ERROR (303)\n2021-08-29 20:01:46.470306: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (train-1193bacd-worker-0): /proc/driver/nvidia/version does not exist\n2021-08-29 20:01:46.518782: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\nTo enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n2021-08-29 20:01:46.518927: I tensorflow/compiler/jit/xla_gpu_device.cc:99] Not creating XLA devices, tf_xla_enable_xla_devices not set\nSome callbacks may not have access to the averaged metrics, see https://github.com/horovod/horovod/issues/2440\nTraceback (most recent call last):\n File \"/User/demos/image-classification-with-distributed-training/src-tfv2/horovod-training.py\", line 116, in \n hvd.callbacks.LearningRateWarmupCallback(warmup_epochs=5, verbose=1),\nTypeError: __init__() missing 1 required positional argument: 'initial_lr'\n" + "error": "2021-08-29 20:01:36.582972: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib:\n2021-08-29 20:01:36.583019: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n2021-08-29 20:01:46.470042: I tensorflow/compiler/jit/xla_cpu_device.cc:41] Not creating XLA devices, tf_xla_enable_xla_devices not set\n2021-08-29 20:01:46.470263: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib:\n2021-08-29 20:01:46.470283: W tensorflow/stream_executor/cuda/cuda_driver.cc:326] failed call to cuInit: UNKNOWN ERROR (303)\n2021-08-29 20:01:46.470306: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (train-1193bacd-worker-0): /proc/driver/nvidia/version does not exist\n2021-08-29 20:01:46.518782: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\nTo enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n2021-08-29 20:01:46.518927: I tensorflow/compiler/jit/xla_gpu_device.cc:99] Not creating XLA devices, tf_xla_enable_xla_devices not set\nSome callbacks may not have access to the averaged metrics, see https://github.com/horovod/horovod/issues/2440\nTraceback (most recent call last):\n File \"/User/demos/image-classification-with-distributed-training/src-tfv2/horovod-training.py\", line 116, in \n hvd.callbacks.LearningRateWarmupCallback(warmup_epochs=5, verbose=1),\nTypeError: __init__() missing 1 required positional argument: 'initial_lr'\n", + "retry_count": 1 } }, { @@ -781,7 +928,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -799,7 +952,8 @@ "uid": "20-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -830,7 +984,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -848,7 +1008,8 @@ "uid": "21-0", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -900,7 +1061,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1415,7 +1582,8 @@ "uid": "22-0", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -1451,7 +1619,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1459,7 +1633,8 @@ "start_time": "2021-11-09T15:39:58.595075+00:00", "last_update": "2021-11-09T15:39:58.910192+00:00", "error": "[Errno 2] No such file or directory: '/User/demos/customer-churn-prediction/data/pipeline/eaae138e-439a-47fa-93c6-ba0fe1dc3b79/tenured-test-set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1487,14 +1662,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-09T15:39:25.398562+00:00", "last_update": "2021-11-09T15:39:25.473487+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -1530,7 +1712,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1538,7 +1726,8 @@ "start_time": "2021-11-08T16:26:06.311262+00:00", "last_update": "2021-11-08T16:26:06.600147+00:00", "error": "[Errno 2] No such file or directory: '/User/demos/customer-churn-prediction/data/pipeline/eaae138e-439a-47fa-93c6-ba0fe1dc3b79/tenured-test-set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1566,14 +1755,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T16:25:34.779339+00:00", "last_update": "2021-11-08T16:25:34.842229+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -1620,7 +1816,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1628,7 +1830,8 @@ "start_time": "2021-11-08T16:25:23.418269+00:00", "last_update": "2021-11-08T16:25:23.647817+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -1676,7 +1879,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1684,7 +1893,8 @@ "start_time": "2021-11-08T16:25:23.359533+00:00", "last_update": "2021-11-08T16:25:23.583287+00:00", "error": "'str' object has no attribute 'as_df'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -1722,7 +1932,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1730,7 +1946,8 @@ "start_time": "2021-11-08T16:25:23.359185+00:00", "last_update": "2021-11-08T16:25:23.809551+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1768,7 +1985,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1776,7 +1999,8 @@ "start_time": "2021-11-08T16:25:23.359144+00:00", "last_update": "2021-11-08T16:25:23.584861+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -1814,7 +2038,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1822,7 +2052,8 @@ "start_time": "2021-11-08T16:25:22.232499+00:00", "last_update": "2021-11-08T16:25:22.405691+00:00", "error": "file type unhandled src", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1860,7 +2091,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1868,7 +2105,8 @@ "start_time": "2021-11-08T16:25:20.324321+00:00", "last_update": "2021-11-08T16:25:20.517116+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -1896,14 +2134,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T16:25:16.966884+00:00", "last_update": "2021-11-08T16:25:17.038745+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -1932,7 +2177,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1940,7 +2191,8 @@ "start_time": "2021-11-08T16:23:11.710713+00:00", "last_update": "2021-11-08T16:23:12.129908+00:00", "artifacts": [], - "error": ".run() can only be execute on \"mlrun\" kind, recreate with function kind \"mlrun\"" + "error": ".run() can only be execute on \"mlrun\" kind, recreate with function kind \"mlrun\"", + "retry_count": 0 } }, { @@ -1975,7 +2227,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -1983,7 +2241,8 @@ "start_time": "2021-09-16T08:00:05.727520+00:00", "last_update": "2021-09-16T08:00:06.112908+00:00", "error": "[Errno 2] No such file or directory: '/User/demos/customer-churn-prediction/data/pipeline/eaae138e-439a-47fa-93c6-ba0fe1dc3b79/test_set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2040,7 +2299,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2048,7 +2313,8 @@ "start_time": "2021-09-15T13:44:33.718770+00:00", "last_update": "2021-09-15T13:44:34.287133+00:00", "error": "file type unhandled v3io://test/test", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2085,7 +2351,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2093,7 +2365,8 @@ "start_time": "2021-09-03T14:02:21.992537+00:00", "last_update": "2021-09-03T14:02:22.143202+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2130,7 +2403,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2138,7 +2417,8 @@ "start_time": "2021-09-03T14:02:14.813451+00:00", "last_update": "2021-09-03T14:02:14.961434+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -2185,7 +2465,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2193,7 +2479,8 @@ "start_time": "2021-09-03T14:02:06.911466+00:00", "last_update": "2021-09-03T14:02:07.047657+00:00", "error": "'str' object has no attribute 'as_df'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -2230,7 +2517,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2238,7 +2531,8 @@ "start_time": "2021-09-03T14:01:57.400446+00:00", "last_update": "2021-09-03T14:01:57.593225+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -2284,7 +2578,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2292,7 +2592,8 @@ "start_time": "2021-09-03T14:01:41.039404+00:00", "last_update": "2021-09-03T14:01:41.302859+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2329,7 +2630,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2337,7 +2644,8 @@ "start_time": "2021-09-03T14:01:25.207451+00:00", "last_update": "2021-09-03T14:01:25.372461+00:00", "error": "file type unhandled src", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2384,7 +2692,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2392,7 +2706,8 @@ "start_time": "2021-09-03T13:56:21.373049+00:00", "last_update": "2021-09-03T13:56:21.517709+00:00", "error": "'str' object has no attribute 'as_df'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -2429,7 +2744,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2437,7 +2758,8 @@ "start_time": "2021-09-03T13:56:21.206337+00:00", "last_update": "2021-09-03T13:56:21.342459+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2474,7 +2796,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2482,7 +2810,8 @@ "start_time": "2021-09-03T13:56:19.700627+00:00", "last_update": "2021-09-03T13:56:19.856594+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -2528,7 +2857,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2536,7 +2871,8 @@ "start_time": "2021-09-03T13:56:19.515710+00:00", "last_update": "2021-09-03T13:56:19.665883+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2573,7 +2909,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2581,7 +2923,8 @@ "start_time": "2021-09-03T13:56:16.478536+00:00", "last_update": "2021-09-03T13:56:16.600809+00:00", "error": "file type unhandled src", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -2618,7 +2961,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -2626,7 +2975,8 @@ "start_time": "2021-09-03T13:55:42.511622+00:00", "last_update": "2021-09-03T13:55:42.712944+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -2663,7 +3013,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -2754,7 +3110,8 @@ "uid": "49-4", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -2791,7 +3148,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -3615,7 +3978,8 @@ "uid": "50-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -3678,7 +4042,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -5847,7 +6217,8 @@ "uid": "51-6", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -5882,7 +6253,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -6007,7 +6384,8 @@ "uid": "52-5", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -6058,7 +6436,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -9587,7 +9971,8 @@ "uid": "53-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -9625,7 +10010,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -12235,7 +12626,8 @@ "uid": "54-4", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -12267,7 +12659,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -14877,7 +15275,8 @@ "uid": "55-4", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -14922,7 +15321,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -14930,7 +15335,8 @@ "start_time": "2021-11-25T15:20:04.626994+00:00", "last_update": "2021-11-25T15:20:04.869705+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -14975,7 +15381,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -14983,7 +15395,8 @@ "start_time": "2021-11-25T15:10:04.547356+00:00", "last_update": "2021-11-25T15:10:04.740772+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15028,7 +15441,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15036,7 +15455,8 @@ "start_time": "2021-11-25T15:00:04.530198+00:00", "last_update": "2021-11-25T15:00:04.778945+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15081,7 +15501,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15089,7 +15515,8 @@ "start_time": "2021-11-25T14:50:04.689049+00:00", "last_update": "2021-11-25T14:50:04.876507+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15134,7 +15561,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15142,7 +15575,8 @@ "start_time": "2021-11-25T14:40:04.591290+00:00", "last_update": "2021-11-25T14:40:04.779383+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15187,7 +15621,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15195,7 +15635,8 @@ "start_time": "2021-11-25T14:30:04.478111+00:00", "last_update": "2021-11-25T14:30:04.671986+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15240,7 +15681,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15248,7 +15695,8 @@ "start_time": "2021-11-25T14:20:04.413115+00:00", "last_update": "2021-11-25T14:20:04.602205+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15293,7 +15741,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15301,7 +15755,8 @@ "start_time": "2021-11-25T14:10:04.748113+00:00", "last_update": "2021-11-25T14:10:04.936987+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15346,7 +15801,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15354,7 +15815,8 @@ "start_time": "2021-11-25T14:00:04.499287+00:00", "last_update": "2021-11-25T14:00:04.748608+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15399,7 +15861,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15407,7 +15875,8 @@ "start_time": "2021-11-25T13:50:04.460226+00:00", "last_update": "2021-11-25T13:50:04.663531+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15452,7 +15921,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15460,7 +15935,8 @@ "start_time": "2021-11-25T13:40:04.616903+00:00", "last_update": "2021-11-25T13:40:05.070431+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15505,7 +15981,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15513,7 +15995,8 @@ "start_time": "2021-11-25T13:30:04.482084+00:00", "last_update": "2021-11-25T13:30:04.682436+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15558,7 +16041,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15566,7 +16055,8 @@ "start_time": "2021-11-25T13:20:04.619182+00:00", "last_update": "2021-11-25T13:20:04.821367+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15611,7 +16101,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15619,7 +16115,8 @@ "start_time": "2021-11-25T13:10:04.530025+00:00", "last_update": "2021-11-25T13:10:04.725068+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15664,7 +16161,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15672,7 +16175,8 @@ "start_time": "2021-11-25T13:00:04.554031+00:00", "last_update": "2021-11-25T13:00:04.800899+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15717,7 +16221,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15725,7 +16235,8 @@ "start_time": "2021-11-25T12:50:04.498226+00:00", "last_update": "2021-11-25T12:50:04.692993+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15770,7 +16281,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15778,7 +16295,8 @@ "start_time": "2021-11-25T12:40:04.664771+00:00", "last_update": "2021-11-25T12:40:04.859887+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -15823,7 +16341,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15831,7 +16355,8 @@ "start_time": "2021-11-25T12:30:04.506004+00:00", "last_update": "2021-11-25T12:30:04.697277+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15876,7 +16401,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15884,7 +16415,8 @@ "start_time": "2021-11-25T12:20:04.678686+00:00", "last_update": "2021-11-25T12:20:04.872209+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -15929,7 +16461,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15937,7 +16475,8 @@ "start_time": "2021-11-25T12:10:04.672087+00:00", "last_update": "2021-11-25T12:10:04.889989+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -15982,7 +16521,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -15990,7 +16535,8 @@ "start_time": "2021-11-25T12:00:04.755738+00:00", "last_update": "2021-11-25T12:00:05.093911+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16035,7 +16581,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16043,7 +16595,8 @@ "start_time": "2021-11-25T11:50:04.480850+00:00", "last_update": "2021-11-25T11:50:04.677429+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16088,7 +16641,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16096,7 +16655,8 @@ "start_time": "2021-11-25T11:40:04.602256+00:00", "last_update": "2021-11-25T11:40:04.850283+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16141,7 +16701,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16149,7 +16715,8 @@ "start_time": "2021-11-25T11:30:04.426377+00:00", "last_update": "2021-11-25T11:30:04.636503+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16194,7 +16761,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16202,7 +16775,8 @@ "start_time": "2021-11-25T11:20:04.516140+00:00", "last_update": "2021-11-25T11:20:04.735509+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16247,7 +16821,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16255,7 +16835,8 @@ "start_time": "2021-11-25T11:10:04.472037+00:00", "last_update": "2021-11-25T11:10:04.664942+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16300,7 +16881,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16308,7 +16895,8 @@ "start_time": "2021-11-25T11:00:04.657896+00:00", "last_update": "2021-11-25T11:00:04.883672+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16353,7 +16941,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16361,7 +16955,8 @@ "start_time": "2021-11-25T10:50:04.647522+00:00", "last_update": "2021-11-25T10:50:04.836197+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16406,7 +17001,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16414,7 +17015,8 @@ "start_time": "2021-11-25T10:40:04.569781+00:00", "last_update": "2021-11-25T10:40:04.770749+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16459,7 +17061,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16467,7 +17075,8 @@ "start_time": "2021-11-25T10:30:04.676500+00:00", "last_update": "2021-11-25T10:30:04.860678+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16512,7 +17121,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16520,7 +17135,8 @@ "start_time": "2021-11-25T10:20:04.709992+00:00", "last_update": "2021-11-25T10:20:04.906660+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16565,7 +17181,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16573,7 +17195,8 @@ "start_time": "2021-11-25T10:10:04.654881+00:00", "last_update": "2021-11-25T10:10:04.877279+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16618,7 +17241,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16626,7 +17255,8 @@ "start_time": "2021-11-25T10:00:04.655647+00:00", "last_update": "2021-11-25T10:00:04.922516+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16671,7 +17301,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16679,7 +17315,8 @@ "start_time": "2021-11-25T09:50:05.301473+00:00", "last_update": "2021-11-25T09:50:05.506318+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -16724,7 +17361,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16732,7 +17375,8 @@ "start_time": "2021-11-25T09:40:04.688485+00:00", "last_update": "2021-11-25T09:40:04.885575+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -16777,7 +17421,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16785,7 +17435,8 @@ "start_time": "2021-11-25T09:30:04.526432+00:00", "last_update": "2021-11-25T09:30:04.714181+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16830,7 +17481,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16838,7 +17495,8 @@ "start_time": "2021-11-25T09:20:04.628475+00:00", "last_update": "2021-11-25T09:20:04.872881+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16883,7 +17541,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16891,7 +17555,8 @@ "start_time": "2021-11-25T09:10:04.450469+00:00", "last_update": "2021-11-25T09:10:04.777839+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -16936,7 +17601,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16944,7 +17615,8 @@ "start_time": "2021-11-25T09:00:04.766381+00:00", "last_update": "2021-11-25T09:00:05.025565+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -16989,7 +17661,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -16997,7 +17675,8 @@ "start_time": "2021-11-25T08:50:04.418181+00:00", "last_update": "2021-11-25T08:50:04.595812+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17042,7 +17721,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17050,7 +17735,8 @@ "start_time": "2021-11-25T08:40:04.569381+00:00", "last_update": "2021-11-25T08:40:04.759896+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17095,7 +17781,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17103,7 +17795,8 @@ "start_time": "2021-11-25T08:30:04.600599+00:00", "last_update": "2021-11-25T08:30:04.848873+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17148,7 +17841,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17156,7 +17855,8 @@ "start_time": "2021-11-25T08:20:04.519720+00:00", "last_update": "2021-11-25T08:20:04.819565+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17201,7 +17901,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17209,7 +17915,8 @@ "start_time": "2021-11-25T08:10:04.578285+00:00", "last_update": "2021-11-25T08:10:04.758011+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17254,7 +17961,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17262,7 +17975,8 @@ "start_time": "2021-11-25T08:00:04.433436+00:00", "last_update": "2021-11-25T08:00:04.694042+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17307,7 +18021,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17315,7 +18035,8 @@ "start_time": "2021-11-25T07:50:04.643860+00:00", "last_update": "2021-11-25T07:50:04.894175+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17360,7 +18081,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17368,7 +18095,8 @@ "start_time": "2021-11-25T07:40:04.621111+00:00", "last_update": "2021-11-25T07:40:04.847086+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17413,7 +18141,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17421,7 +18155,8 @@ "start_time": "2021-11-25T07:30:04.433519+00:00", "last_update": "2021-11-25T07:30:04.623295+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17466,7 +18201,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17474,7 +18215,8 @@ "start_time": "2021-11-25T07:20:04.851092+00:00", "last_update": "2021-11-25T07:20:05.072058+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17519,7 +18261,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17527,7 +18275,8 @@ "start_time": "2021-11-25T07:10:04.701725+00:00", "last_update": "2021-11-25T07:10:04.891876+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17572,7 +18321,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17580,7 +18335,8 @@ "start_time": "2021-11-25T07:00:04.730707+00:00", "last_update": "2021-11-25T07:00:04.959567+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17625,7 +18381,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17633,7 +18395,8 @@ "start_time": "2021-11-25T06:50:04.389233+00:00", "last_update": "2021-11-25T06:50:04.570853+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17678,7 +18441,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17686,7 +18455,8 @@ "start_time": "2021-11-25T06:40:04.779848+00:00", "last_update": "2021-11-25T06:40:04.993553+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17731,7 +18501,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17739,7 +18515,8 @@ "start_time": "2021-11-25T06:30:04.427263+00:00", "last_update": "2021-11-25T06:30:04.614687+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17784,7 +18561,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17792,7 +18575,8 @@ "start_time": "2021-11-25T06:20:04.434939+00:00", "last_update": "2021-11-25T06:20:04.618174+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -17837,7 +18621,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17845,7 +18635,8 @@ "start_time": "2021-11-25T06:10:04.633692+00:00", "last_update": "2021-11-25T06:10:04.845108+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -17890,7 +18681,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17898,7 +18695,8 @@ "start_time": "2021-11-25T06:00:04.609640+00:00", "last_update": "2021-11-25T06:00:04.912946+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17943,7 +18741,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -17951,7 +18755,8 @@ "start_time": "2021-11-25T05:50:04.449949+00:00", "last_update": "2021-11-25T05:50:04.635722+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -17996,7 +18801,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18004,7 +18815,8 @@ "start_time": "2021-11-25T05:40:04.515533+00:00", "last_update": "2021-11-25T05:40:04.736425+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18049,7 +18861,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18057,7 +18875,8 @@ "start_time": "2021-11-25T05:30:04.577631+00:00", "last_update": "2021-11-25T05:30:04.863501+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18102,7 +18921,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18110,7 +18935,8 @@ "start_time": "2021-11-25T05:20:04.455804+00:00", "last_update": "2021-11-25T05:20:04.634993+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18155,7 +18981,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18163,7 +18995,8 @@ "start_time": "2021-11-25T05:10:04.414843+00:00", "last_update": "2021-11-25T05:10:04.629374+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18208,7 +19041,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18216,7 +19055,8 @@ "start_time": "2021-11-25T05:00:04.813068+00:00", "last_update": "2021-11-25T05:00:05.113562+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18261,7 +19101,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18269,7 +19115,8 @@ "start_time": "2021-11-25T04:50:04.587135+00:00", "last_update": "2021-11-25T04:50:04.779001+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18314,7 +19161,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18322,7 +19175,8 @@ "start_time": "2021-11-25T04:40:04.432340+00:00", "last_update": "2021-11-25T04:40:04.693033+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18367,7 +19221,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18375,7 +19235,8 @@ "start_time": "2021-11-25T04:30:04.785460+00:00", "last_update": "2021-11-25T04:30:04.974252+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18420,7 +19281,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18428,7 +19295,8 @@ "start_time": "2021-11-25T04:20:04.487176+00:00", "last_update": "2021-11-25T04:20:04.689088+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18473,7 +19341,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18481,7 +19355,8 @@ "start_time": "2021-11-25T04:10:04.525230+00:00", "last_update": "2021-11-25T04:10:04.804950+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18526,7 +19401,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18534,7 +19415,8 @@ "start_time": "2021-11-25T04:00:04.434934+00:00", "last_update": "2021-11-25T04:00:04.684001+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18579,7 +19461,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18587,7 +19475,8 @@ "start_time": "2021-11-25T03:50:04.404080+00:00", "last_update": "2021-11-25T03:50:04.721225+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18632,7 +19521,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18640,7 +19535,8 @@ "start_time": "2021-11-25T03:40:04.494475+00:00", "last_update": "2021-11-25T03:40:04.780123+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18685,7 +19581,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18693,7 +19595,8 @@ "start_time": "2021-11-25T03:30:04.696343+00:00", "last_update": "2021-11-25T03:30:04.898417+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18738,7 +19641,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18746,7 +19655,8 @@ "start_time": "2021-11-25T03:20:04.805759+00:00", "last_update": "2021-11-25T03:20:04.984463+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18791,7 +19701,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18799,7 +19715,8 @@ "start_time": "2021-11-25T03:10:04.538969+00:00", "last_update": "2021-11-25T03:10:04.807798+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -18844,7 +19761,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18852,7 +19775,8 @@ "start_time": "2021-11-25T03:00:04.573902+00:00", "last_update": "2021-11-25T03:00:04.835497+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -18897,7 +19821,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18905,7 +19835,8 @@ "start_time": "2021-11-25T02:50:04.776007+00:00", "last_update": "2021-11-25T02:50:04.956215+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -18950,7 +19881,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -18958,7 +19895,8 @@ "start_time": "2021-11-25T02:40:04.477586+00:00", "last_update": "2021-11-25T02:40:04.665052+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19003,7 +19941,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19011,7 +19955,8 @@ "start_time": "2021-11-25T02:30:04.474322+00:00", "last_update": "2021-11-25T02:30:04.663125+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19056,7 +20001,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19064,7 +20015,8 @@ "start_time": "2021-11-25T02:20:04.518030+00:00", "last_update": "2021-11-25T02:20:04.854487+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19109,7 +20061,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19117,7 +20075,8 @@ "start_time": "2021-11-25T02:10:04.644281+00:00", "last_update": "2021-11-25T02:10:04.827435+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19162,7 +20121,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19170,7 +20135,8 @@ "start_time": "2021-11-25T02:00:04.631916+00:00", "last_update": "2021-11-25T02:00:04.879130+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19215,7 +20181,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19223,7 +20195,8 @@ "start_time": "2021-11-25T01:50:04.616606+00:00", "last_update": "2021-11-25T01:50:04.799437+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19268,7 +20241,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19276,7 +20255,8 @@ "start_time": "2021-11-25T01:40:04.559437+00:00", "last_update": "2021-11-25T01:40:04.750553+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19321,7 +20301,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19329,7 +20315,8 @@ "start_time": "2021-11-25T01:30:04.941823+00:00", "last_update": "2021-11-25T01:30:05.134506+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19374,7 +20361,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19382,7 +20375,8 @@ "start_time": "2021-11-25T01:20:04.596188+00:00", "last_update": "2021-11-25T01:20:04.782960+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19427,7 +20421,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19435,7 +20435,8 @@ "start_time": "2021-11-25T01:10:04.491352+00:00", "last_update": "2021-11-25T01:10:04.667277+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19480,7 +20481,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19488,7 +20495,8 @@ "start_time": "2021-11-25T01:00:04.644596+00:00", "last_update": "2021-11-25T01:00:04.873300+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19533,7 +20541,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19541,7 +20555,8 @@ "start_time": "2021-11-25T00:50:04.982616+00:00", "last_update": "2021-11-25T00:50:05.168071+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19586,7 +20601,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19594,7 +20615,8 @@ "start_time": "2021-11-25T00:40:04.603050+00:00", "last_update": "2021-11-25T00:40:04.891375+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19639,7 +20661,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19647,7 +20675,8 @@ "start_time": "2021-11-25T00:30:04.551138+00:00", "last_update": "2021-11-25T00:30:04.740014+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19692,7 +20721,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19700,7 +20735,8 @@ "start_time": "2021-11-25T00:20:04.463810+00:00", "last_update": "2021-11-25T00:20:04.814736+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19745,7 +20781,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19753,7 +20795,8 @@ "start_time": "2021-11-25T00:10:04.738628+00:00", "last_update": "2021-11-25T00:10:05.017899+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -19798,7 +20841,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19806,7 +20855,8 @@ "start_time": "2021-11-25T00:00:04.544586+00:00", "last_update": "2021-11-25T00:00:05.005375+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19851,7 +20901,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19859,7 +20915,8 @@ "start_time": "2021-11-24T23:50:04.516034+00:00", "last_update": "2021-11-24T23:50:04.708996+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -19904,7 +20961,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19912,7 +20975,8 @@ "start_time": "2021-11-24T23:40:04.527184+00:00", "last_update": "2021-11-24T23:40:04.794158+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -19957,7 +21021,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -19965,7 +21035,8 @@ "start_time": "2021-11-24T23:30:04.532170+00:00", "last_update": "2021-11-24T23:30:04.726453+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -20010,7 +21081,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20018,7 +21095,8 @@ "start_time": "2021-11-24T23:20:04.469606+00:00", "last_update": "2021-11-24T23:20:04.756696+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20063,7 +21141,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20071,7 +21155,8 @@ "start_time": "2021-11-24T23:10:04.438960+00:00", "last_update": "2021-11-24T23:10:04.654338+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20116,7 +21201,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20124,7 +21215,8 @@ "start_time": "2021-11-24T23:00:04.699017+00:00", "last_update": "2021-11-24T23:00:05.044694+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20169,7 +21261,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20177,7 +21275,8 @@ "start_time": "2021-11-24T22:50:04.479638+00:00", "last_update": "2021-11-24T22:50:04.668838+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20222,7 +21321,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20230,7 +21335,8 @@ "start_time": "2021-11-24T22:40:04.504226+00:00", "last_update": "2021-11-24T22:40:04.695845+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20275,7 +21381,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20283,7 +21395,8 @@ "start_time": "2021-11-24T22:30:04.458818+00:00", "last_update": "2021-11-24T22:30:04.711903+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20328,7 +21441,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20336,7 +21455,8 @@ "start_time": "2021-11-24T22:20:04.418897+00:00", "last_update": "2021-11-24T22:20:04.607711+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20381,7 +21501,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20389,7 +21515,8 @@ "start_time": "2021-11-24T22:10:04.538668+00:00", "last_update": "2021-11-24T22:10:04.734232+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20434,7 +21561,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20442,7 +21575,8 @@ "start_time": "2021-11-24T22:00:04.539921+00:00", "last_update": "2021-11-24T22:00:04.781730+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -20487,7 +21621,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20495,7 +21635,8 @@ "start_time": "2021-11-24T21:50:04.510394+00:00", "last_update": "2021-11-24T21:50:04.691104+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20540,7 +21681,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20548,7 +21695,8 @@ "start_time": "2021-11-24T21:40:04.550718+00:00", "last_update": "2021-11-24T21:40:04.749227+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20593,7 +21741,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20601,7 +21755,8 @@ "start_time": "2021-11-24T21:30:04.409693+00:00", "last_update": "2021-11-24T21:30:04.598307+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20646,7 +21801,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20654,7 +21815,8 @@ "start_time": "2021-11-24T21:20:04.621030+00:00", "last_update": "2021-11-24T21:20:04.810078+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -20699,7 +21861,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20707,7 +21875,8 @@ "start_time": "2021-11-24T21:10:04.375332+00:00", "last_update": "2021-11-24T21:10:04.626326+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -20752,7 +21921,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20760,7 +21935,8 @@ "start_time": "2021-11-24T21:00:04.870989+00:00", "last_update": "2021-11-24T21:00:05.112089+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20805,7 +21981,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20813,7 +21995,8 @@ "start_time": "2021-11-24T20:50:04.507278+00:00", "last_update": "2021-11-24T20:50:04.686896+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20858,7 +22041,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20866,7 +22055,8 @@ "start_time": "2021-11-24T20:40:04.546515+00:00", "last_update": "2021-11-24T20:40:04.731933+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -20911,7 +22101,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20919,7 +22115,8 @@ "start_time": "2021-11-24T20:30:04.298374+00:00", "last_update": "2021-11-24T20:30:04.511135+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -20964,7 +22161,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -20972,7 +22175,8 @@ "start_time": "2021-11-24T20:20:04.870619+00:00", "last_update": "2021-11-24T20:20:05.159143+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21017,7 +22221,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21025,7 +22235,8 @@ "start_time": "2021-11-24T20:10:04.611475+00:00", "last_update": "2021-11-24T20:10:04.839482+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21070,7 +22281,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21078,7 +22295,8 @@ "start_time": "2021-11-24T20:00:04.475649+00:00", "last_update": "2021-11-24T20:00:04.795051+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21123,7 +22341,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21131,7 +22355,8 @@ "start_time": "2021-11-24T19:50:04.568253+00:00", "last_update": "2021-11-24T19:50:04.759309+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21176,7 +22401,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21184,7 +22415,8 @@ "start_time": "2021-11-24T19:40:04.520061+00:00", "last_update": "2021-11-24T19:40:04.722499+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21229,7 +22461,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21237,7 +22475,8 @@ "start_time": "2021-11-24T19:30:04.429974+00:00", "last_update": "2021-11-24T19:30:04.643339+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21282,7 +22521,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21290,7 +22535,8 @@ "start_time": "2021-11-24T19:20:04.682369+00:00", "last_update": "2021-11-24T19:20:04.987412+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21335,7 +22581,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21343,7 +22595,8 @@ "start_time": "2021-11-24T19:10:04.798406+00:00", "last_update": "2021-11-24T19:10:04.987420+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21388,7 +22641,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21396,7 +22655,8 @@ "start_time": "2021-11-24T19:00:04.611443+00:00", "last_update": "2021-11-24T19:00:04.904232+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -21441,7 +22701,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21449,7 +22715,8 @@ "start_time": "2021-11-24T18:50:04.615771+00:00", "last_update": "2021-11-24T18:50:04.798803+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21494,7 +22761,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21502,7 +22775,8 @@ "start_time": "2021-11-24T18:40:04.599586+00:00", "last_update": "2021-11-24T18:40:04.795373+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21547,7 +22821,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21555,7 +22835,8 @@ "start_time": "2021-11-24T18:30:04.433271+00:00", "last_update": "2021-11-24T18:30:04.641423+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21600,7 +22881,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21608,7 +22895,8 @@ "start_time": "2021-11-24T18:20:04.349454+00:00", "last_update": "2021-11-24T18:20:04.527202+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21653,7 +22941,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21661,7 +22955,8 @@ "start_time": "2021-11-24T18:10:04.801067+00:00", "last_update": "2021-11-24T18:10:05.109504+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21706,7 +23001,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21714,7 +23015,8 @@ "start_time": "2021-11-24T18:00:04.470012+00:00", "last_update": "2021-11-24T18:00:04.699333+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21759,7 +23061,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21767,7 +23075,8 @@ "start_time": "2021-11-24T17:50:04.767415+00:00", "last_update": "2021-11-24T17:50:04.958676+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21812,7 +23121,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21820,7 +23135,8 @@ "start_time": "2021-11-24T17:40:04.565225+00:00", "last_update": "2021-11-24T17:40:04.758722+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -21865,7 +23181,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21873,7 +23195,8 @@ "start_time": "2021-11-24T17:30:04.542465+00:00", "last_update": "2021-11-24T17:30:04.726922+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21918,7 +23241,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21926,7 +23255,8 @@ "start_time": "2021-11-24T17:20:04.558157+00:00", "last_update": "2021-11-24T17:20:04.747969+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -21971,7 +23301,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -21979,7 +23315,8 @@ "start_time": "2021-11-24T17:10:04.510999+00:00", "last_update": "2021-11-24T17:10:04.741880+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22024,7 +23361,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22032,7 +23375,8 @@ "start_time": "2021-11-24T17:00:04.637790+00:00", "last_update": "2021-11-24T17:00:04.914986+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22077,7 +23421,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22085,7 +23435,8 @@ "start_time": "2021-11-24T16:50:04.532151+00:00", "last_update": "2021-11-24T16:50:04.707283+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22130,7 +23481,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22138,7 +23495,8 @@ "start_time": "2021-11-24T16:40:04.654448+00:00", "last_update": "2021-11-24T16:40:04.857622+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22183,7 +23541,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22191,7 +23555,8 @@ "start_time": "2021-11-24T16:30:04.726833+00:00", "last_update": "2021-11-24T16:30:04.915715+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22236,7 +23601,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22244,7 +23615,8 @@ "start_time": "2021-11-24T16:20:04.765431+00:00", "last_update": "2021-11-24T16:20:04.995627+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22289,7 +23661,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22297,7 +23675,8 @@ "start_time": "2021-11-24T16:10:04.475159+00:00", "last_update": "2021-11-24T16:10:04.707052+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22342,7 +23721,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22350,7 +23735,8 @@ "start_time": "2021-11-24T16:00:04.513842+00:00", "last_update": "2021-11-24T16:00:04.798010+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22395,7 +23781,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22403,7 +23795,8 @@ "start_time": "2021-11-24T15:50:04.436252+00:00", "last_update": "2021-11-24T15:50:04.625205+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -22448,7 +23841,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22456,7 +23855,8 @@ "start_time": "2021-11-24T15:40:04.481903+00:00", "last_update": "2021-11-24T15:40:04.663438+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22501,7 +23901,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22509,7 +23915,8 @@ "start_time": "2021-11-24T15:30:04.446758+00:00", "last_update": "2021-11-24T15:30:04.620499+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -22554,7 +23961,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22562,7 +23975,8 @@ "start_time": "2021-11-24T15:20:04.612123+00:00", "last_update": "2021-11-24T15:20:04.796937+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22607,7 +24021,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22615,7 +24035,8 @@ "start_time": "2021-11-24T15:10:04.476532+00:00", "last_update": "2021-11-24T15:10:04.690365+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22660,7 +24081,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22668,7 +24095,8 @@ "start_time": "2021-11-24T15:00:04.661578+00:00", "last_update": "2021-11-24T15:00:04.888075+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22713,7 +24141,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22721,7 +24155,8 @@ "start_time": "2021-11-24T14:50:04.475653+00:00", "last_update": "2021-11-24T14:50:04.661629+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -22766,7 +24201,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22774,7 +24215,8 @@ "start_time": "2021-11-24T14:40:04.698078+00:00", "last_update": "2021-11-24T14:40:04.874743+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -22819,7 +24261,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22827,7 +24275,8 @@ "start_time": "2021-11-24T14:30:04.539611+00:00", "last_update": "2021-11-24T14:30:04.795622+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -22872,7 +24321,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22880,7 +24335,8 @@ "start_time": "2021-11-24T14:20:04.446140+00:00", "last_update": "2021-11-24T14:20:04.626509+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22925,7 +24381,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22933,7 +24395,8 @@ "start_time": "2021-11-24T14:10:04.852408+00:00", "last_update": "2021-11-24T14:10:05.035730+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -22978,7 +24441,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -22986,7 +24455,8 @@ "start_time": "2021-11-24T14:00:04.645034+00:00", "last_update": "2021-11-24T14:00:04.878150+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23031,7 +24501,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23039,7 +24515,8 @@ "start_time": "2021-11-24T13:50:04.477657+00:00", "last_update": "2021-11-24T13:50:04.662831+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23084,7 +24561,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23092,7 +24575,8 @@ "start_time": "2021-11-24T13:40:04.670473+00:00", "last_update": "2021-11-24T13:40:04.861574+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23137,7 +24621,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23145,7 +24635,8 @@ "start_time": "2021-11-24T13:30:04.495716+00:00", "last_update": "2021-11-24T13:30:04.694276+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23190,7 +24681,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23198,7 +24695,8 @@ "start_time": "2021-11-24T13:20:04.449564+00:00", "last_update": "2021-11-24T13:20:04.665086+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23243,7 +24741,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23251,7 +24755,8 @@ "start_time": "2021-11-24T13:10:04.511729+00:00", "last_update": "2021-11-24T13:10:04.694280+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23296,7 +24801,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23304,7 +24815,8 @@ "start_time": "2021-11-24T13:00:04.465753+00:00", "last_update": "2021-11-24T13:00:04.702928+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23349,7 +24861,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23357,7 +24875,8 @@ "start_time": "2021-11-24T12:50:04.505712+00:00", "last_update": "2021-11-24T12:50:04.716717+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23402,7 +24921,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23410,7 +24935,8 @@ "start_time": "2021-11-24T12:40:04.529680+00:00", "last_update": "2021-11-24T12:40:04.723592+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23455,7 +24981,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23463,7 +24995,8 @@ "start_time": "2021-11-24T12:30:04.591878+00:00", "last_update": "2021-11-24T12:30:04.767677+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23508,7 +25041,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23516,7 +25055,8 @@ "start_time": "2021-11-24T12:20:04.506881+00:00", "last_update": "2021-11-24T12:20:04.707187+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23561,7 +25101,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23569,7 +25115,8 @@ "start_time": "2021-11-24T12:10:04.455195+00:00", "last_update": "2021-11-24T12:10:04.662142+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23614,7 +25161,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23622,7 +25175,8 @@ "start_time": "2021-11-24T12:00:04.474861+00:00", "last_update": "2021-11-24T12:00:04.712058+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23667,7 +25221,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23675,7 +25235,8 @@ "start_time": "2021-11-24T11:50:04.465545+00:00", "last_update": "2021-11-24T11:50:04.643853+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23720,7 +25281,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23728,7 +25295,8 @@ "start_time": "2021-11-24T11:40:04.518707+00:00", "last_update": "2021-11-24T11:40:04.714892+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23773,7 +25341,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23781,7 +25355,8 @@ "start_time": "2021-11-24T11:30:04.439386+00:00", "last_update": "2021-11-24T11:30:04.606311+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -23826,7 +25401,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23834,7 +25415,8 @@ "start_time": "2021-11-24T11:20:04.553954+00:00", "last_update": "2021-11-24T11:20:04.741887+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23879,7 +25461,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23887,7 +25475,8 @@ "start_time": "2021-11-24T11:10:04.512320+00:00", "last_update": "2021-11-24T11:10:04.692293+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -23932,7 +25521,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23940,7 +25535,8 @@ "start_time": "2021-11-24T11:00:04.783589+00:00", "last_update": "2021-11-24T11:00:05.027705+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -23985,7 +25581,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -23993,7 +25595,8 @@ "start_time": "2021-11-24T10:50:04.460250+00:00", "last_update": "2021-11-24T10:50:04.637607+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24038,7 +25641,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24046,7 +25655,8 @@ "start_time": "2021-11-24T10:40:04.872549+00:00", "last_update": "2021-11-24T10:40:05.055488+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24091,7 +25701,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24099,7 +25715,8 @@ "start_time": "2021-11-24T10:30:04.447723+00:00", "last_update": "2021-11-24T10:30:04.657345+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24144,7 +25761,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24152,7 +25775,8 @@ "start_time": "2021-11-24T10:20:04.460217+00:00", "last_update": "2021-11-24T10:20:04.672371+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24197,7 +25821,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24205,7 +25835,8 @@ "start_time": "2021-11-24T10:10:04.461257+00:00", "last_update": "2021-11-24T10:10:04.644618+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24250,7 +25881,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24258,7 +25895,8 @@ "start_time": "2021-11-24T10:00:04.573863+00:00", "last_update": "2021-11-24T10:00:04.798016+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24303,7 +25941,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24311,7 +25955,8 @@ "start_time": "2021-11-24T09:50:04.512501+00:00", "last_update": "2021-11-24T09:50:04.695227+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24356,7 +26001,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24364,7 +26015,8 @@ "start_time": "2021-11-24T09:40:04.629863+00:00", "last_update": "2021-11-24T09:40:04.834239+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24409,7 +26061,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24417,7 +26075,8 @@ "start_time": "2021-11-24T09:30:04.415640+00:00", "last_update": "2021-11-24T09:30:04.602695+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24462,7 +26121,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24470,7 +26135,8 @@ "start_time": "2021-11-24T09:20:04.389076+00:00", "last_update": "2021-11-24T09:20:04.627217+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24515,7 +26181,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24523,7 +26195,8 @@ "start_time": "2021-11-24T09:10:04.487116+00:00", "last_update": "2021-11-24T09:10:04.670124+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24568,7 +26241,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24576,7 +26255,8 @@ "start_time": "2021-11-24T09:00:04.719912+00:00", "last_update": "2021-11-24T09:00:04.905482+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24621,7 +26301,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24629,7 +26315,8 @@ "start_time": "2021-11-24T08:50:04.761983+00:00", "last_update": "2021-11-24T08:50:04.929543+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -24674,7 +26361,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24682,7 +26375,8 @@ "start_time": "2021-11-24T08:40:04.705636+00:00", "last_update": "2021-11-24T08:40:04.897900+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24727,7 +26421,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24735,7 +26435,8 @@ "start_time": "2021-11-24T08:30:04.927018+00:00", "last_update": "2021-11-24T08:30:05.101610+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24780,7 +26481,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24788,7 +26495,8 @@ "start_time": "2021-11-24T08:20:04.573076+00:00", "last_update": "2021-11-24T08:20:04.769617+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24833,7 +26541,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24841,7 +26555,8 @@ "start_time": "2021-11-24T08:10:04.640802+00:00", "last_update": "2021-11-24T08:10:04.829147+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -24886,7 +26601,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24894,7 +26615,8 @@ "start_time": "2021-11-24T08:00:04.604561+00:00", "last_update": "2021-11-24T08:00:04.847589+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24939,7 +26661,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -24947,7 +26675,8 @@ "start_time": "2021-11-24T07:50:04.475602+00:00", "last_update": "2021-11-24T07:50:04.652628+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -24992,7 +26721,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25000,7 +26735,8 @@ "start_time": "2021-11-24T07:40:04.577226+00:00", "last_update": "2021-11-24T07:40:04.759757+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25045,7 +26781,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25053,7 +26795,8 @@ "start_time": "2021-11-24T07:30:04.628014+00:00", "last_update": "2021-11-24T07:30:04.842011+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25098,7 +26841,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25106,7 +26855,8 @@ "start_time": "2021-11-24T07:20:04.572949+00:00", "last_update": "2021-11-24T07:20:04.745549+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25151,7 +26901,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25159,7 +26915,8 @@ "start_time": "2021-11-24T07:10:04.502879+00:00", "last_update": "2021-11-24T07:10:04.764787+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25204,7 +26961,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25212,7 +26975,8 @@ "start_time": "2021-11-24T07:00:04.531331+00:00", "last_update": "2021-11-24T07:00:04.813165+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25257,7 +27021,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25265,7 +27035,8 @@ "start_time": "2021-11-24T06:50:04.460491+00:00", "last_update": "2021-11-24T06:50:04.656143+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25310,7 +27081,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25318,7 +27095,8 @@ "start_time": "2021-11-24T06:40:04.504154+00:00", "last_update": "2021-11-24T06:40:04.742584+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25363,7 +27141,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25371,7 +27155,8 @@ "start_time": "2021-11-24T06:30:04.491594+00:00", "last_update": "2021-11-24T06:30:04.725370+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25416,7 +27201,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25424,7 +27215,8 @@ "start_time": "2021-11-24T06:20:04.519788+00:00", "last_update": "2021-11-24T06:20:04.734958+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25469,7 +27261,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25477,7 +27275,8 @@ "start_time": "2021-11-24T06:10:04.532763+00:00", "last_update": "2021-11-24T06:10:04.823954+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25522,7 +27321,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25530,7 +27335,8 @@ "start_time": "2021-11-24T06:00:04.831518+00:00", "last_update": "2021-11-24T06:00:05.063036+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25575,7 +27381,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25583,7 +27395,8 @@ "start_time": "2021-11-24T05:50:04.921557+00:00", "last_update": "2021-11-24T05:50:05.106362+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25628,7 +27441,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25636,7 +27455,8 @@ "start_time": "2021-11-24T05:40:04.639983+00:00", "last_update": "2021-11-24T05:40:04.822973+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -25681,7 +27501,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25689,7 +27515,8 @@ "start_time": "2021-11-24T05:30:04.552970+00:00", "last_update": "2021-11-24T05:30:04.758206+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25734,7 +27561,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25742,7 +27575,8 @@ "start_time": "2021-11-24T05:20:04.568293+00:00", "last_update": "2021-11-24T05:20:04.766989+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25787,7 +27621,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25795,7 +27635,8 @@ "start_time": "2021-11-24T05:10:04.425638+00:00", "last_update": "2021-11-24T05:10:04.610183+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25840,7 +27681,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25848,7 +27695,8 @@ "start_time": "2021-11-24T05:00:04.659651+00:00", "last_update": "2021-11-24T05:00:04.878540+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25893,7 +27741,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25901,7 +27755,8 @@ "start_time": "2021-11-24T04:50:04.525809+00:00", "last_update": "2021-11-24T04:50:04.698016+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -25946,7 +27801,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -25954,7 +27815,8 @@ "start_time": "2021-11-24T04:40:04.553894+00:00", "last_update": "2021-11-24T04:40:04.748205+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -25999,7 +27861,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26007,7 +27875,8 @@ "start_time": "2021-11-24T04:30:04.505059+00:00", "last_update": "2021-11-24T04:30:04.694984+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26052,7 +27921,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26060,7 +27935,8 @@ "start_time": "2021-11-24T04:20:04.444087+00:00", "last_update": "2021-11-24T04:20:04.674675+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26105,7 +27981,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26113,7 +27995,8 @@ "start_time": "2021-11-24T04:10:04.502094+00:00", "last_update": "2021-11-24T04:10:04.693319+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26158,7 +28041,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26166,7 +28055,8 @@ "start_time": "2021-11-24T04:00:04.463193+00:00", "last_update": "2021-11-24T04:00:04.701626+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26211,7 +28101,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26219,7 +28115,8 @@ "start_time": "2021-11-24T03:50:04.567814+00:00", "last_update": "2021-11-24T03:50:04.753820+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26264,7 +28161,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26272,7 +28175,8 @@ "start_time": "2021-11-24T03:40:04.602754+00:00", "last_update": "2021-11-24T03:40:04.796732+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26317,7 +28221,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26325,7 +28235,8 @@ "start_time": "2021-11-24T03:30:04.418104+00:00", "last_update": "2021-11-24T03:30:04.601174+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26370,7 +28281,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26378,7 +28295,8 @@ "start_time": "2021-11-24T03:20:04.461566+00:00", "last_update": "2021-11-24T03:20:04.660232+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26423,7 +28341,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26431,7 +28355,8 @@ "start_time": "2021-11-24T03:10:04.632882+00:00", "last_update": "2021-11-24T03:10:04.841486+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26476,7 +28401,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26484,7 +28415,8 @@ "start_time": "2021-11-24T03:00:04.532402+00:00", "last_update": "2021-11-24T03:00:04.777504+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26529,7 +28461,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26537,7 +28475,8 @@ "start_time": "2021-11-24T02:50:04.500997+00:00", "last_update": "2021-11-24T02:50:04.679010+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26582,7 +28521,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26590,7 +28535,8 @@ "start_time": "2021-11-24T02:40:04.528901+00:00", "last_update": "2021-11-24T02:40:04.721345+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26635,7 +28581,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26643,7 +28595,8 @@ "start_time": "2021-11-24T02:30:04.720846+00:00", "last_update": "2021-11-24T02:30:05.074548+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26688,7 +28641,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26696,7 +28655,8 @@ "start_time": "2021-11-24T02:20:04.612354+00:00", "last_update": "2021-11-24T02:20:04.794415+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26741,7 +28701,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26749,7 +28715,8 @@ "start_time": "2021-11-24T02:10:04.489593+00:00", "last_update": "2021-11-24T02:10:04.713319+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26794,7 +28761,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26802,7 +28775,8 @@ "start_time": "2021-11-24T02:00:04.538137+00:00", "last_update": "2021-11-24T02:00:04.755615+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -26847,7 +28821,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26855,7 +28835,8 @@ "start_time": "2021-11-24T01:50:04.546914+00:00", "last_update": "2021-11-24T01:50:04.747734+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -26900,7 +28881,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26908,7 +28895,8 @@ "start_time": "2021-11-24T01:40:04.433153+00:00", "last_update": "2021-11-24T01:40:04.626096+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -26953,7 +28941,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -26961,7 +28955,8 @@ "start_time": "2021-11-24T01:30:04.510443+00:00", "last_update": "2021-11-24T01:30:04.692919+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27006,7 +29001,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27014,7 +29015,8 @@ "start_time": "2021-11-24T01:20:05.295062+00:00", "last_update": "2021-11-24T01:20:05.497610+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27059,7 +29061,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27067,7 +29075,8 @@ "start_time": "2021-11-24T01:10:04.688801+00:00", "last_update": "2021-11-24T01:10:04.883373+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27112,7 +29121,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27120,7 +29135,8 @@ "start_time": "2021-11-24T01:00:04.939719+00:00", "last_update": "2021-11-24T01:00:05.178464+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27165,7 +29181,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27173,7 +29195,8 @@ "start_time": "2021-11-24T00:50:04.468549+00:00", "last_update": "2021-11-24T00:50:04.701356+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27218,7 +29241,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27226,7 +29255,8 @@ "start_time": "2021-11-24T00:40:04.815652+00:00", "last_update": "2021-11-24T00:40:05.000489+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27271,7 +29301,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27279,7 +29315,8 @@ "start_time": "2021-11-24T00:30:04.598658+00:00", "last_update": "2021-11-24T00:30:04.774050+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27324,7 +29361,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27332,7 +29375,8 @@ "start_time": "2021-11-24T00:20:04.517762+00:00", "last_update": "2021-11-24T00:20:04.706307+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27377,7 +29421,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27385,7 +29435,8 @@ "start_time": "2021-11-24T00:10:04.545462+00:00", "last_update": "2021-11-24T00:10:04.727941+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27430,7 +29481,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27438,7 +29495,8 @@ "start_time": "2021-11-24T00:00:04.535371+00:00", "last_update": "2021-11-24T00:00:04.746612+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27483,7 +29541,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27491,7 +29555,8 @@ "start_time": "2021-11-23T23:50:04.643566+00:00", "last_update": "2021-11-23T23:50:04.826637+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27536,7 +29601,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27544,7 +29615,8 @@ "start_time": "2021-11-23T23:40:04.589647+00:00", "last_update": "2021-11-23T23:40:04.791146+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27589,7 +29661,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27597,7 +29675,8 @@ "start_time": "2021-11-23T23:30:04.528050+00:00", "last_update": "2021-11-23T23:30:04.734943+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -27642,7 +29721,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27650,7 +29735,8 @@ "start_time": "2021-11-23T23:20:04.551632+00:00", "last_update": "2021-11-23T23:20:04.738770+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27695,7 +29781,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27703,7 +29795,8 @@ "start_time": "2021-11-23T23:10:04.450823+00:00", "last_update": "2021-11-23T23:10:04.652075+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27748,7 +29841,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27756,7 +29855,8 @@ "start_time": "2021-11-23T23:00:04.869365+00:00", "last_update": "2021-11-23T23:00:05.128497+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27801,7 +29901,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27809,7 +29915,8 @@ "start_time": "2021-11-23T22:50:04.634188+00:00", "last_update": "2021-11-23T22:50:04.810555+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -27854,7 +29961,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27862,7 +29975,8 @@ "start_time": "2021-11-23T22:40:04.569522+00:00", "last_update": "2021-11-23T22:40:04.769561+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27907,7 +30021,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27915,7 +30035,8 @@ "start_time": "2021-11-23T22:30:04.434236+00:00", "last_update": "2021-11-23T22:30:04.623421+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -27960,7 +30081,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -27968,7 +30095,8 @@ "start_time": "2021-11-23T22:20:04.379221+00:00", "last_update": "2021-11-23T22:20:04.571849+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28013,7 +30141,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28021,7 +30155,8 @@ "start_time": "2021-11-23T22:10:04.424226+00:00", "last_update": "2021-11-23T22:10:04.606574+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28066,7 +30201,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28074,7 +30215,8 @@ "start_time": "2021-11-23T22:00:04.584191+00:00", "last_update": "2021-11-23T22:00:04.802213+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28119,7 +30261,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28127,7 +30275,8 @@ "start_time": "2021-11-23T21:50:04.332475+00:00", "last_update": "2021-11-23T21:50:04.660638+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28172,7 +30321,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28180,7 +30335,8 @@ "start_time": "2021-11-23T21:40:04.437659+00:00", "last_update": "2021-11-23T21:40:04.653196+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28225,7 +30381,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28233,7 +30395,8 @@ "start_time": "2021-11-23T21:30:04.453384+00:00", "last_update": "2021-11-23T21:30:04.654010+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28278,7 +30441,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28286,7 +30455,8 @@ "start_time": "2021-11-23T21:20:04.442566+00:00", "last_update": "2021-11-23T21:20:04.625930+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28331,7 +30501,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28339,7 +30515,8 @@ "start_time": "2021-11-23T21:10:04.532801+00:00", "last_update": "2021-11-23T21:10:04.771198+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28384,7 +30561,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28392,7 +30575,8 @@ "start_time": "2021-11-23T21:00:04.543551+00:00", "last_update": "2021-11-23T21:00:04.762114+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28437,7 +30621,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28445,7 +30635,8 @@ "start_time": "2021-11-23T20:50:04.599458+00:00", "last_update": "2021-11-23T20:50:04.810958+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28490,7 +30681,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28498,7 +30695,8 @@ "start_time": "2021-11-23T20:40:04.375137+00:00", "last_update": "2021-11-23T20:40:04.549978+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28543,7 +30741,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28551,7 +30755,8 @@ "start_time": "2021-11-23T20:30:04.725045+00:00", "last_update": "2021-11-23T20:30:04.910512+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28596,7 +30801,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28604,7 +30815,8 @@ "start_time": "2021-11-23T20:20:04.650462+00:00", "last_update": "2021-11-23T20:20:04.826445+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28649,7 +30861,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28657,7 +30875,8 @@ "start_time": "2021-11-23T20:10:04.516348+00:00", "last_update": "2021-11-23T20:10:04.854112+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28702,7 +30921,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28710,7 +30935,8 @@ "start_time": "2021-11-23T20:00:04.707833+00:00", "last_update": "2021-11-23T20:00:04.908904+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28755,7 +30981,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28763,7 +30995,8 @@ "start_time": "2021-11-23T19:50:04.421833+00:00", "last_update": "2021-11-23T19:50:04.632400+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -28808,7 +31041,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28816,7 +31055,8 @@ "start_time": "2021-11-23T19:40:04.418991+00:00", "last_update": "2021-11-23T19:40:04.591359+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28861,7 +31101,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28869,7 +31115,8 @@ "start_time": "2021-11-23T19:30:04.517543+00:00", "last_update": "2021-11-23T19:30:04.705190+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -28914,7 +31161,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28922,7 +31175,8 @@ "start_time": "2021-11-23T19:20:04.559188+00:00", "last_update": "2021-11-23T19:20:04.744737+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -28967,7 +31221,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -28975,7 +31235,8 @@ "start_time": "2021-11-23T19:10:04.590607+00:00", "last_update": "2021-11-23T19:10:04.789711+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29020,7 +31281,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29028,7 +31295,8 @@ "start_time": "2021-11-23T19:00:04.581072+00:00", "last_update": "2021-11-23T19:00:04.821969+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29073,7 +31341,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29081,7 +31355,8 @@ "start_time": "2021-11-23T18:50:04.699860+00:00", "last_update": "2021-11-23T18:50:04.931051+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29126,7 +31401,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29134,7 +31415,8 @@ "start_time": "2021-11-23T18:40:05.087681+00:00", "last_update": "2021-11-23T18:40:05.261694+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29179,7 +31461,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29187,7 +31475,8 @@ "start_time": "2021-11-23T18:30:04.418439+00:00", "last_update": "2021-11-23T18:30:04.598008+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29232,7 +31521,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29240,7 +31535,8 @@ "start_time": "2021-11-23T18:20:04.498606+00:00", "last_update": "2021-11-23T18:20:04.694717+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29285,7 +31581,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29293,7 +31595,8 @@ "start_time": "2021-11-23T18:10:04.694077+00:00", "last_update": "2021-11-23T18:10:04.877956+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29338,7 +31641,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29346,7 +31655,8 @@ "start_time": "2021-11-23T18:00:04.451190+00:00", "last_update": "2021-11-23T18:00:04.685289+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29391,7 +31701,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29399,7 +31715,8 @@ "start_time": "2021-11-23T17:50:04.409692+00:00", "last_update": "2021-11-23T17:50:04.574748+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29444,7 +31761,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29452,7 +31775,8 @@ "start_time": "2021-11-23T17:40:04.803186+00:00", "last_update": "2021-11-23T17:40:05.024504+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29497,7 +31821,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29505,7 +31835,8 @@ "start_time": "2021-11-23T17:30:04.458452+00:00", "last_update": "2021-11-23T17:30:04.643441+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29550,7 +31881,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29558,7 +31895,8 @@ "start_time": "2021-11-23T17:20:04.389008+00:00", "last_update": "2021-11-23T17:20:04.559117+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29603,7 +31941,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29611,7 +31955,8 @@ "start_time": "2021-11-23T17:10:04.429827+00:00", "last_update": "2021-11-23T17:10:04.697423+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29656,7 +32001,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29664,7 +32015,8 @@ "start_time": "2021-11-23T17:00:04.636519+00:00", "last_update": "2021-11-23T17:00:04.852019+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29709,7 +32061,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29717,7 +32075,8 @@ "start_time": "2021-11-23T16:50:04.469691+00:00", "last_update": "2021-11-23T16:50:04.638176+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29762,7 +32121,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29770,7 +32135,8 @@ "start_time": "2021-11-23T16:40:04.793124+00:00", "last_update": "2021-11-23T16:40:04.979396+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29815,7 +32181,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29823,7 +32195,8 @@ "start_time": "2021-11-23T16:30:04.511592+00:00", "last_update": "2021-11-23T16:30:04.701880+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -29868,7 +32241,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29876,7 +32255,8 @@ "start_time": "2021-11-23T16:20:04.441622+00:00", "last_update": "2021-11-23T16:20:04.616568+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -29921,7 +32301,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -29929,7 +32315,8 @@ "start_time": "2021-11-23T16:10:04.297534+00:00", "last_update": "2021-11-23T16:10:04.488367+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -29956,14 +32343,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-23T16:01:58.107788+00:00", "last_update": "2021-11-23T16:01:58.227436+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30008,7 +32402,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30016,7 +32416,8 @@ "start_time": "2021-11-23T16:00:04.725458+00:00", "last_update": "2021-11-23T16:00:04.968356+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30061,7 +32462,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30069,7 +32476,8 @@ "start_time": "2021-11-23T15:50:04.422576+00:00", "last_update": "2021-11-23T15:50:04.635788+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -30114,7 +32522,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30122,7 +32536,8 @@ "start_time": "2021-11-23T15:40:04.641266+00:00", "last_update": "2021-11-23T15:40:04.882666+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -30167,7 +32582,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30175,7 +32596,8 @@ "start_time": "2021-11-23T15:30:04.378826+00:00", "last_update": "2021-11-23T15:30:04.565072+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30220,7 +32642,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30228,7 +32656,8 @@ "start_time": "2021-11-23T15:20:04.559525+00:00", "last_update": "2021-11-23T15:20:04.758667+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30273,7 +32702,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30281,7 +32716,8 @@ "start_time": "2021-11-23T15:10:04.536833+00:00", "last_update": "2021-11-23T15:10:04.726331+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30326,7 +32762,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30334,7 +32776,8 @@ "start_time": "2021-11-23T15:00:04.563670+00:00", "last_update": "2021-11-23T15:00:04.784840+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30379,7 +32822,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30387,7 +32836,8 @@ "start_time": "2021-11-23T14:50:04.460492+00:00", "last_update": "2021-11-23T14:50:04.649701+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30432,7 +32882,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30440,7 +32896,8 @@ "start_time": "2021-11-23T14:40:04.553734+00:00", "last_update": "2021-11-23T14:40:04.854853+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30485,7 +32942,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30493,7 +32956,8 @@ "start_time": "2021-11-23T14:30:04.626953+00:00", "last_update": "2021-11-23T14:30:04.806765+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30538,7 +33002,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30546,7 +33016,8 @@ "start_time": "2021-11-23T14:20:04.478122+00:00", "last_update": "2021-11-23T14:20:04.710932+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30591,7 +33062,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30599,7 +33076,8 @@ "start_time": "2021-11-23T14:10:04.510030+00:00", "last_update": "2021-11-23T14:10:04.734683+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -30644,7 +33122,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30652,7 +33136,8 @@ "start_time": "2021-11-23T14:00:04.692590+00:00", "last_update": "2021-11-23T14:00:04.913319+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30697,7 +33182,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30705,7 +33196,8 @@ "start_time": "2021-11-23T13:50:04.486524+00:00", "last_update": "2021-11-23T13:50:04.707908+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30750,7 +33242,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30758,7 +33256,8 @@ "start_time": "2021-11-23T13:40:04.695802+00:00", "last_update": "2021-11-23T13:40:04.864555+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30803,7 +33302,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30811,7 +33316,8 @@ "start_time": "2021-11-23T13:30:04.466982+00:00", "last_update": "2021-11-23T13:30:04.645016+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -30856,7 +33362,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30864,7 +33376,8 @@ "start_time": "2021-11-23T13:20:04.432215+00:00", "last_update": "2021-11-23T13:20:04.593066+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -30909,7 +33422,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30917,7 +33436,8 @@ "start_time": "2021-11-23T13:10:04.377343+00:00", "last_update": "2021-11-23T13:10:04.562248+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -30962,7 +33482,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -30970,7 +33496,8 @@ "start_time": "2021-11-23T13:00:04.757717+00:00", "last_update": "2021-11-23T13:00:04.976383+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31015,7 +33542,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31023,7 +33556,8 @@ "start_time": "2021-11-23T12:50:04.510481+00:00", "last_update": "2021-11-23T12:50:04.694038+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31068,7 +33602,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31076,7 +33616,8 @@ "start_time": "2021-11-23T12:40:04.381615+00:00", "last_update": "2021-11-23T12:40:04.572676+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31121,7 +33662,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31129,7 +33676,8 @@ "start_time": "2021-11-23T12:30:04.503862+00:00", "last_update": "2021-11-23T12:30:04.678147+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31174,7 +33722,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31182,7 +33736,8 @@ "start_time": "2021-11-23T12:20:04.559097+00:00", "last_update": "2021-11-23T12:20:04.737203+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31227,7 +33782,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31235,7 +33796,8 @@ "start_time": "2021-11-23T12:10:04.449115+00:00", "last_update": "2021-11-23T12:10:04.625507+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31280,7 +33842,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31288,7 +33856,8 @@ "start_time": "2021-11-23T12:00:04.486243+00:00", "last_update": "2021-11-23T12:00:04.698411+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31333,7 +33902,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31341,7 +33916,8 @@ "start_time": "2021-11-23T11:50:04.723311+00:00", "last_update": "2021-11-23T11:50:04.932266+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31386,7 +33962,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31394,7 +33976,8 @@ "start_time": "2021-11-23T11:40:04.649386+00:00", "last_update": "2021-11-23T11:40:04.869518+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31439,7 +34022,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31447,7 +34036,8 @@ "start_time": "2021-11-23T11:30:04.532380+00:00", "last_update": "2021-11-23T11:30:04.711271+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31492,7 +34082,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31500,7 +34096,8 @@ "start_time": "2021-11-23T11:20:04.501966+00:00", "last_update": "2021-11-23T11:20:04.698149+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31545,7 +34142,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31553,7 +34156,8 @@ "start_time": "2021-11-23T11:10:04.480587+00:00", "last_update": "2021-11-23T11:10:04.666382+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31598,7 +34202,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31606,7 +34216,8 @@ "start_time": "2021-11-23T11:00:04.482799+00:00", "last_update": "2021-11-23T11:00:04.712377+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31651,7 +34262,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31659,7 +34276,8 @@ "start_time": "2021-11-23T10:50:04.458809+00:00", "last_update": "2021-11-23T10:50:04.633174+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31704,7 +34322,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31712,7 +34336,8 @@ "start_time": "2021-11-23T10:40:04.415844+00:00", "last_update": "2021-11-23T10:40:04.582542+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -31757,7 +34382,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31765,7 +34396,8 @@ "start_time": "2021-11-23T10:30:04.376510+00:00", "last_update": "2021-11-23T10:30:04.568037+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31810,7 +34442,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31818,7 +34456,8 @@ "start_time": "2021-11-23T10:20:04.393940+00:00", "last_update": "2021-11-23T10:20:04.599562+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31863,7 +34502,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31871,7 +34516,8 @@ "start_time": "2021-11-23T10:10:04.602995+00:00", "last_update": "2021-11-23T10:10:04.792896+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -31919,7 +34565,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -31927,7 +34579,8 @@ "start_time": "2021-11-23T10:04:11.101928+00:00", "last_update": "2021-11-23T10:04:11.277613+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31963,14 +34616,21 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-23T10:03:38.156539+00:00", "last_update": "2021-11-23T10:03:52.050684+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -31998,14 +34658,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-23T10:03:35.393063+00:00", "last_update": "2021-11-23T10:03:35.483063+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32032,14 +34699,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T11:46:51.227805+00:00", "last_update": "2021-11-08T11:46:51.296237+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32066,14 +34740,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T11:45:22.064287+00:00", "last_update": "2021-11-08T11:45:22.145479+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32108,7 +34789,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -32116,7 +34803,8 @@ "start_time": "2021-11-08T11:43:51.387325+00:00", "last_update": "2021-11-08T11:43:51.660572+00:00", "error": "Columns must be same length as key", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32159,14 +34847,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-11-08T11:42:59.089848+00:00", "last_update": "2021-11-08T11:43:07.483195+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32213,14 +34908,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-08T11:40:08.223207+00:00", "last_update": "2021-11-08T11:40:36.453731+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32263,14 +34965,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-08T11:39:43.558424+00:00", "last_update": "2021-11-08T11:40:06.182841+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32317,14 +35026,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-08T11:39:35.083703+00:00", "last_update": "2021-11-08T11:39:35.895469+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32352,14 +35068,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-08T11:36:03.228032+00:00", "last_update": "2021-11-08T11:36:03.301501+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32387,14 +35110,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-02T08:47:57.208326+00:00", "last_update": "2021-11-02T08:47:57.328639+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32422,14 +35152,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-11-01T00:00:08.999400+00:00", "last_update": "2021-11-01T00:00:09.211607+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32455,14 +35192,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-28T18:12:56.106520+00:00", "last_update": "2021-10-28T18:13:17.198567+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32488,14 +35232,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-28T14:18:37.228925+00:00", "last_update": "2021-10-28T14:19:06.426608+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32523,14 +35274,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-28T13:46:21.225458+00:00", "last_update": "2021-10-28T13:46:21.294035+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32581,7 +35339,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -32589,7 +35353,8 @@ "start_time": "2021-10-28T13:43:30.968141+00:00", "last_update": "2021-10-28T13:43:31.647120+00:00", "error": "file type unhandled v3io:///test/test", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32631,14 +35396,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-28T08:40:35.739139+00:00", "last_update": "2021-10-28T08:41:05.600456+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32684,14 +35456,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-21T18:14:19.099271+00:00", "last_update": "2021-10-21T18:14:46.228065+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32717,14 +35496,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-19T07:46:06.654759+00:00", "last_update": "2021-10-19T07:46:36.553501+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32750,14 +35536,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-19T07:32:37.765470+00:00", "last_update": "2021-10-19T07:32:56.606738+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32783,14 +35576,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-15T14:54:55.118884+00:00", "last_update": "2021-10-15T14:55:06.696436+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32817,14 +35617,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T19:58:01.299873+00:00", "last_update": "2021-10-13T19:58:01.374021+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32851,14 +35658,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T19:41:12.462796+00:00", "last_update": "2021-10-13T19:41:12.541077+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -32884,14 +35698,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-13T19:23:24.084989+00:00", "last_update": "2021-10-13T19:23:24.472745+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32917,14 +35738,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-13T19:22:17.420518+00:00", "last_update": "2021-10-13T19:22:24.018887+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -32950,14 +35778,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-13T15:55:43.092290+00:00", "last_update": "2021-10-13T15:56:04.828883+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -32984,14 +35819,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T15:14:29.209667+00:00", "last_update": "2021-10-13T15:14:29.271307+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33018,14 +35860,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T14:12:55.122657+00:00", "last_update": "2021-10-13T14:12:55.188855+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33052,14 +35901,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-10-13T14:02:19.750855+00:00", "last_update": "2021-10-13T14:02:19.839795+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33085,14 +35941,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-10T10:27:23.881911+00:00", "last_update": "2021-10-10T10:27:24.616015+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33118,14 +35981,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-10T10:22:23.551995+00:00", "last_update": "2021-10-10T10:22:29.710206+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33151,14 +36021,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-10T10:22:01.460726+00:00", "last_update": "2021-10-10T10:22:06.341668+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33184,14 +36061,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-10T10:21:34.872124+00:00", "last_update": "2021-10-10T10:21:44.400075+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33227,14 +36111,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-06T14:10:00.438518+00:00", "last_update": "2021-10-06T14:10:16.259616+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33261,14 +36152,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-01T00:00:00.235989+00:00", "last_update": "2021-10-01T00:00:12.308235+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33294,14 +36192,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-30T12:03:14.421289+00:00", "last_update": "2021-09-30T12:03:33.039369+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33327,14 +36232,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-30T12:00:57.901153+00:00", "last_update": "2021-09-30T12:01:01.851605+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33360,14 +36272,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-09-17T15:08:47.936899+00:00", "last_update": "2021-09-17T15:09:07.462131+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33424,7 +36343,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33432,7 +36357,8 @@ "start_time": "2021-09-17T15:08:29.202452+00:00", "last_update": "2021-09-17T15:08:30.072691+00:00", "error": "unable to connect to account for Must provide either a connection_string or account_name with credentials!!", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33489,7 +36415,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33497,7 +36429,8 @@ "start_time": "2021-09-17T12:53:31.183995+00:00", "last_update": "2021-09-17T12:53:31.818200+00:00", "error": "file type unhandled v3io://hhhhjjjjkkkk", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33554,7 +36487,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33562,7 +36501,8 @@ "start_time": "2021-09-17T12:50:53.673923+00:00", "last_update": "2021-09-17T12:50:54.305932+00:00", "error": "file type unhandled v3io://hhhhhhh", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33619,7 +36559,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33627,7 +36573,8 @@ "start_time": "2021-09-17T12:44:47.158478+00:00", "last_update": "2021-09-17T12:44:47.738459+00:00", "error": "file type unhandled v3io://test", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33684,7 +36631,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33692,7 +36645,8 @@ "start_time": "2021-09-17T12:15:35.974230+00:00", "last_update": "2021-09-17T12:15:36.567922+00:00", "error": "file type unhandled v3io://sdadsada", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33749,7 +36703,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33757,7 +36717,8 @@ "start_time": "2021-09-17T12:14:22.653559+00:00", "last_update": "2021-09-17T12:14:23.294026+00:00", "error": "file type unhandled v3io://ss", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -33814,7 +36775,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33822,7 +36789,8 @@ "start_time": "2021-09-17T12:13:17.761118+00:00", "last_update": "2021-09-17T12:13:18.502005+00:00", "error": "file type unhandled v3io://yy", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -33879,7 +36847,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33887,7 +36861,8 @@ "start_time": "2021-09-17T12:12:48.401039+00:00", "last_update": "2021-09-17T12:12:49.044854+00:00", "error": "file type unhandled v3io://tt", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -33944,7 +36919,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -33952,7 +36933,8 @@ "start_time": "2021-09-17T12:09:10.806047+00:00", "last_update": "2021-09-17T12:09:11.364692+00:00", "error": "file type unhandled v3io://ewqewq", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34009,7 +36991,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34017,7 +37005,8 @@ "start_time": "2021-09-17T11:59:50.920646+00:00", "last_update": "2021-09-17T11:59:51.576888+00:00", "error": "file type unhandled v3io://asd", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34074,7 +37063,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34082,7 +37077,8 @@ "start_time": "2021-09-17T11:59:01.285243+00:00", "last_update": "2021-09-17T11:59:04.051728+00:00", "error": "file type unhandled s3://asd", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34139,7 +37135,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34147,7 +37149,8 @@ "start_time": "2021-09-17T11:57:57.036076+00:00", "last_update": "2021-09-17T11:57:57.905590+00:00", "error": "file type unhandled v3io://qweewqqwwwwwwww", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34173,14 +37176,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-17T11:34:04.948045+00:00", "last_update": "2021-09-17T11:34:11.649796+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34237,7 +37247,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34245,7 +37261,8 @@ "start_time": "2021-09-17T08:01:55.544559+00:00", "last_update": "2021-09-17T08:01:56.622206+00:00", "error": "unable to connect to account for Must provide either a connection_string or account_name with credentials!!", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34302,7 +37319,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34310,7 +37333,8 @@ "start_time": "2021-09-16T15:34:11.324884+00:00", "last_update": "2021-09-16T15:34:11.938806+00:00", "error": "file type unhandled v3io://asd", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34367,7 +37391,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34375,7 +37405,8 @@ "start_time": "2021-09-15T11:11:23.310455+00:00", "last_update": "2021-09-15T11:11:23.886661+00:00", "error": "file type unhandled v3io://aa", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34401,7 +37432,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34409,7 +37446,8 @@ "start_time": "2021-09-10T08:07:55.696888+00:00", "last_update": "2021-09-10T08:07:55.747261+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 08:07:55 GMT', 'Content-Length': '1026'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-vmghw\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"volume_test__name\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-vmghw\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"volume_test__name\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 08:07:55 GMT', 'Content-Length': '1026'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-vmghw\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"volume_test__name\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-vmghw\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"volume_test__name\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 1 } }, { @@ -34435,7 +37473,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34443,7 +37487,8 @@ "start_time": "2021-09-10T08:07:27.992706+00:00", "last_update": "2021-09-10T08:07:28.071778+00:00", "artifacts": [], - "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 08:07:28 GMT', 'Content-Length': '1026'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-d2x69\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"volume_test__name\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-d2x69\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"volume_test__name\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n" + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 08:07:28 GMT', 'Content-Length': '1026'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"test-i-d2x69\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"volume_test__name\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"test-i-d2x69\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"volume_test__name\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"volume_test__name\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 0 } }, { @@ -34469,14 +37514,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-08T16:01:00.020724+00:00", "last_update": "2021-09-08T16:01:28.024926+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34502,14 +37554,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-08T15:51:02.734809+00:00", "last_update": "2021-09-08T15:51:23.296887+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34535,14 +37594,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-08T15:37:29.504427+00:00", "last_update": "2021-09-08T15:37:47.727633+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34588,14 +37654,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-07T11:42:54.171035+00:00", "last_update": "2021-09-07T11:42:56.512443+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34621,14 +37694,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-07T11:20:14.154220+00:00", "last_update": "2021-09-07T11:20:16.663883+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34654,14 +37734,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-07T09:03:37.071417+00:00", "last_update": "2021-09-07T09:04:05.569790+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -34712,7 +37799,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -34721,7 +37814,8 @@ }, "start_time": "2021-09-04T08:13:13.409154+00:00", "last_update": "2021-09-04T08:13:14.808015+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34755,7 +37849,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34763,7 +37863,8 @@ "start_time": "2021-09-03T13:53:56.088502+00:00", "last_update": "2021-09-03T13:53:56.318914+00:00", "error": "Columns must be same length as key", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34790,14 +37891,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-09-03T13:53:50.030505+00:00", "last_update": "2021-09-03T13:53:50.099756+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34844,7 +37952,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34852,7 +37966,8 @@ "start_time": "2021-09-03T13:53:35.470383+00:00", "last_update": "2021-09-03T13:53:35.716754+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34879,14 +37994,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-09-03T13:52:40.749944+00:00", "last_update": "2021-09-03T13:52:40.810108+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -34913,14 +38035,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-09-03T12:02:52.273993+00:00", "last_update": "2021-09-03T12:02:52.335681+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -34955,7 +38084,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -34963,7 +38098,8 @@ "start_time": "2021-09-03T12:02:03.774104+00:00", "last_update": "2021-09-03T12:02:03.936616+00:00", "error": "[Errno 2] No such file or directory: 'message_file'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35010,7 +38146,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35018,7 +38160,8 @@ "start_time": "2021-09-01T13:32:53.361949+00:00", "last_update": "2021-09-01T13:32:53.519516+00:00", "error": "'str' object has no attribute 'url'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35044,7 +38187,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35052,7 +38201,8 @@ "start_time": "2021-08-31T19:07:10.627886+00:00", "last_update": "2021-08-31T19:07:10.683889+00:00", "artifacts": [], - "error": "cannot import from ''" + "error": "cannot import from ''", + "retry_count": 1 } }, { @@ -35078,14 +38228,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-10-04T06:43:00.974008+00:00", "last_update": "2021-10-04T06:43:07.566741+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35123,7 +38280,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -35132,7 +38295,8 @@ }, "start_time": "2021-08-29T19:45:14.995282+00:00", "last_update": "2021-08-29T19:45:18.516911+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35163,14 +38327,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-23T10:00:00.059030+00:00", "last_update": "2021-11-23T10:00:20.339115+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35200,14 +38371,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-11-23T09:58:33.718204+00:00", "last_update": "2021-11-23T09:58:49.667649+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35239,7 +38417,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35247,7 +38431,8 @@ "start_time": "2021-11-08T16:26:31.029770+00:00", "last_update": "2021-11-08T16:27:42.496061+00:00", "error": "401 received while accessing 'getting-started-tutorial-admin/artifacts/data/test_set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35282,7 +38467,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35290,7 +38481,8 @@ "start_time": "2021-11-08T16:26:21.976983+00:00", "last_update": "2021-11-08T16:28:41.537143+00:00", "error": "401 received while accessing 'getting-started-tutorial-admin/artifacts/pipeline/dd5972cb-cbc2-4998-ab0e-705dba1b307d/data/test_set.csv'", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35323,7 +38515,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35331,7 +38529,8 @@ "start_time": "2021-11-08T16:24:23.377270+00:00", "last_update": "2021-11-08T16:24:23.642837+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -35364,7 +38563,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35372,7 +38577,8 @@ "start_time": "2021-11-08T16:24:03.601835+00:00", "last_update": "2021-11-08T16:24:03.787381+00:00", "error": "file type unhandled source_url", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -35414,7 +38620,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35422,7 +38634,8 @@ "start_time": "2021-11-08T16:21:59.747369+00:00", "last_update": "2021-11-08T16:21:59.925727+00:00", "error": "file type unhandled test_set", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35460,7 +38673,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35468,7 +38687,8 @@ "start_time": "2021-11-08T16:21:43.033778+00:00", "last_update": "2021-11-08T16:21:43.242064+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -35495,7 +38715,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -35503,7 +38729,8 @@ "start_time": "2021-11-08T16:21:00.729828+00:00", "last_update": "2021-11-08T16:21:00.772223+00:00", "artifacts": [], - "error": ".run() can only be execute on \"mlrun\" kind, recreate with function kind \"mlrun\"" + "error": ".run() can only be execute on \"mlrun\" kind, recreate with function kind \"mlrun\"", + "retry_count": 1 } }, { @@ -35539,7 +38766,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -36188,7 +39421,8 @@ "uid": "460-3", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -36225,7 +39459,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -37327,7 +40567,8 @@ "uid": "461-5", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -37363,7 +40604,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -37879,7 +41126,8 @@ "uid": "462-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -37912,7 +41160,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -38561,7 +41815,8 @@ "uid": "463-3", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -38592,7 +41847,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -38702,7 +41963,8 @@ "uid": "464-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -38733,7 +41995,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -39835,7 +43103,8 @@ "uid": "465-5", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -39864,7 +43133,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -40380,7 +43655,8 @@ "uid": "466-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -40409,7 +43685,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -40925,7 +44207,8 @@ "uid": "467-0", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -40954,7 +44237,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -41470,7 +44759,8 @@ "uid": "468-0", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -41499,14 +44789,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-08-31T19:47:38.497611+00:00", "last_update": "2021-08-31T19:47:53.564737+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41537,14 +44834,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", "results": {}, "start_time": "2021-08-29T20:05:25.859281+00:00", "last_update": "2021-08-29T20:07:09.961262+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -41570,14 +44874,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-10T11:40:10.676831+00:00", "last_update": "2021-09-10T11:40:27.194590+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -41603,14 +44914,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-09-08T12:58:23.170389+00:00", "last_update": "2021-09-08T12:58:43.526754+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -41645,7 +44963,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -41653,7 +44977,8 @@ "start_time": "2021-09-06T15:18:24.118044+00:00", "last_update": "2021-09-06T15:18:24.379177+00:00", "error": "unsupported archive type in archive_url", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41699,7 +45024,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -41707,7 +45038,8 @@ "start_time": "2021-09-06T13:47:42.720200+00:00", "last_update": "2021-09-06T13:47:42.859183+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -41753,7 +45085,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -41761,7 +45099,8 @@ "start_time": "2021-09-06T13:45:12.800502+00:00", "last_update": "2021-09-06T13:45:12.929041+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -41807,14 +45146,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "aborted", "results": {}, "start_time": "2021-09-03T11:09:10.722682+00:00", "last_update": "2021-09-03T11:09:31.085216+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41838,14 +45184,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-11-16T07:37:26.003124+00:00", "last_update": "2021-11-16T07:37:26.003133+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -41869,14 +45222,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-11-16T07:37:26.001892+00:00", "last_update": "2021-11-16T07:37:26.001899+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -41900,14 +45260,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-11-16T07:37:25.723971+00:00", "last_update": "2021-11-16T07:37:25.723978+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -41931,14 +45298,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 9, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-11-16T07:37:25.667003+00:00", "last_update": "2021-11-16T07:37:25.667009+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -41982,7 +45356,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 10, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -42035,7 +45415,8 @@ "uid": "481-2", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -42059,14 +45440,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-08-29T20:28:59.571945+00:00", "last_update": "2021-08-29T20:28:59.571951+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -42090,14 +45478,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-08-29T20:28:59.571725+00:00", "last_update": "2021-08-29T20:28:59.571731+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -42135,7 +45530,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -42164,7 +45565,8 @@ "uid": "484-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -42188,14 +45590,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-08-29T20:28:11.410654+00:00", "last_update": "2021-08-29T20:28:11.410660+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -42219,14 +45628,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", "results": {}, "start_time": "2021-08-29T20:28:11.397877+00:00", "last_update": "2021-08-29T20:28:11.397882+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -42264,7 +45680,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -42935,7 +46357,8 @@ "uid": "487-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -42976,7 +46399,13 @@ "inputs": { "dataset": "store://datasets/network-operations-admin/feature_selection_selected_features:cd151783-05df-4f9c-a9db-3aa674e4a058" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -43972,7 +47401,8 @@ "uid": "488-6", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -44013,7 +47443,13 @@ "inputs": { "dataset": "store://datasets/network-operations-admin/feature_selection_selected_features:cd151783-05df-4f9c-a9db-3aa674e4a058" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -44992,7 +48428,8 @@ "uid": "489-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -45033,7 +48470,13 @@ "inputs": { "dataset": "store://datasets/network-operations-admin/feature_selection_selected_features:cd151783-05df-4f9c-a9db-3aa674e4a058" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 8, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -46029,7 +49472,8 @@ "uid": "490-6", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -46077,7 +49521,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -47170,7 +50620,8 @@ "uid": "491-7", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -47214,7 +50665,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -47324,7 +50781,8 @@ "uid": "492-5", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -47364,7 +50822,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -49889,7 +53353,8 @@ "uid": "493-9", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -49934,7 +53399,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -50072,7 +53543,8 @@ "uid": "494-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -50124,7 +53596,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -53006,7 +56484,8 @@ "uid": "495-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -53045,7 +56524,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -53183,7 +56668,8 @@ "uid": "496-5", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -53234,7 +56720,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -56116,7 +59608,8 @@ "uid": "497-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -56154,7 +59647,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -56264,7 +59763,8 @@ "uid": "498-5", "tag": "latest" } - ] + ], + "retry_count": 2 } }, { @@ -56288,7 +59788,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "running", @@ -56873,7 +60379,8 @@ "uid": "499-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -56918,14 +60425,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "pending", "results": {}, "start_time": "2021-10-01T00:00:00.277689+00:00", "last_update": "2021-10-01T00:00:12.345881+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -56973,7 +60487,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -56981,7 +60501,8 @@ "start_time": "2021-09-01T00:00:07.362502+00:00", "last_update": "2021-09-01T00:00:07.556686+00:00", "error": "file type unhandled dataset", - "artifacts": [] + "artifacts": [], + "retry_count": 0 } }, { @@ -57018,7 +60539,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", @@ -57026,7 +60553,8 @@ "start_time": "2021-08-31T12:28:09.838061+00:00", "last_update": "2021-08-31T12:28:10.003381+00:00", "error": "file type unhandled table", - "artifacts": [] + "artifacts": [], + "retry_count": 1 } }, { @@ -57062,7 +60590,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -57091,7 +60625,8 @@ "uid": "503-0", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -57127,7 +60662,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -57746,7 +61287,8 @@ "uid": "504-4", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -57786,7 +61328,13 @@ "inputs": { "dataset": "store://datasets/sk-project-admin/get-data_iris_dataset:a0e31343-3be8-4aa2-9de5-0e54342f8e1a" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -58664,7 +62212,8 @@ "uid": "505-5", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -58704,7 +62253,13 @@ "inputs": { "dataset": "store://datasets/sk-project-admin/get-data_iris_dataset:a0e31343-3be8-4aa2-9de5-0e54342f8e1a" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -59565,7 +63120,8 @@ "uid": "506-4", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -59605,7 +63161,13 @@ "inputs": { "dataset": "store://datasets/sk-project-admin/get-data_iris_dataset:a0e31343-3be8-4aa2-9de5-0e54342f8e1a" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -60483,7 +64045,8 @@ "uid": "507-5", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -60518,7 +64081,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 7, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -60628,7 +64197,8 @@ "uid": "508-5", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -60675,7 +64245,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 12, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -61645,7 +65221,8 @@ "uid": "509-6", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -61679,7 +65256,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 4, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -62193,7 +65776,8 @@ "uid": "510-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -62224,7 +65808,13 @@ }, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 3, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -62334,7 +65924,8 @@ "uid": "511-5", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -62361,7 +65952,13 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -62875,7 +66472,8 @@ "uid": "512-0", "tag": "latest" } - ] + ], + "retry_count": 1 } }, { @@ -62907,14 +66505,21 @@ "inputs": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "error", "results": {}, "start_time": "2021-10-28T13:52:42.987115+00:00", "last_update": "2021-10-28T13:52:55.115320+00:00", - "artifacts": [] + "artifacts": [], + "retry_count": 2 } }, { @@ -62960,7 +66565,13 @@ "hyper_param_options": { "selector": "max.accuracy" }, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 5, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "state": "completed", @@ -67755,7 +71366,8 @@ "uid": "514-7", "tag": "latest" } - ] + ], + "retry_count": 0 } }, { @@ -67792,7 +71404,13 @@ "node_selector": {}, "hyperparams": {}, "hyper_param_options": {}, - "data_stores": [] + "data_stores": [], + "retry": { + "count": 11, + "backoff": { + "base_delay": "30s" + } + } }, "status": { "results": {}, @@ -67800,7 +71418,8 @@ "last_update": "2024-10-08T14:34:12.621378+00:00", "state": "aborted", "abort_task_id": "74be3e06-56fb-4bc9-9ece-b77f7f818373", - "status_text": "aborted" + "status_text": "aborted", + "retry_count": 2 } } ] From a656409861857fef62a065c9cd7cff00db14a9ef Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:47:23 +0300 Subject: [PATCH 036/228] Fix [Monitoring app] UI alignment and text updates for Figma consistency (#3310) --- .../MonitoringApplicationCard/MonitoringApplicationCard.jsx | 3 ++- .../monitoringApplicationCounters.scss | 4 ++-- .../monitoringApplicationCounters.util.jsx | 4 ++-- .../MonitoringApplications/MonitoringApplications.jsx | 2 +- .../MonitoringApplications/monitoringApplications.util.js | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx index 40e44f9b56..e070efb110 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx @@ -49,6 +49,7 @@ const MonitoringApplicationCard = ({
      {loading ? : error ? 'N/A' : counter.title} + {counter.status && }
      {counter.subtitle && ( @@ -58,7 +59,7 @@ const MonitoringApplicationCard = ({ template={} > {counter.subtitle} - + {counter.subtitleStatus && }
      )} diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss index 007ac616a7..09d14d7c03 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss @@ -34,8 +34,8 @@ margin-bottom: 10px; } - .stats__subtitle { - margin-right: 5px; + [class^="state"] { + margin-left: 5px; } } } diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index bb7df14f95..cbd230f9b7 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -50,13 +50,13 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => id: 'running', title: applicationsSummary.running_model_monitoring_functions, subtitle: 'Running', - status: 'running' + subtitleStatus: 'running' }, { id: 'failed', title: applicationsSummary.failed_model_monitoring_functions, subtitle: 'Failed', - status: 'failed' + subtitleStatus: 'failed' } ] }, diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx index 43c87fe408..6d4f226972 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx @@ -83,7 +83,7 @@ const MonitoringApplications = () => {
      - Operating functions + System functions
      {operatingFunctions.length === 0 ? ( diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js index 474e78b300..125746b1b7 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js @@ -32,7 +32,7 @@ export const generateOperatingFunctionsTable = functions => { }, { value: 'Status', className: 'table-cell_small' }, { - value: 'Started at', + value: 'Updated', className: 'table-cell_medium' }, { From 93c43e6f8328573424b8a758747be2f784114193 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:47:42 +0300 Subject: [PATCH 037/228] Fix [Artifacts] Add a confirmation pop-up (#3311) --- src/components/Details/DetailsHeader/DetailsHeader.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/Details/DetailsHeader/DetailsHeader.jsx b/src/components/Details/DetailsHeader/DetailsHeader.jsx index b6b39600ea..88622d930a 100644 --- a/src/components/Details/DetailsHeader/DetailsHeader.jsx +++ b/src/components/Details/DetailsHeader/DetailsHeader.jsx @@ -57,6 +57,7 @@ const DetailsHeader = ({ DetailsHeaderContainer, actionButton, commonDetailsStore, + handleActionClick, handleBackClick, handleCancelClick, headerRef, @@ -248,6 +249,7 @@ const DetailsHeader = ({ commonDetailsStore={commonDetailsStore} getCloseDetailsLink={getCloseDetailsLink} getDefaultCloseDetailsLink={getDefaultCloseDetailsLink} + handleActionClick={handleActionClick} handleCancelClick={handleCancelClick} handleRefresh={handleRefresh} headerRef={headerRef} From 3166ae2db1eab811646d552cfd95160bd4435f35 Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Thu, 26 Jun 2025 10:49:06 +0200 Subject: [PATCH 038/228] Tests [QA] v1.10.0-rc6 (#3309) - added tests for terminating workflows - updated tests involving the Projects dropdown in Jobs and Workflows filters --- tests/features/common-tools/common-consts.js | 15 +- .../page-objects/jobs-and-workflows.po.js | 6 +- .../common/page-objects/jobs-monitoring.po.js | 11 +- tests/features/featureStore.feature | 1 + tests/features/jobsAndWorkflows.feature | 126 +++++++++- tests/features/jobsMonitoring.feature | 217 ++++++++++++++++-- tests/features/projectsPage.feature | 3 + tests/mockServer/data/pipelines.json | 2 +- tests/mockServer/data/piplineIDs.json | 2 +- 9 files changed, 353 insertions(+), 30 deletions(-) diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index e2bc5dd593..1b68abc227 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -568,11 +568,14 @@ export default { Running_Job_Action_Menu_Options: ['Run\'s resource monitoring', 'Abort', 'View YAML'], Delete_Run_Message: /Are you sure you want to delete the run with the UID "(.+?)" of the job "(.+?)"\? Deleted runs can not be restored./, Delete_All_Runs_Message: /Are you sure you want to delete all runs of the job "(.+?)"\? Deleted runs can not be restored./, - Workflows_Action_Menu_Options: ['View YAML', 'Retry'], - Workflows_Info_Pane_Action_Menu_Options: ['Batch re-run', 'Monitoring', 'View YAML', 'Delete'], + Terminate_Workflow_Message: /Are you sure you want to terminate the workflow "(.+?)" \(stop its execution\)\? Workflows termination cannot be undone\./, + Workflows_Action_Menu_Options: ['View YAML', 'Retry', 'Terminate'], + Workflows_Running_Action_Menu_Options: ['View YAML', 'Terminate'], + Workflows_Info_Pane_Action_Menu_Options: ['Batch re-run', 'Monitoring', 'View YAML', 'Delete', 'Terminate'], Pending_Job_Action_Menu_Options: ['Batch re-run', 'Run\'s resource monitoring', 'Abort', 'View YAML'], Schedule_Action_Menu_Options: ['Run now', 'Edit', 'Delete', 'View YAML'], - Workflows_Unsuccessful_Run_Message: 'Workflow did not run successfully\nRETRY' + Workflows_Unsuccessful_Run_Message: 'Workflow did not run successfully\nRETRY', + Workflows_Unsuccessful_Terminate_Message: 'Workflow "stocks-admin-main 2021-08-30 05-36-35 failed to terminate' }, Jobs_Monitor_Tab_Info_Pane: { Pending_State: 'Pending', @@ -732,10 +735,10 @@ export default { }, No_Data_Message: { Common_Message_Jobs_Monitoring: - /No data matches the filter: "Start time: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: test"/, + /No data matches the filter: "Start time: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, Common_Message_Monitor_Jobs_Name: /No data matches the filter: "Name: (.+?)"/, Common_Message_Jobs_Monitoring_Workflow_Project: - /No data matches the filter: "Created at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: test"/, + /No data matches the filter: "Created at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, Common_Message_Jobs_Monitoring_Status: /No data matches the filter: "Created at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Status: (.+?)"/, Common_Message_Jobs_Monitoring_Type: @@ -743,7 +746,7 @@ export default { Common_Message_Monitor_Jobs: /No data matches the filter: "Start time: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}"/, Common_Message_Jobs_Monitoring_Scheduled: - /No data matches the filter: "Scheduled at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: test"/, + /No data matches the filter: "Scheduled at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, Common_Message: 'No data matches the filter: "Version Tag: latest, Name: ccccc"', Common_Message_Feature: 'No data matches the filter: "Version Tag: latest"', Common_Message_Feature_Vector_Tab: diff --git a/tests/features/common/page-objects/jobs-and-workflows.po.js b/tests/features/common/page-objects/jobs-and-workflows.po.js index 422496f6df..b7ad3ea96f 100644 --- a/tests/features/common/page-objects/jobs-and-workflows.po.js +++ b/tests/features/common/page-objects/jobs-and-workflows.po.js @@ -460,6 +460,8 @@ const commonCustomRangeFilter = dropdownComponent( ) ) +const commonActionMenu = actionMenu(actionMenuStructure) + export default { JobsMonitorTab: { Jobs_Tab_Selector: jobsTabSelector, @@ -504,10 +506,12 @@ export default { Date_Time_Picker: datepicker(dateTimePickerCalendars), Workflows_Monitor_Table: commonTable(workflowsMonitorTable), Toggle_View_Button: By.css('.workflow-container .actions .toggle-view-btn'), + Terminate_Button: By.css('.workflow-container .btn-danger'), Workflow_List_View_Table: commonTable(jobsMonitorTable), Workflow_Graph: graph(monitorWorkflowGraph), Table_Refresh_Button: tableRefreshButton, - Monitor_Workflows_Subtitle: By.css('.table-container .monitor-workflows__subtitle') + Monitor_Workflows_Subtitle: By.css('.table-container .monitor-workflows__subtitle'), + Action_Menu: commonActionMenu, }, ScheduleMonitorTab: { Table_Name_Filter_Input: commonTableNameFilter, diff --git a/tests/features/common/page-objects/jobs-monitoring.po.js b/tests/features/common/page-objects/jobs-monitoring.po.js index 4d7a6b2731..123ba5e307 100644 --- a/tests/features/common/page-objects/jobs-monitoring.po.js +++ b/tests/features/common/page-objects/jobs-monitoring.po.js @@ -35,9 +35,9 @@ const tabSelector = { root: '.content .content-menu', header: {}, body: { - root: '.content-menu__list', + root: '.content-menu__tabs', row: { - root: '.content-menu__item', + root: '.content-menu__tab', fields: { key: '' } @@ -277,6 +277,7 @@ const dateTimePickerCalendars = { const commonRefreshButton = By.css('[data-testid="refresh"]') const commonErrorMessage = By.css('[data-testid="no-data"] h3') +const commonActionMenu = actionMenu(actionMenuStructure) export default { crossJobsMonitorTab: { @@ -309,7 +310,11 @@ export default { Date_Time_Picker: datepicker(dateTimePickerCalendars), Refresh_Button: commonRefreshButton, Error_Message: commonErrorMessage, - Workflows_Table: commonTable(overallTable) + Workflows_Table: commonTable(overallTable), + Action_Menu: commonActionMenu, + Toggle_View_Button: By.css('.workflow-container .actions .toggle-view-btn'), + Terminate_Button: By.css('.workflow-container .btn-danger'), + Workflow_List_View_Table: commonTable(overallTable) }, crossScheduledMonitorTab: { Cross_Jobs_Tab_Selector: commonTable(tabSelector), diff --git a/tests/features/featureStore.feature b/tests/features/featureStore.feature index 1e7025702a..00c3a282b9 100644 --- a/tests/features/featureStore.feature +++ b/tests/features/featureStore.feature @@ -774,6 +774,7 @@ Feature: Feature Store Page Then verify "Feature_Set_Name_Input" on "New_Feature_Set" wizard should display options "Input_Hint"."Feature_Set_Name_Hint" When click on "Accordion_Header" element in "Data_Source_Accordion" on "New_Feature_Set" wizard Then verify "Feature_Set_Name_Input" options rules on "New_Feature_Set" wizard + And wait load page Then type value " " to "Version_Input" field on "New_Feature_Set" wizard Then verify "Version_Input" on "New_Feature_Set" wizard should display options "Input_Hint"."Feature_Set_Version_Hint" When click on "Accordion_Header" element in "Data_Source_Accordion" on "New_Feature_Set" wizard diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index 4e78b93ea3..8170d0e071 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -749,7 +749,7 @@ Feature: Jobs and workflows Then verify "Title" element visibility on "Modal_Transition_Popup" wizard Then "Title" element on "Modal_Transition_Popup" should contains "aggregate" value Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard - Then "Data_Status" element on "Modal_Transition_Popup" should contains "Nov 25, 2021, 05:20:00 PM" value + Then "Data_Status" element on "Modal_Transition_Popup" should contains "Nov 25, 2021, 04:20:00 PM" value Then verify "State_Icon" element visibility on "Modal_Transition_Popup" wizard Then verify "State_Icon" element on "Modal_Transition_Popup" wizard should display hover tooltip "ML_Function_Info_Pane"."Initialized_State" Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard @@ -960,8 +960,99 @@ Feature: Jobs and workflows Then verify "Workflows_Monitor_Table" element visibility on "Workflows_Monitor_Tab" wizard When click on cell with row index 1 in "name" column in "Workflows_Monitor_Table" table on "Workflows_Monitor_Tab" wizard And wait load page + Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then "Terminate_Button" element on "Workflows_Monitor_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is disabled + Then verify "Toggle_View_Button" element visibility on "Workflows_Monitor_Tab" wizard Then click on "Toggle_View_Button" element on "Workflows_Monitor_Tab" wizard + And wait load page Then verify "Workflow_List_View_Table" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then "Terminate_Button" element on "Workflows_Monitor_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is disabled + When click on cell with row index 1 in "name" column in "Workflow_List_View_Table" table on "Workflows_Monitor_Tab" wizard + And wait load page + Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Updated" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Cross_Close_Button" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard should contains "Jobs_Monitor_Tab_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then "Terminate_Button" element on "Workflows_Monitor_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is disabled + Then select "project" with "stocks-admin" value in breadcrumbs menu + And wait load page + Then verify breadcrumbs "project" label should be equal "stocks-admin" value + When click on cell with row index 1 in "name" column in "Workflows_Monitor_Table" table on "Workflows_Monitor_Tab" wizard + And wait load page + Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then "Terminate_Button" element on "Workflows_Monitor_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is enabled + Then click on "Terminate_Button" element on "Workflows_Monitor_Tab" wizard + And wait load page + Then verify if "Confirm_Popup" popup dialog appears + Then "Title" element on "Confirm_Popup" should contains "Terminate workflow" value + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + Then verify "Confirm_Dialog_Message" element visibility on "Confirm_Popup" wizard + Then "Confirm_Dialog_Message" component on "Confirm_Popup" should be equal "Jobs_And_Workflows"."Terminate_Workflow_Message" + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + Then "Cancel_Button" element on "Confirm_Popup" should contains "Cancel" value + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + Then "Delete_Button" element on "Confirm_Popup" should contains "Terminate" value + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Workflows_Monitor_Tab" wizard + And wait load page + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cross_Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Workflows_Monitor_Tab" wizard + And wait load page + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + When click on "Delete_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is enabled + Then verify "Workflow_List_View_Table" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then "Terminate_Button" element on "Workflows_Monitor_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is enabled + When click on cell with row index 1 in "name" column in "Workflow_List_View_Table" table on "Workflows_Monitor_Tab" wizard + And wait load page + Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Updated" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Cross_Close_Button" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard should contains "ML_Function_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard + Then click on "Terminate_Button" element on "Workflows_Monitor_Tab" wizard + And wait load page + Then verify if "Confirm_Popup" popup dialog appears + Then "Title" element on "Confirm_Popup" should contains "Terminate workflow" value + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + Then verify "Confirm_Dialog_Message" element visibility on "Confirm_Popup" wizard + Then "Confirm_Dialog_Message" component on "Confirm_Popup" should be equal "Jobs_And_Workflows"."Terminate_Workflow_Message" + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + Then "Cancel_Button" element on "Confirm_Popup" should contains "Cancel" value + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + Then "Delete_Button" element on "Confirm_Popup" should contains "Terminate" value + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Workflows_Monitor_Tab" wizard + And wait load page + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + When click on "Delete_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard @MLJW @passive @@ -1250,6 +1341,37 @@ Feature: Jobs and workflows And wait load page Then verify "Monitor Workflows" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify options in action menu on "Workflows_Monitor_Tab" wizard in "Workflows_Monitor_Table" table with "Completed" value in "status" column should contains "Jobs_And_Workflows"."Workflows_Action_Menu_Options" + Then check that "Terminate" option in action menu on "Workflows_Monitor_Tab" wizard is disabled + Then select "project" with "stocks-admin" value in breadcrumbs menu + And wait load page + Then verify breadcrumbs "project" label should be equal "stocks-admin" value + Then verify options in action menu on "Workflows_Monitor_Tab" wizard in "Workflows_Monitor_Table" table with "Running" value in "status" column should contains "Jobs_And_Workflows"."Workflows_Running_Action_Menu_Options" + Then check that "Terminate" option in action menu on "Workflows_Monitor_Tab" wizard is enabled + Then select "Terminate" option in action menu on "Workflows_Monitor_Tab" wizard in "Workflows_Monitor_Table" table at row with "main 2021-08-30 05-36-35" value in "name" column + Then verify if "Confirm_Popup" popup dialog appears + Then "Title" element on "Confirm_Popup" should contains "Terminate workflow" value + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + Then verify "Confirm_Dialog_Message" element visibility on "Confirm_Popup" wizard + Then "Confirm_Dialog_Message" component on "Confirm_Popup" should be equal "Jobs_And_Workflows"."Terminate_Workflow_Message" + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + Then "Cancel_Button" element on "Confirm_Popup" should contains "Cancel" value + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + Then "Delete_Button" element on "Confirm_Popup" should contains "Terminate" value + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then select "Terminate" option in action menu on "Workflows_Monitor_Tab" wizard in "Workflows_Monitor_Table" table at row with "main 2021-08-30 05-36-35" value in "name" column + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cross_Cancel_Button" element on "Confirm_Popup" wizard + Then select "Terminate" option in action menu on "Workflows_Monitor_Tab" wizard in "Workflows_Monitor_Table" table at row with "main 2021-08-30 05-36-35" value in "name" column + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + When click on "Delete_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard @MLJW @passive @@ -1483,6 +1605,7 @@ Feature: Jobs and workflows And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Jobs and workflows" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And wait load page + And wait load page And select "Schedule" tab in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard And wait load page Then select "Run now" option in action menu on "Schedule_Monitor_Tab" wizard in "Schedule_Monitor_Table" table at row with "erann-test" value in "name" column @@ -1557,6 +1680,7 @@ Feature: Jobs and workflows And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Jobs and workflows" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And wait load page + And wait load page And select "Schedule" tab in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard And wait load page Then click on cell with row index 2 in "name" column in "Schedule_Monitor_Table" table on "Schedule_Monitor_Tab" wizard diff --git a/tests/features/jobsMonitoring.feature b/tests/features/jobsMonitoring.feature index d6d63ea0ae..91fbd51eee 100644 --- a/tests/features/jobsMonitoring.feature +++ b/tests/features/jobsMonitoring.feature @@ -33,7 +33,8 @@ Feature: Jobs Monitoring Page Then "Auto_Refresh_Checkbox" element should be unchecked on "Jobs_Monitoring_Jobs_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard Then "Title" element on "FilterBy_Popup" should contains "Filter by" value - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Status_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Status_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Jobs_Status_Filter_Options" @@ -112,8 +113,8 @@ Feature: Jobs Monitoring Page When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard - Then type value "test" to "Table_Project_Filter_Input" field on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + When select "churn-project-admin" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard And wait load page Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page @@ -139,8 +140,9 @@ Feature: Jobs Monitoring Page And select "Scheduled" tab in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Scheduled_Tab" wizard And select "Jobs" tab in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Jobs_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard - Then type value "cat-vs-dog-classification" to "Table_Project_Filter_Input" field on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "cat-vs-dog-classification" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page Then value in "project_name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "cat-vs-dog-classification" @@ -539,7 +541,8 @@ Feature: Jobs Monitoring Page Then verify "Workflows_Table" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard Then "Title" element on "FilterBy_Popup" should contains "Filter by" value - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Status_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Status_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Workflows_Status_Filter_Options" @@ -603,8 +606,8 @@ Feature: Jobs Monitoring Page When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard - Then type value "test" to "Table_Project_Filter_Input" field on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + When select "auto-generated-data" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard And wait load page Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page @@ -641,8 +644,9 @@ Feature: Jobs Monitoring Page And select "Scheduled" tab in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Scheduled_Tab" wizard And select "Workflows" tab in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Workflows_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard - Then type value "cat-vs-dog-classification" to "Table_Project_Filter_Input" field on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "cat-vs-dog-classification" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page Then value in "project_name" column with "text" in "Workflows_Table" on "Jobs_Monitoring_Workflows_Tab" wizard should contains "cat-vs-dog-classification" @@ -677,8 +681,178 @@ Feature: Jobs Monitoring Page Then verify "Workflows_Table" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard Then verify that 3 row elements are displayed in "Workflows_Table" on "Jobs_Monitoring_Workflows_Tab" wizard When pick up "Custom range" from "09/03/2024 00:00" to "09/04/2024 00:00" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page Then verify from "09/03/2024 00:00" to "09/04/2024 00:00" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard And wait load page + + @MLJM + @smoke + Scenario: MLJM015 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status + Given open url + And wait load page + When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Workflows_Tab" wizard selected option value "Any time" + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "stocks-admin" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify options in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "Running" value in "status" column should contains "Jobs_And_Workflows"."Workflows_Running_Action_Menu_Options" + Then check that "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard is enabled + And wait load page + Then select "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table at row with "main 2021-08-30 05-36-35" value in "name" column + Then verify if "Confirm_Popup" popup dialog appears + Then "Title" element on "Confirm_Popup" should contains "Terminate workflow" value + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + Then verify "Confirm_Dialog_Message" element visibility on "Confirm_Popup" wizard + Then "Confirm_Dialog_Message" component on "Confirm_Popup" should be equal "Jobs_And_Workflows"."Terminate_Workflow_Message" + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + Then "Cancel_Button" element on "Confirm_Popup" should contains "Cancel" value + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + Then "Delete_Button" element on "Confirm_Popup" should contains "Terminate" value + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then select "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table at row with "main 2021-08-30 05-36-35" value in "name" column + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cross_Cancel_Button" element on "Confirm_Popup" wizard + Then select "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table at row with "main 2021-08-30 05-36-35" value in "name" column + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + When click on "Delete_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + When click on cell with row index 1 in "name" column in "Workflows_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is enabled + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cross_Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + When click on "Delete_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Toggle_View_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then click on "Toggle_View_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Workflow_List_View_Table" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is enabled + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cross_Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + When click on "Delete_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + When click on cell with row index 1 in "name" column in "Workflow_List_View_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Updated" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Cross_Close_Button" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard should contains "ML_Function_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is enabled + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + When click on "Cross_Cancel_Button" element on "Confirm_Popup" wizard + Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + When click on "Delete_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + + @MLJM + @smoke + Scenario: MLJM016 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with compleated status + Given open url + And wait load page + When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Workflows_Tab" wizard selected option value "Any time" + Then verify "Workflows" tab is active in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify options in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "Completed" value in "status" column should contains "Jobs_And_Workflows"."Workflows_Action_Menu_Options" + Then check that "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard is disabled + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "cat-vs-dog-classification" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with row index 1 in "name" column in "Workflows_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled + Then verify "Toggle_View_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then click on "Toggle_View_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Workflow_List_View_Table" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled + When click on cell with row index 1 in "name" column in "Workflows_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Updated" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Cross_Close_Button" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard should contains "Jobs_Monitor_Tab_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard + Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled @MLJM @smoke @@ -776,7 +950,8 @@ Feature: Jobs Monitoring Page Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then "Title" element on "FilterBy_Popup" should contains "Filter by" value - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" @@ -809,7 +984,8 @@ Feature: Jobs Monitoring Page Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then "Title" element on "FilterBy_Popup" should contains "Filter by" value - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Job" Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" @@ -837,7 +1013,8 @@ Feature: Jobs Monitoring Page Then verify "Table_FilterBy_Button" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then "Title" element on "FilterBy_Popup" should contains "Filter by" value - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" @@ -858,8 +1035,9 @@ Feature: Jobs Monitoring Page And wait load page Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard - Then type value "test" to "Table_Project_Filter_Input" field on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "auto-generated-data" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard And wait load page Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page @@ -886,10 +1064,13 @@ Feature: Jobs Monitoring Page Then verify that 2 row elements are displayed in "Scheduled_Table" on "Jobs_Monitoring_Scheduled_Tab" wizard Then value in "name" column with "text" in "Scheduled_Table" on "Jobs_Monitoring_Scheduled_Tab" wizard should contains "clean" And select "Workflows" tab in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page And select "Scheduled" tab in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Scheduled_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard - Then verify "Table_Project_Filter_Input" element visibility on "FilterBy_Popup" wizard - Then type value "default" to "Table_Project_Filter_Input" field on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "default" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + And wait load page Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page Then value in "project_name" column with "text" in "Scheduled_Table" on "Jobs_Monitoring_Scheduled_Tab" wizard should contains "default" @@ -925,6 +1106,8 @@ Feature: Jobs Monitoring Page Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then verify that 8 row elements are displayed in "Scheduled_Table" on "Jobs_Monitoring_Scheduled_Tab" wizard When pick up "Custom range" from "09/03/2024 00:00" to "09/04/2024 00:00" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitoring_Scheduled_Tab" wizard + And wait load page + And wait load page Then verify from "09/03/2024 00:00" to "09/04/2024 00:00" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Scheduled_Tab" wizard And wait load page diff --git a/tests/features/projectsPage.feature b/tests/features/projectsPage.feature index 06b3d25482..6d446f628f 100644 --- a/tests/features/projectsPage.feature +++ b/tests/features/projectsPage.feature @@ -313,6 +313,7 @@ Feature: Projects Page Then verify breadcrumbs "tab" label should be equal "Project monitoring" value And click on cell with value "Feature store" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And wait load page + And wait load page Then verify breadcrumbs "tab" label should be equal "Feature store" value And click on cell with value "Datasets" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And wait load page @@ -512,6 +513,7 @@ Feature: Projects Page Then "Total_Scheduled_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Total" value Then verify "Total_Scheduled_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard When click on "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard + And wait load page Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value @@ -562,6 +564,7 @@ Feature: Projects Page Then verify "Total_Alerts_Number" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard Then "Total_Alerts_Number" element in "Monitoring_Alerts_Box" on "Projects" should contains "39" value When click on "Total_Alerts_Number" element in "Monitoring_Alerts_Box" on "Projects" wizard + And wait load page Then verify redirection to "projects/*/alerts-monitoring?bePage=1&fePage=1" Then verify breadcrumbs "cross" label should be equal "Alerts monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value diff --git a/tests/mockServer/data/pipelines.json b/tests/mockServer/data/pipelines.json index e2556b2aa9..d931d3e65b 100644 --- a/tests/mockServer/data/pipelines.json +++ b/tests/mockServer/data/pipelines.json @@ -204,7 +204,7 @@ "created_at": "2021-08-30 05:36:36+00:00", "scheduled_at": "1970-01-01 00:00:00+00:00", "finished_at": "2021-08-30 05:38:29+00:00", - "status": "Error", + "status": "Running", "error": "None", "project": "stocks-admin" } diff --git a/tests/mockServer/data/piplineIDs.json b/tests/mockServer/data/piplineIDs.json index d3f0ac3aca..22a3b7fb2d 100644 --- a/tests/mockServer/data/piplineIDs.json +++ b/tests/mockServer/data/piplineIDs.json @@ -1558,7 +1558,7 @@ "created_at": "2021-08-30 05:36:36+00:00", "scheduled_at": "1970-01-01 00:00:00+00:00", "finished_at": "2021-08-30 05:38:29+00:00", - "status": "Error", + "status": "Running", "error": "None", "project": "stocks-admin", "message": "" From ff73252cdbb4484dae359416c94f39e195c8472c Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 30 Jun 2025 10:46:31 +0300 Subject: [PATCH 039/228] Fix [UI] Unexpected application error (#3308) --- src/components/Alerts/Alerts.jsx | 2 +- .../ProjectStatisticsCounter.jsx | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/components/Alerts/Alerts.jsx b/src/components/Alerts/Alerts.jsx index a07a87dc39..eb61454064 100644 --- a/src/components/Alerts/Alerts.jsx +++ b/src/components/Alerts/Alerts.jsx @@ -149,7 +149,7 @@ const Alerts = () => { withRefreshButton withoutExpandButton > - +
      {alertsStore.loading && } diff --git a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx index 99e4057cff..b9f2a6bd95 100644 --- a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx +++ b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx @@ -24,6 +24,7 @@ import classnames from 'classnames' import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import Arrow from 'igz-controls/images/arrow.svg?react' +import { isNil } from 'lodash' const ProjectStatisticsCounter = ({ counterObject }) => { const MAX_VISIBLE_COUNTER = 999999 @@ -34,19 +35,25 @@ const ProjectStatisticsCounter = ({ counterObject }) => { ) const generatedCountersContent = useMemo(() => { - const displayValue = counterObject.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + if (!isNil(counterObject.value)) { + const displayValue = counterObject.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + + if (Number(counterObject.value) < MAX_VISIBLE_COUNTER) { + return { + value: displayValue + } + } + + const truncatedValue = Math.floor(counterObject.value / 100000) / 10 - if (Number(counterObject.value) < MAX_VISIBLE_COUNTER) { return { - value: displayValue + value: (truncatedValue % 1 === 0 ? Math.floor(truncatedValue) : truncatedValue) + 'M', + tooltip: ` (${displayValue})` } } - const truncatedValue = Math.floor(counterObject.value / 100000) / 10 - return { - value: (truncatedValue % 1 === 0 ? Math.floor(truncatedValue) : truncatedValue) + 'M', - tooltip: ` (${displayValue})` + value: counterObject.value } }, [counterObject.value]) From fdf85853a057e0bfa5f044696cd96b75b630949a Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 30 Jun 2025 10:46:45 +0300 Subject: [PATCH 040/228] Impl [Workflows] Add mock for retry functionality (#3314) --- src/components/Details/details.util.js | 1 - tests/mockServer/mock.js | 45 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/components/Details/details.util.js b/src/components/Details/details.util.js index b9e56b4c83..3df7867218 100644 --- a/src/components/Details/details.util.js +++ b/src/components/Details/details.util.js @@ -33,7 +33,6 @@ import { DATASETS_PAGE, DOCUMENTS_PAGE, FEATURE_SETS_TAB, - FEATURE_STORE_PAGE, FEATURE_VECTORS_TAB, FILES_PAGE, FUNCTION_TYPE_APPLICATION, diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index f65ac7a7c3..26e36e5c41 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -1730,6 +1730,50 @@ function getPipeline(req, res) { res.send(collectedPipeline) } +function pipelineRetry(req, res) { + const originalPipelineID = pipelineIDs.find( + item => item.run.id === req.params.pipelineID && item.run.project === req.params.project + ) + const originalPipeline = (pipelines[req.params.project]?.runs ?? []).find(pipeline => { + return pipeline.id = req.params.pipelineID + }) + if (originalPipeline) { + const runID = makeUID(32) + const newPipelineID = { + ...originalPipelineID, + run: { + ...originalPipelineID.run, + id: runID, + name: `Retry of ${originalPipelineID.run.name}`, + status: 'Running' + } + } + const newPipeline = { + ...originalPipeline, + id: runID, + name: `Retry of ${originalPipeline.name}`, + status: 'Running' + } + + pipelines[req.params.project]?.runs.push(newPipeline) + pipelineIDs.push(newPipelineID) + + setTimeout(() => { + newPipelineID.run.status = 'Failed' + newPipeline.status = 'Failed' + }, 5000) + + res.send(runID) + } else { + res.statusCode = 404 + res.send({ + detail: { + reason: `MLRunNotFoundError('Workflow not found ${req.params.project}/${req.params.pipelineID}')` + } + }) + } +} + function getFuncs(req, res) { const dt = parseInt(Date.now()) const collectedFuncsByPrjTime = funcs.funcs @@ -2853,6 +2897,7 @@ app.put(`${mlrunAPIIngress}/projects/:project/schedules/:schedule/`, updateSched app.get(`${mlrunAPIIngress}/projects/:project/pipelines`, getPipelines) app.get(`${mlrunAPIIngress}/projects/*/pipelines`, getPipelines) app.get(`${mlrunAPIIngress}/projects/:project/pipelines/:pipelineID`, getPipeline) +app.post(`${mlrunAPIIngress}/projects/:project/pipelines/:pipelineID/retry`, pipelineRetry) app.get(`${mlrunAPIIngress}/projects/:project/artifact-tags`, getProjectsArtifactTags) app.get(`${mlrunAPIIngressV2}/projects/:project/artifacts`, getArtifacts) From 6bca7c275d740600456664da03596d1f617d7517 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 30 Jun 2025 10:46:57 +0300 Subject: [PATCH 041/228] Fix [Project settings] Project secrets are not displayed (#3315) --- src/reducers/projectReducer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reducers/projectReducer.js b/src/reducers/projectReducer.js index 6959d1f581..05ce577d1e 100644 --- a/src/reducers/projectReducer.js +++ b/src/reducers/projectReducer.js @@ -497,7 +497,7 @@ const projectStoreSlice = createSlice({ }) builder.addCase(fetchProjectSecrets.fulfilled, (state, action) => { state.project.secrets = { - data: action.payload, + data: action.payload.data, error: null, loading: false } From c7e52d943d3c19f1cc858f309d7bac51bce987c1 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Tue, 1 Jul 2025 15:33:01 +0300 Subject: [PATCH 042/228] Impl [Projects Counters] Update "Projects" and "Monitoring" Page counters and Add New Sections (#3317) --- src/common/StatsCard/StatsCard.jsx | 10 +- src/common/StatsCard/statsCard.scss | 26 ++- src/components/Project/ProjectMonitorView.jsx | 41 +--- src/components/Project/project.scss | 16 ++ .../ProjectsMonitoring/ProjectsMonitoring.jsx | 23 ++- .../projectsMonitoring.scss | 62 +++++- src/components/ProjectsPage/projects.scss | 1 - src/components/ProjectsPage/projects.util.jsx | 22 ++ .../AlertsCounters.jsx | 177 +++++++++------- .../ApplicationCounters.jsx | 65 ++++++ .../ArtifactsCounters.jsx | 157 ++++++++++++++ .../ModelsCounters.jsx | 65 ++++++ .../RunsCounters.jsx | 109 ++++++++++ .../ScheduledJobsCounters.jsx | 185 ++++++++++------- .../WorkflowsCounters.jsx | 191 +++++++++++------- .../projectsMonitoringCounters.scss | 187 ++++++++++++----- src/utils/generateMonitoringData.js | 105 ++++++++-- 17 files changed, 1098 insertions(+), 344 deletions(-) create mode 100644 src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx create mode 100644 src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx create mode 100644 src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx create mode 100644 src/elements/ProjectsMonitoringCounters/RunsCounters.jsx diff --git a/src/common/StatsCard/StatsCard.jsx b/src/common/StatsCard/StatsCard.jsx index 55a7381b64..73e7bbeca6 100644 --- a/src/common/StatsCard/StatsCard.jsx +++ b/src/common/StatsCard/StatsCard.jsx @@ -18,10 +18,10 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import React from 'react' -import PropTypes from 'prop-types' import classNames from 'classnames' +import PropTypes from 'prop-types' -import { Tip } from 'igz-controls/components' +import { TextTooltipTemplate, Tip, Tooltip } from 'igz-controls/components' import './statsCard.scss' @@ -43,8 +43,10 @@ StatsCard.Header = ({ children = null, icon = null, iconClass = '', title = '',
      {icon && {icon}} - {title && {title}} - {tip && } +
      + }>{title} + {tip && } +
      {children}
      diff --git a/src/common/StatsCard/statsCard.scss b/src/common/StatsCard/statsCard.scss index c951a442a1..0cf65f04bc 100644 --- a/src/common/StatsCard/statsCard.scss +++ b/src/common/StatsCard/statsCard.scss @@ -3,26 +3,26 @@ .stats { &-card { + position: relative; display: flex; flex-wrap: wrap; - position: relative; + padding: 15px; color: colors.$topaz; background-color: colors.$white; border-radius: 8px; box-shadow: shadows.$previewBoxShadowInit; - padding: 15px; transition: all 0.3s ease-in-out; @media screen and (min-width: 1500px) { - padding: 20px 25px 15px; + padding: 20px 20px 5px; } &__row { display: flex; - flex-flow: row nowrap; flex: 1 0 100%; - justify-content: space-between; + flex-flow: row nowrap; align-items: baseline; + justify-content: space-between; &:not(:last-child) { margin-bottom: 1em; @@ -42,11 +42,12 @@ &__title { position: relative; display: flex; + gap: 6px; align-items: center; + margin: 0; color: colors.$primary; font-weight: normal; font-size: 1rem; - margin: 0; transition: font-size 0.3s ease-in-out; @media screen and (min-width: 1600px) { @@ -63,20 +64,20 @@ &-icon { position: absolute; - left: 0; top: 1px; - height: 16px; + left: 0; width: 16px; + height: 16px; transition: all 0.3s ease-in-out; @media screen and (min-width: 1600px) { - height: 20px; width: 20px; + height: 20px; } svg { - height: inherit; width: inherit; + height: inherit; path { fill: colors.$ceriseRed; @@ -88,5 +89,10 @@ &__title-tip { margin-left: 5px; } + + &__title-wrapper { + display: flex; + align-items: normal; + } } } diff --git a/src/components/Project/ProjectMonitorView.jsx b/src/components/Project/ProjectMonitorView.jsx index 090d790f02..83e4c7f901 100644 --- a/src/components/Project/ProjectMonitorView.jsx +++ b/src/components/Project/ProjectMonitorView.jsx @@ -21,21 +21,21 @@ import React from 'react' import PropTypes from 'prop-types' import { isEmpty } from 'lodash' -import AlertsCounters from '../../elements/ProjectsMonitoringCounters/AlertsCounters' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import FeatureSetsPanel from '../FeatureSetsPanel/FeatureSetsPanel' import FunctionsPanel from '../FunctionsPanel/FunctionsPanel' import NewFunctionPopUp from '../../elements/NewFunctionPopUp/NewFunctionPopUp' import NoData from '../../common/NoData/NoData' -import ProjectFunctions from '../../elements/ProjectFunctions/ProjectFunctions' import ProjectDetailsHeader from '../../common/ProjectDetailsHeader/ProjectDetailsHeader' +import ProjectFunctions from '../../elements/ProjectFunctions/ProjectFunctions' import ProjectJobs from '../../elements/ProjectJobs/ProjectJobs' -import ProjectSummaryCard from '../../elements/ProjectSummaryCard/ProjectSummaryCard' +import ProjectsMonitoring from '../ProjectsPage/ProjectsMonitoring/ProjectsMonitoring' import Select from '../../common/Select/Select' + import { ConfirmDialog, RoundedIcon, Loader } from 'igz-controls/components' import { PANEL_CREATE_MODE } from '../../constants' -import { launchIDEOptions, generateTipMessageForCounter } from './project.utils' +import { launchIDEOptions } from './project.utils' import RefreshIcon from 'igz-controls/images/refresh.svg?react' @@ -56,7 +56,6 @@ const ProjectMonitorView = ({ nuclioStreamsAreEnabled, params, project, - projectSummary, refresh, setIsNewFunctionPopUpOpen, setShowFunctionsPanel, @@ -123,36 +122,7 @@ const ProjectMonitorView = ({
      -
      -
      - - - - - -
      -
      - -
      -
      +
      @@ -208,7 +178,6 @@ ProjectMonitorView.propTypes = { nuclioStreamsAreEnabled: PropTypes.bool.isRequired, params: PropTypes.object.isRequired, project: PropTypes.object.isRequired, - projectSummary: PropTypes.object.isRequired, refresh: PropTypes.func.isRequired, setIsNewFunctionPopUpOpen: PropTypes.func.isRequired, setShowFunctionsPanel: PropTypes.func.isRequired, diff --git a/src/components/Project/project.scss b/src/components/Project/project.scss index c0fc327790..66b5a076a9 100644 --- a/src/components/Project/project.scss +++ b/src/components/Project/project.scss @@ -254,6 +254,10 @@ flex: 2; } } + + @media (max-width: 1250px) { + grid-template-columns: repeat(1, 2fr); + } } } } @@ -263,3 +267,15 @@ color: colors.$primary; } } + +main.unpinned { + .main-info__statistics-section { + @media (max-width: 1250px) { + grid-template-columns: repeat(2, 1fr); + } + + @media (max-width: 1100px) { + grid-template-columns: repeat(1, 2fr); + } + } +} diff --git a/src/components/ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx b/src/components/ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx index 244b2f602f..6cce0194cd 100644 --- a/src/components/ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx +++ b/src/components/ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx @@ -17,23 +17,40 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import classNames from 'classnames' +import { useParams } from 'react-router-dom' + import AlertsCounters from '../../../elements/ProjectsMonitoringCounters/AlertsCounters' -import JobsCounters from '../../../elements/ProjectsMonitoringCounters/JobsCounters' +import ApplicationCounter from '../../../elements/ProjectsMonitoringCounters/ApplicationCounters' +import DataAndArtifactsCounter from '../../../elements/ProjectsMonitoringCounters/ArtifactsCounters' +import ModelsAndApplication from '../../../elements/ProjectsMonitoringCounters/ModelsCounters' import PageHeader from '../../../elements/PageHeader/PageHeader' +import RunCounter from '../../../elements/ProjectsMonitoringCounters/RunsCounters' import ScheduledJobsCounters from '../../../elements/ProjectsMonitoringCounters/ScheduledJobsCounters' import WorkflowsCounters from '../../../elements/ProjectsMonitoringCounters/WorkflowsCounters' import './projectsMonitoring.scss' const ProjectsMonitoring = () => { + const { projectName } = useParams() + const monitoringStatsClassName = classNames( + 'projects-monitoring-stats', + projectName ? 'projects-monitoring-stats_narrow' : 'projects-monitoring-stats_wide' + ) + return (
      -
      - +
      + + {!projectName && } {/* Todo: Delete WorkflowsCounters after ML-5460 is impplemented */} +
      + + +
      {/* Todo: implement as part of ML-5460 */} diff --git a/src/components/ProjectsPage/ProjectsMonitoring/projectsMonitoring.scss b/src/components/ProjectsPage/ProjectsMonitoring/projectsMonitoring.scss index 268b998544..b0967eced4 100644 --- a/src/components/ProjectsPage/ProjectsMonitoring/projectsMonitoring.scss +++ b/src/components/ProjectsPage/ProjectsMonitoring/projectsMonitoring.scss @@ -11,11 +11,35 @@ &-stats { display: grid; - grid-template-columns: repeat(2, 1fr); gap: 15px; - @media screen and (min-width: 1400px) { - grid-template-columns: 4fr 4fr 3.5fr 4fr; + &_narrow { + grid-template-columns: repeat(5, 1fr); + + @media (max-width: 1250px) { + grid-template-columns: repeat(6, 1fr); + gap: 10px; + } + } + + &_wide { + grid-template-columns: repeat(6, 1fr); + + @media (max-width: 1150px) { + .monitoring-stats .project-card__info { + display: none; + } + } + + @media (max-width: 1250px) { + grid-template-columns: repeat(6, 1fr); + gap: 10px; + } + + @media (max-width: 1100px) { + grid-template-columns: repeat(7, 1fr); + gap: 10px; + } } } @@ -23,3 +47,35 @@ margin-left: 5px; } } + +main.unpinned { + .projects-monitoring-stats_narrow { + @media (max-width: 1250px) { + grid-template-columns: repeat(5, 1fr); + gap: 10px; + } + + @media (max-width: 1100px) { + grid-template-columns: repeat(6, 1fr); + gap: 10px; + } + } + + .projects-monitoring-stats_wide { + @media (max-width: 1150px) { + .monitoring-stats .project-card__info { + display: none; + } + } + + @media (max-width: 1250px) { + grid-template-columns: repeat(6, 1fr); + gap: 10px; + } + + @media (max-width: 1100px) { + grid-template-columns: repeat(7, 1fr); + gap: 10px; + } + } +} diff --git a/src/components/ProjectsPage/projects.scss b/src/components/ProjectsPage/projects.scss index 8e87c05f06..238a6ea971 100644 --- a/src/components/ProjectsPage/projects.scss +++ b/src/components/ProjectsPage/projects.scss @@ -35,7 +35,6 @@ &__col { display: flex; flex: 1; - margin-bottom: 1rem; &-right { diff --git a/src/components/ProjectsPage/projects.util.jsx b/src/components/ProjectsPage/projects.util.jsx index bab5c38ca9..4038961197 100644 --- a/src/components/ProjectsPage/projects.util.jsx +++ b/src/components/ProjectsPage/projects.util.jsx @@ -292,6 +292,16 @@ export const generateMonitoringCounters = (data, dispatch) => { jobs: 0, application: 0, total: 0 + }, + models: { + total: 0 + }, + artifacts: { + documents: 0, + datasets: 0, + files: 0, + llm_prompts: 0, + total: 0 } } @@ -325,6 +335,18 @@ export const generateMonitoringCounters = (data, dispatch) => { monitoringCounters.alerts.endpoint + monitoringCounters.alerts.jobs + monitoringCounters.alerts.application + + monitoringCounters.models.total += project.models_count || 0 + + monitoringCounters.artifacts.llm_prompts += project.llm_prompts_count || 0 + monitoringCounters.artifacts.datasets += project.datasets_count || 0 + monitoringCounters.artifacts.files += project.files_count || 0 + monitoringCounters.artifacts.documents += project.documents_count || 0 + monitoringCounters.artifacts.total = + monitoringCounters.artifacts.llm_prompts + + monitoringCounters.artifacts.datasets + + monitoringCounters.artifacts.files + + monitoringCounters.artifacts.documents }) dispatch(setJobsMonitoringData(monitoringCounters)) diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index a0a29cc3fa..fdea11e54d 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -17,13 +17,13 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useMemo } from 'react' +import React, { useMemo, useRef, useState } from 'react' +import classNames from 'classnames' import { useNavigate, useParams } from 'react-router-dom' import { useSelector } from 'react-redux' -import classNames from 'classnames' +import { Loader, PopUpDialog } from 'igz-controls/components' import StatsCard from '../../common/StatsCard/StatsCard' -import { Loader } from 'igz-controls/components' import { generateAlertsStats } from '../../utils/generateAlertsStats' @@ -33,9 +33,22 @@ import ClockIcon from 'igz-controls/images/clock.svg?react' import './projectsMonitoringCounters.scss' const AlertsCounters = () => { + const anchorRef = useRef(null) + const detailsRef = useRef(null) + const [showPopup, setShowPopup] = useState(false) const { projectName: paramProjectName } = useParams() const navigate = useNavigate() const projectStore = useSelector(store => store.projectStore) + const timeLabel = paramProjectName ? '24 hrs' : 'Past 24 hrs' + + const handleOpenPopUp = () => { + const isHidden = !detailsRef.current?.offsetParent + setShowPopup(isHidden) + } + + const handleClosePopUp = () => { + setShowPopup(false) + } const alertsData = useMemo(() => { const projectName = paramProjectName ? paramProjectName : '*' @@ -86,82 +99,106 @@ const AlertsCounters = () => { ) return ( - - } iconClass="stats-card__title-icon"> - -
      +
      + +
      + } iconClass="stats-card__title-icon"> +
      + + {timeLabel} +
      +
      +
      - Total -
      - {projectStore.projectsSummary.loading ? ( +
      + {projectStore?.projectsSummary?.loading ? ( ) : ( - (alertsData.data.total || 0).toLocaleString() + alertsData?.data?.total?.toLocaleString() )}
      -
      - -
      - Past 24 hours -
      - - - - -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - (alertsData.data.endpoint || 0).toLocaleString() - )} -
      -
      Endpoint
      -
      -
      - -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - (alertsData.data.jobs || 0).toLocaleString() - )} -
      -
      Jobs
      -
      -
      - -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - (alertsData.data.application || 0).toLocaleString() - )} -
      -
      Application
      + + +
      + +
      +
      Endpoint
      +
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + alertsData?.data?.endpoint?.toLocaleString() + )} +
      +
      +
      + +
      +
      Jobs
      +
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + alertsData?.data?.jobs?.toLocaleString() + )} +
      +
      +
      + +
      +
      Application
      +
      + {projectStore.projectsSummary.loading ? ( + + ) : ( + alertsData?.data?.application?.toLocaleString() + )} +
      +
      +
      - - - + {showPopup && ( + +
      +
      + Endpoint: {alertsData?.data?.endpoint} +
      +
      + Jobs: {alertsData?.data?.jobs} +
      +
      + Application: {alertsData?.data?.application} +
      +
      +
      + )} +
      + +
      ) } diff --git a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx new file mode 100644 index 0000000000..c8c48d1710 --- /dev/null +++ b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx @@ -0,0 +1,65 @@ +/* +Copyright 2019 Iguazio Systems Ltd. +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React, { useMemo } from 'react' +import { useSelector } from 'react-redux' +import { useNavigate, useParams } from 'react-router-dom' + +import { Loader } from 'igz-controls/components' + +import { APPLICATION } from '../../constants' +import StatsCard from '../../common/StatsCard/StatsCard' +import { generateMonitoringStats } from '../../utils/generateMonitoringData' + +import './projectsMonitoringCounters.scss' + +const ApplicationCounter = () => { + const projectStore = useSelector(store => store.projectStore) + const { projectName } = useParams() + const navigate = useNavigate() + + const applicationData = projectName + ? projectStore.projectSummary.data?.application_count || 0 + : projectStore.jobsMonitoringData?.application?.total || 0 + + const data = useMemo( + () => generateMonitoringStats(applicationData, navigate, APPLICATION, projectName), + [applicationData, navigate, projectName] + ) + + return ( + + + +
      +
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + data?.application?.counter?.toLocaleString() + )} +
      +
      +
      +
      + ) +} + +export default React.memo(ApplicationCounter) diff --git a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx new file mode 100644 index 0000000000..baa90c7711 --- /dev/null +++ b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx @@ -0,0 +1,157 @@ +/* +Copyright 2019 Iguazio Systems Ltd. +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ + +import React, { useMemo, useRef, useState } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import { useSelector } from 'react-redux' +import classNames from 'classnames' + +import { Loader, PopUpDialog } from 'igz-controls/components' +import ClockIcon from 'igz-controls/images/clock.svg?react' + +import { ARTIFACTS_PAGE } from '../../constants' +import StatsCard from '../../common/StatsCard/StatsCard' +import { generateMonitoringStats } from '../../utils/generateMonitoringData' + +import './projectsMonitoringCounters.scss' + +const ArtifactsCounters = () => { + const anchorRef = useRef(null) + const detailsRef = useRef(null) + const [showPopup, setShowPopup] = useState(false) + const { projectName } = useParams() + const navigate = useNavigate() + const projectStore = useSelector(store => store.projectStore) + const timeLabel = projectName ? '24 hrs' : 'Past 24 hrs' + + const handleOpenPopUp = () => { + const isHidden = !detailsRef.current?.offsetParent + setShowPopup(isHidden) + } + + const handleClosePopUp = () => { + setShowPopup(false) + } + + const dataStats = useMemo(() => { + if (projectName) { + const llm_prompts = projectStore?.projectSummary?.data?.llm_prompts || 0 + const files = projectStore?.projectSummary?.data?.files_count || 0 + const documents = projectStore?.projectSummary?.data?.documents_count || 0 + const datasets = projectStore?.projectSummary?.data?.datasets_count || 0 + + return { + llm_prompts, + files, + documents, + datasets, + total: llm_prompts + files + datasets + documents + } + } + return ( + projectStore.jobsMonitoringData.artifacts || { + llm_prompts: 0, + files: 0, + documents: 0, + datasets: 0, + total: 0 + } + ) + }, [projectName, projectStore.jobsMonitoringData.artifacts, projectStore.projectSummary.data]) + + const data = useMemo( + () => generateMonitoringStats(dataStats, navigate, ARTIFACTS_PAGE, projectName), + [dataStats, navigate, projectName] + ) + + return ( +
      + +
      + +
      + + {timeLabel} +
      +
      + +
      +
      + {projectStore.projectsSummary.loading ? ( + + ) : ( + data?.total?.counter?.toLocaleString() + )} +
      +
      +
      +
      + +
      +
      Files
      +
      {data?.files?.counter?.toLocaleString()}
      +
      +
      + +
      +
      Datasets
      +
      {data?.datasets.counter?.toLocaleString()}
      +
      +
      + +
      +
      Documents
      +
      {data?.documents?.counter?.toLocaleString()}
      +
      +
      + +
      +
      LLM Prompts
      +
      {data?.llm_prompt?.counter?.toLocaleString()}
      +
      +
      +
      + + {showPopup && ( + +
      + {data.list.map(item => ( +
      + {item.label}: {data[item.key].counter.toLocaleString()} +
      + ))} +
      +
      + )} +
      +
      +
      + ) +} + +export default React.memo(ArtifactsCounters) diff --git a/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx new file mode 100644 index 0000000000..255c8be0e4 --- /dev/null +++ b/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx @@ -0,0 +1,65 @@ +/* +Copyright 2019 Iguazio Systems Ltd. +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React, { useMemo } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import { useSelector } from 'react-redux' + +import { Loader } from 'igz-controls/components' + +import StatsCard from '../../common/StatsCard/StatsCard' +import { MODELS_PAGE } from '../../constants' +import { generateMonitoringStats } from '../../utils/generateMonitoringData' + +import './projectsMonitoringCounters.scss' + +const ModelsAndApplication = () => { + const projectStore = useSelector(store => store.projectStore) + const { projectName } = useParams() + const navigate = useNavigate() + + const modelsData = projectName + ? projectStore.projectSummary.data?.models_count || 0 + : projectStore.jobsMonitoringData?.models?.total || 0 + + const data = useMemo( + () => generateMonitoringStats(modelsData, navigate, MODELS_PAGE, projectName), + [modelsData, navigate, projectName] + ) + + return ( + + + +
      +
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + data?.models?.counter?.toLocaleString() + )} +
      +
      +
      +
      + ) +} + +export default React.memo(ModelsAndApplication) diff --git a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx new file mode 100644 index 0000000000..ee664a38fb --- /dev/null +++ b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx @@ -0,0 +1,109 @@ +/* +Copyright 2019 Iguazio Systems Ltd. +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React, { useMemo } from 'react' +import { useNavigate } from 'react-router-dom' +import { useSelector } from 'react-redux' + +import StatsCard from '../../common/StatsCard/StatsCard' +import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' + +import { generateMonitoringStats } from '../../utils/generateMonitoringData' +import { JOBS_MONITORING_JOBS_TAB } from '../../constants' + +import ClockIcon from 'igz-controls/images/clock.svg?react' + +import './projectsMonitoringCounters.scss' + +const RunCounter = () => { + const navigate = useNavigate() + const projectStore = useSelector(store => store.projectStore) + + const jobStats = useMemo( + () => + generateMonitoringStats( + projectStore.jobsMonitoringData.jobs, + navigate, + JOBS_MONITORING_JOBS_TAB + ), + [navigate, projectStore.jobsMonitoringData.jobs] + ) + + return ( +
      + +
      + +
      + + Past 24 hrs +
      +
      + +
      +
      + {projectStore.projectsSummary.loading ? ( + + ) : ( + jobStats.total.counter.toLocaleString() + )} +
      +
      +
      + +
      + {jobStats?.counters?.map( + ({ counter, className, label, link, statusClass, tooltip }) => { + return ( + +
      +
      + }> +
      {label}
      + +
      +
      +
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + counter.toLocaleString() + )} +
      +
      +
      + ) + } + )} +
      +
      +
      +
      + ) +} + +export default React.memo(RunCounter) diff --git a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx index 28fccda82a..163ea8070f 100644 --- a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx @@ -17,12 +17,12 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useMemo } from 'react' +import React, { useMemo, useRef, useState } from 'react' +import { useNavigate, useParams } from 'react-router-dom' import { useSelector } from 'react-redux' -import { useNavigate } from 'react-router-dom' +import { Loader, PopUpDialog } from 'igz-controls/components' import StatsCard from '../../common/StatsCard/StatsCard' -import { Loader } from 'igz-controls/components' import { generateMonitoringStats } from '../../utils/generateMonitoringData' import { JOBS_MONITORING_SCHEDULED_TAB } from '../../constants' @@ -33,91 +33,134 @@ import './projectsMonitoringCounters.scss' const ScheduledJobsCounters = () => { const navigate = useNavigate() + const { projectName } = useParams() const projectStore = useSelector(store => store.projectStore) + const [showPopup, setShowPopup] = useState(false) + const anchorRef = useRef(null) + const detailsRef = useRef(null) + const timeLabel = projectName ? '24 hrs' : 'Next 24 hrs' + + const handleOpenPopUp = () => { + const isHidden = !detailsRef.current?.offsetParent + setShowPopup(isHidden) + } + + const handleClosePopUp = () => { + setShowPopup(false) + } + + const scheduledData = useMemo(() => { + if (projectName) { + const jobs = projectStore.projectSummary?.data?.distinct_scheduled_jobs_pending_count || 0 + const workflows = + projectStore.projectSummary?.data?.distinct_scheduled_pipelines_pending_count || 0 + + return { + jobs, + workflows, + total: jobs + workflows + } + } + return ( + projectStore?.jobsMonitoringData.scheduled || { + jobs: 0, + workflows: 0, + total: 0 + } + ) + }, [ + projectName, + projectStore.projectSummary?.data?.distinct_scheduled_jobs_pending_count, + projectStore.projectSummary?.data?.distinct_scheduled_pipelines_pending_count, + projectStore.jobsMonitoringData?.scheduled + ]) const scheduledStats = useMemo( - () => - generateMonitoringStats( - projectStore.jobsMonitoringData.scheduled, - navigate, - JOBS_MONITORING_SCHEDULED_TAB - ), - [navigate, projectStore.jobsMonitoringData.scheduled] + () => generateMonitoringStats(scheduledData, navigate, JOBS_MONITORING_SCHEDULED_TAB), + [navigate, scheduledData] ) return ( - - - -
      +
      + +
      + +
      + + {timeLabel} +
      +
      +
      - Total
      - {projectStore.projectsSummary.loading ? ( + {projectStore?.projectsSummary?.loading ? ( ) : ( scheduledStats.total.counter )}
      -
      - -
      - Next 24 hours -
      - - - {/* Todo: Use in the future - */} - - - -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - scheduledStats.jobs.counter - )} -
      -
      Jobs
      -
      -
      - -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - scheduledStats.workflows.counter - )} -
      -
      Workflows
      + +
      + +
      +
      Jobs
      +
      + {projectStore.projectsSummary.loading ? ( + + ) : ( + scheduledStats.jobs.counter.toLocaleString() + )} +
      +
      +
      + +
      +
      Workflows
      +
      + {projectStore.projectsSummary.loading ? ( + + ) : ( + scheduledStats.workflows.counter.toLocaleString() + )} +
      +
      +
      - - - + {showPopup && ( + +
      +
      + Runs: {scheduledStats.workflows.counter} +
      +
      + Workflows: {scheduledStats.workflows.counter} +
      +
      +
      + )} +
      +
      +
      ) } diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index f859f3a3c3..78cc91f2f4 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -17,109 +17,152 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useMemo } from 'react' -import { useNavigate } from 'react-router-dom' +import React, { useMemo, useRef, useState } from 'react' +import { useNavigate, useParams } from 'react-router-dom' import { useSelector } from 'react-redux' -import StatsCard from '../../common/StatsCard/StatsCard' -import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' +import { Loader, PopUpDialog, TextTooltipTemplate, Tooltip } from 'igz-controls/components' +import ClockIcon from 'igz-controls/images/clock.svg?react' +import StatsCard from '../../common/StatsCard/StatsCard' import { generateMonitoringStats } from '../../utils/generateMonitoringData' import { JOBS_MONITORING_WORKFLOWS_TAB } from '../../constants' -import ClockIcon from 'igz-controls/images/clock.svg?react' - import './projectsMonitoringCounters.scss' const WorkflowsCounters = () => { + const anchorRef = useRef(null) + const detailsRef = useRef(null) + const [showPopup, setShowPopup] = useState(false) + const { projectName } = useParams() const navigate = useNavigate() const projectStore = useSelector(store => store.projectStore) + const timeLabel = projectName ? '24 hrs' : 'Past 24 hrs' + + const handleOpenPopUp = () => { + const isHidden = !detailsRef.current?.offsetParent + setShowPopup(isHidden) + } + + const handleClosePopUp = () => { + setShowPopup(false) + } + + const workflowsData = useMemo(() => { + if (projectName) { + const completed = projectStore?.projectSummary.data?.pipelines_completed_recent_count || 0 + const failed = projectStore?.projectSummary.data?.pipelines_failed_recent_count || 0 + const running = projectStore?.projectSummary.data?.pipelines_running_count || 0 + + return { + completed, + failed, + running, + total: completed + failed + running + } + } + + return ( + projectStore.jobsMonitoringData.workflows || { + completed: 0, + failed: 0, + running: 0, + total: 0 + } + ) + }, [ + projectName, + projectStore.projectSummary.data?.pipelines_completed_recent_count, + projectStore.projectSummary.data?.pipelines_failed_recent_count, + projectStore.projectSummary.data?.pipelines_running_count, + projectStore.jobsMonitoringData.workflows + ]) const workflowsStats = useMemo( - () => - generateMonitoringStats( - projectStore.jobsMonitoringData.workflows, - navigate, - JOBS_MONITORING_WORKFLOWS_TAB - ), - [navigate, projectStore.jobsMonitoringData.workflows] + () => generateMonitoringStats(workflowsData, navigate, JOBS_MONITORING_WORKFLOWS_TAB), + [navigate, workflowsData] ) return ( - - - -
      +
      + +
      + +
      + + {timeLabel} +
      +
      +
      - Total
      - {projectStore.projectsSummary.loading ? ( + {projectStore?.projectsSummary?.loading ? ( ) : ( - workflowsStats.total.counter + workflowsStats?.total?.counter?.toLocaleString() )}
      -
      - -
      - Past 24 hours -
      - - - {/* Todo: Use in the future - */} - - - {/* -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - - {scheduledStats.jobs.counter} - + + +
      + {workflowsStats.counters.map( + ({ counter, className, label, link, statusClass, tooltip }) => { + return ( + +
      +
      + }> +
      {label}
      + +
      +
      +
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + counter?.toLocaleString() + )} +
      +
      +
      + ) + } )}
      - */} - {workflowsStats.counters.map(({ counter, label, link, statusClass, tooltip }) => ( - -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - counter - )} -
      -
      - }> -
      {label}
      - -
      + {showPopup && ( + +
      + {workflowsStats?.counters?.map(({ link, counter, label, statusClass }) => ( +
      + {' '} + + {label}: {counter} + +
      + ))}
      -
      - - ))} - - + + )} +
      + +
      ) } diff --git a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss index 9a83d753f6..99fe861399 100644 --- a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss +++ b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss @@ -6,19 +6,32 @@ text-decoration: underline; cursor: pointer; text-underline-offset: 1px; - text-decoration-thickness: 2px; + text-decoration-thickness: 1px; +} + +.card__small-container { + display: flex; + flex-direction: column; + gap: 15px; + justify-content: space-between; + + @media (max-width: 1250px) { + display: contents; + flex-direction: row; + } } .monitoring-stats { + flex: 1; flex-direction: column; flex-wrap: unset; justify-content: flex-start; + min-width: 0; + height: 100%; border: 1px solid colors.$frenchLilac; &.alerts-card { - transition: - background-color 0s, - border-color 0s; + transition: background-color 0s, border-color 0s; } &.alerts-card_not-empty { @@ -32,57 +45,80 @@ margin: 0; color: colors.$topaz; font-weight: normal; - font-size: 0.75rem; + font-size: 14px; } &-card__row { flex: unset; - - &:last-child { - padding: 10px 0; + margin-bottom: 0; + font-weight: 400; + font-size: 14px; + + & > * { + position: relative; + display: flex; + justify-content: space-between; + width: 100%; + padding-bottom: 0.5rem; + color: colors.$primary; } } - &-card__col:not(:last-child) { - padding-right: 0.75em; + &-large { + min-height: 34px; } - &__counter { - color: colors.$primary; - font-weight: 400; - font-size: 28px; + &__counter_header { + font-weight: 600; + font-size: 26px; + } - &-large { - min-height: 34px; - } + &__details { + margin-top: 0.5em; - &:hover { - @include counterLinkHover; + & > * { + margin-bottom: 0.5em; } - } - &__status { - i[class^='state-'] { - margin-left: 5px; + @media (max-width: 1250px) { + display: none; } } &__link { - cursor: pointer; - &:hover { - .stats__counter { + * { @include counterLinkHover; } } } + + &__line { + &::after { + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 1px; + background-color: colors.$mulledWineThree; + content: ''; + } + } + + &__status { + i[class^='state-'] { + margin-left: 5px; + } + } } .project-card__info { display: flex; + flex-shrink: 0; align-items: center; justify-content: flex-end; - margin-left: 1rem; + width: 80px; + margin-left: 0.5em; color: colors.$topaz; font-size: 0.75rem; @@ -90,11 +126,6 @@ margin-right: 5px; } - .stats__link { - display: flex; - align-items: center; - } - &-icon { flex: 0 1 12px; @@ -103,40 +134,88 @@ } } + @media (max-width: 1250px) { + display: none; + } + .stats__subtitle { - margin: 0 5px 0 0; font-size: inherit; } + } - .stats__counter { - position: relative; - margin-right: 0.6em; - padding-right: 0.75em; - font-size: 1rem; + .date-picker-container { + margin-left: 15px; - &::after { - position: absolute; - top: 0; - right: 0; - bottom: 0; - display: inline-block; - width: 1px; - margin: 3px 0; - background-color: colors.$mulledWineThree; - content: ''; + .input-wrapper .input.date-picker__input { + padding: 10px; + } + } +} + +.card-popup { + .pop-up-dialog { + z-index: 9999; + width: max-content; + min-width: 100%; + max-width: 600px; + margin-top: -10px; + padding: 0; + background: colors.$primary; + } + + &_text { + display: flex; + flex-direction: column; + align-items: stretch; + padding: 10px; + overflow-x: auto; + color: colors.$white; + font-size: 12px; + line-height: 20px; + white-space: nowrap; + + &_link { + &:hover { + @include counterLinkHover; + + color: white; } } + } +} - .project-card__info-icon { - position: relative; +main.unpinned { + .card__small-container { + @media (max-width: 1250px) { + display: flex; + flex-direction: column; + } + + @media (max-width: 1100px) { + display: contents; + flex-direction: row; } } - .date-picker-container { - margin-left: 15px; + .monitoring-stats { + .stats__details { + @media (max-width: 1250px) { + display: block; + } - .input-wrapper .input.date-picker__input { - padding: 10px; + @media (max-width: 1100px) { + display: none; + } + } + + .project-card__info { + @media (max-width: 1250px) { + display: flex; + } + + @media (max-width: 1100px) { + display: none; + } } } } diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index ff22e8cd73..78313a78a2 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -18,25 +18,40 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import { + APPLICATION, + ARTIFACTS_PAGE, DATES_FILTER, + ERROR_STATE, + FAILED_STATE, FILTER_ALL_ITEMS, JOBS_MONITORING_JOBS_TAB, JOBS_MONITORING_PAGE, JOBS_MONITORING_WORKFLOWS_TAB, JOB_KIND_JOB, JOB_KIND_WORKFLOW, + MODELS_PAGE, STATUS_FILTER, - TYPE_FILTER, - ERROR_STATE, - FAILED_STATE + TYPE_FILTER } from '../constants' import { ANY_TIME_DATE_OPTION } from './datePicker.util' +import classNames from 'classnames' const IN_PROCESS = 'In Process' +const RUNNING = 'Running' const FAILED = 'Failed' const SUCCEEDED = 'Succeeded' -export const generateMonitoringStats = (data, navigate, tab) => { +export const generateMonitoringStats = (data, navigate, tab, projectName) => { + const linkClassNameDetails = (projectName, noLine) => + classNames(!noLine && 'stats__line', projectName && 'stats__link') + + const linkClassNameHeader = projectName => + classNames('stats__counter_header', projectName && 'stats__link') + + const navigateToTab = (projectName, tab) => { + projectName && navigate(`/projects/${projectName}/${tab}`) + } + const navigateToJobsMonitoringPage = (filters = {}) => { navigate(`/projects/*/${JOBS_MONITORING_PAGE}/${tab}?${new URLSearchParams(filters)}`) } @@ -50,6 +65,7 @@ export const generateMonitoringStats = (data, navigate, tab) => { counters: [ { counter: data.running || 0, + className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['running', 'pending', 'aborting'], @@ -57,10 +73,11 @@ export const generateMonitoringStats = (data, navigate, tab) => { }), statusClass: 'running', tooltip: 'Aborting, Pending, Running', - label: IN_PROCESS + label: RUNNING }, { counter: data.failed || 0, + className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: [ERROR_STATE, 'aborted'] }), statusClass: 'failed', tooltip: 'Aborted, Error', @@ -68,6 +85,7 @@ export const generateMonitoringStats = (data, navigate, tab) => { }, { counter: data.completed || 0, + className: classNames('stats__link'), link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['completed'] }), statusClass: 'completed', tooltip: 'Completed', @@ -89,12 +107,14 @@ export const generateMonitoringStats = (data, navigate, tab) => { [STATUS_FILTER]: ['running'], [DATES_FILTER]: ANY_TIME_DATE_OPTION }), + className: classNames('stats__link', 'stats__line'), statusClass: 'running', tooltip: 'Running', label: IN_PROCESS }, { counter: data.failed || 0, + className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: [ERROR_STATE, FAILED_STATE] }), statusClass: 'failed', @@ -103,6 +123,7 @@ export const generateMonitoringStats = (data, navigate, tab) => { }, { counter: data.completed || 0, + className: classNames('stats__link'), link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['completed'] }), statusClass: 'completed', tooltip: 'Completed', @@ -110,18 +131,66 @@ export const generateMonitoringStats = (data, navigate, tab) => { } ] } - : { - total: { - counter: data.total || 0, - link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: FILTER_ALL_ITEMS }, {}) - }, - jobs: { - counter: data.jobs || 0, - link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: JOB_KIND_JOB }, {}) - }, - workflows: { - counter: data.workflows || 0, - link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: JOB_KIND_WORKFLOW }, {}) + : tab === ARTIFACTS_PAGE + ? { + total: { + counter: data.total || 0 + }, + files: { + counter: data.files || 0, + link: () => navigateToTab(projectName, 'files'), + className: linkClassNameDetails(projectName) + }, + datasets: { + counter: data.datasets || 0, + link: () => navigateToTab(projectName, 'datasets'), + className: linkClassNameDetails(projectName) + }, + documents: { + counter: data.documents || 0, + link: () => navigateToTab(projectName, 'documents'), + className: linkClassNameDetails(projectName) + }, + llm_prompt: { + counter: data.llm_prompts || 0, + link: () => navigateToTab(projectName, 'llm-prompts'), + className: linkClassNameDetails(projectName, true) + }, + list: [ + { key: 'files', label: 'Files' }, + { key: 'datasets', label: 'Datasets' }, + { key: 'documents', label: 'Documents' }, + { key: 'llm_prompt', label: 'LLM Prompts' } + ] } - } + : tab === MODELS_PAGE + ? { + models: { + counter: data || 0, + link: () => navigateToTab(projectName, 'models'), + className: linkClassNameHeader(projectName) + } + } + : tab === APPLICATION + ? { + application: { + counter: data || 0, + link: () => navigateToTab(projectName, 'monitoring-app'), + className: linkClassNameHeader(projectName) + } + } + : { + total: { + counter: data.total || 0, + link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: FILTER_ALL_ITEMS }, {}) + }, + jobs: { + counter: data.jobs || 0, + link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: JOB_KIND_JOB }, {}) + }, + workflows: { + counter: data.workflows || 0, + link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: JOB_KIND_WORKFLOW }, {}) + } + } } From 83661c162d5b48946eedbc23e010ed9e5132a4aa Mon Sep 17 00:00:00 2001 From: adi-gini Date: Wed, 2 Jul 2025 18:35:05 +0300 Subject: [PATCH 043/228] Fix [Project monitoring] Consumer Group button leads to home page (#3316) --- src/elements/ProjectFunctions/ProjectFunctions.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elements/ProjectFunctions/ProjectFunctions.jsx b/src/elements/ProjectFunctions/ProjectFunctions.jsx index 9793e8c82c..9d35c228b0 100644 --- a/src/elements/ProjectFunctions/ProjectFunctions.jsx +++ b/src/elements/ProjectFunctions/ProjectFunctions.jsx @@ -110,7 +110,7 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { label: 'Consumer groups', className: Object.keys(nuclioStore.v3ioStreams.data ?? {}).length > 0 ? 'running' : 'default', - href: `/projects/${params.projectName}/monitor${ + link: `/projects/${params.projectName}/monitor${ !isNuclioModeDisabled ? '/consumer-groups' : '' }` } From e8590d1f82c189bc6e94988033275191b0c129a9 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Wed, 2 Jul 2025 18:35:29 +0300 Subject: [PATCH 044/228] =?UTF-8?q?Impl=20[Project=20Monitoring]=20Update?= =?UTF-8?q?=20=E2=80=9CQuick=20Actions=E2=80=9D=20and=20header=20UI=20(#33?= =?UTF-8?q?18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProjectDetailsHeader.jsx | 63 +++------------ .../ProjectDetailsHeader.scss | 18 ++--- src/common/Select/Select.jsx | 12 ++- src/common/Select/select.scss | 13 ++- src/components/Project/ProjectMonitor.jsx | 7 +- src/components/Project/ProjectMonitorView.jsx | 5 +- src/components/Project/project.utils.jsx | 79 +++++++++++-------- 7 files changed, 96 insertions(+), 101 deletions(-) diff --git a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx index 7fd1d32941..e3a611bae3 100644 --- a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx +++ b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx @@ -20,74 +20,35 @@ such restriction. import React from 'react' import PropTypes from 'prop-types' import { useSelector } from 'react-redux' -import { Link, useLocation } from 'react-router-dom' import { getDateAndTimeByFormat } from 'igz-controls/utils/datetime.util' -import { PROJECT_MONITOR, PROJECT_QUICK_ACTIONS_PAGE } from '../../constants' import './ProjectDetailsHeader.scss' const ProjectDetailsHeader = ({ projectData, projectName }) => { - const location = useLocation() const frontendSpec = useSelector(store => store.appStore.frontendSpec) return (
      -
      -
      -
      - {projectName} -
      - -

      - {projectData && projectData.spec.description} -

      +
      {projectName}
      + {projectData && ( +
      + + Created: + {getDateAndTimeByFormat(projectData.metadata.created, ' MM/DD/YYYY, HH:mm:ss A')} + + {projectData.spec.owner && !frontendSpec.ce?.version && ( + Owner: {projectData.spec.owner} + )}
      - {projectData && ( -
        -
      • - Created: - - {getDateAndTimeByFormat(projectData.metadata.created, 'MM/DD/YYYY, HH:mm:ss A')} - -
      • - {!frontendSpec.ce?.version && ( -
      • - Owner: - {projectData.spec.owner} -
      • - )} -
      • - Status: -
        - {projectData.status.state} - -
        -
      • -
      • - {location.pathname.includes(PROJECT_MONITOR) ? ( - - Project quick actions - - ) : ( - - Project monitoring - - )} -
      • -
      - )} -
      + )}
      ) } ProjectDetailsHeader.propTypes = { projectData: PropTypes.object, - projectName: PropTypes.string.isRequired, + projectName: PropTypes.string.isRequired } export default ProjectDetailsHeader diff --git a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.scss b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.scss index aecdb2dbb3..f1a8ef5c66 100644 --- a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.scss +++ b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.scss @@ -36,21 +36,19 @@ &__details { display: flex; flex-flow: column nowrap; - list-style-type: none; margin: 1rem 0; padding: 0; line-height: 1.5; - - li { - display: flex; - align-items: center; - margin-bottom: 0.2rem; - } + list-style-type: none; &-label { - margin-right: 10px; - font-weight: 700; - min-width: 60px; + font-size: 14px; + + &:not(:last-child)::after { + margin: 8px; + border-right: borders.$dividerBorder; + content: ""; + } } i[class^='state-'] { diff --git a/src/common/Select/Select.jsx b/src/common/Select/Select.jsx index c102f4c8d2..6a0b9f1840 100644 --- a/src/common/Select/Select.jsx +++ b/src/common/Select/Select.jsx @@ -42,10 +42,13 @@ const Select = ({ labelAtTop = false, onClick = null, options, + popUpClassName = 'select__body', + position = 'bottom-right', search = false, selectType = '', selectedId = '', selectedItemAction = null, + width = '', withoutBorder = false, withSelectedIcon = false }) => { @@ -199,11 +202,11 @@ const Select = ({ headerIsHidden customPosition={{ element: selectRef, - position: 'bottom-right' + position: position }} - style={{ width: `${dropdownWidth}px` }} + style={{ width: `${width || dropdownWidth}px` }} > -
      +
      {search && (
      { navigate, params, openRegisterArtifactModal, - openRegisterModelModal, - setCreateFeatureSetPanelIsOpen, - setIsNewFunctionPopUpOpen, - isDemoMode + generateNuclioLink, + openPopUp ) return { diff --git a/src/components/Project/ProjectMonitorView.jsx b/src/components/Project/ProjectMonitorView.jsx index 83e4c7f901..1e818ed406 100644 --- a/src/components/Project/ProjectMonitorView.jsx +++ b/src/components/Project/ProjectMonitorView.jsx @@ -109,7 +109,10 @@ const ProjectMonitorView = ({ className="main-info__toolbar-menu create-new-menu" density="dense" hideSelectedOption - label="Create new" + position="bottom-left" + width="auto" + popUpClassName="" + label="Quick actions" options={createNewOptions} /> [ { - label: 'Batch run', - id: 'batchRun', + label: 'Register dataset', + id: 'registerDataset', + icon: , handler: () => { - openPopUp(JobWizard, { - params - }) + openRegisterArtifactModal(DATASET_TYPE) } }, - { - label: 'ML function', - id: 'mlFunction', - handler: () => { - setIsNewFunctionPopUpOpen(true) - }, - hidden: !isDemoMode - }, - { - label: 'Feature set', - id: 'featureSet', - handler: () => setCreateFeatureSetsPanelIsOpen(true) - }, { label: 'Register artifact', id: 'registerFile', + icon: , handler: () => { openRegisterArtifactModal(ARTIFACT_TYPE) } }, { - label: 'Register model', - id: 'registerModel', + label: 'Batch run', + id: 'batchRun', + icon: , + handler: () => { + openPopUp(JobWizard, { + params + }) + } + }, + { + label: 'Train Model', + id: 'trainModel', + icon: , handler: () => { - openRegisterModelModal() - }, - hidden: !isDemoMode + openPopUp(JobWizard, { + params, + isTrain: true, + wizardTitle: 'Train model', + isOverview: true + }) + } }, { - label: 'Register dataset', - id: 'registerDataset', + label: 'Batch Inference', + id: 'batchInference', + icon: , handler: () => { - openRegisterArtifactModal(DATASET_TYPE) + openPopUp(JobWizard, { + params, + isBatchInference: true, + wizardTitle: 'Batch inference' + }) } + }, + { + label: 'Create real-time function', + id: 'createRealTimeFunction', + icon: , + handler: () => + window.open(generateNuclioLink(`/projects/${params.projectName}/create-function`), '_blank') } ] From 9fdfdb696ede9584cf3c5766876628882718eeb4 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Fri, 4 Jul 2025 03:39:54 +0300 Subject: [PATCH 045/228] Impl [Jobs] Show logs for each attempt (#3319) --- src/api/jobs-api.js | 17 +++-- .../Details/DetailsHeader/DetailsHeader.jsx | 63 +++++++++++++------ src/components/Details/details.util.js | 8 +-- src/components/DetailsLogs/DetailsLogs.jsx | 62 +++++++++++++++--- src/components/Jobs/jobs.util.js | 4 +- src/elements/JobsTable/JobsTable.jsx | 4 +- src/reducers/detailsReducer.js | 10 +++ src/reducers/jobReducer.js | 12 ++-- src/utils/createJobsContent.js | 4 +- src/utils/getJobLogs.util.js | 9 ++- src/utils/parseJob.js | 6 +- 11 files changed, 148 insertions(+), 51 deletions(-) diff --git a/src/api/jobs-api.js b/src/api/jobs-api.js index da3d482806..34da1baddc 100644 --- a/src/api/jobs-api.js +++ b/src/api/jobs-api.js @@ -68,10 +68,19 @@ const jobsApi = { return mainHttpClient.get(`/projects/${project}/runs/${jobId}`, { params }) }, - getJobLogs: (id, project) => - fetch(`${mainBaseUrl}/projects/${project}/logs/${id}`, { - method: 'get' - }), + getJobLogs: (id, project, attempt, signal) => { + let params = '' + + // if attempt === 0 or empty BE return logs for the last attempt + if (attempt > 0) { + params = `?attempt=${attempt}` + } + + return fetch(`${mainBaseUrl}/projects/${project}/logs/${id}${params}`, { + method: 'get', + signal + }) + }, getScheduledJobs: (project, newConfig) => { return mainHttpClient.get(`/projects/${project}/schedules`, newConfig) }, diff --git a/src/components/Details/DetailsHeader/DetailsHeader.jsx b/src/components/Details/DetailsHeader/DetailsHeader.jsx index 88622d930a..c0d452b33e 100644 --- a/src/components/Details/DetailsHeader/DetailsHeader.jsx +++ b/src/components/Details/DetailsHeader/DetailsHeader.jsx @@ -27,11 +27,11 @@ import Select from '../../../common/Select/Select' import { Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' import { ACTIONS_MENU } from 'igz-controls/types' -import { DETAILS_ARTIFACTS_TAB, JOBS_PAGE } from '../../../constants' +import { DETAILS_ARTIFACTS_TAB, DETAILS_LOGS_TAB, JOBS_PAGE } from '../../../constants' import { formatDatetime } from 'igz-controls/utils/datetime.util' import { generateUrlFromRouterPath } from 'igz-controls/utils/common.util' import { getDefaultCloseDetailsLink } from '../../../utils/link-helper.util' -import { setIteration } from '../../../reducers/detailsReducer' +import { setIteration, setRunAttempt } from '../../../reducers/detailsReducer' import { useDetailsHeader } from 'igz-controls/hooks/useDetailsHeader.hook' import Back from 'igz-controls/images/back-arrow.svg?react' @@ -220,24 +220,47 @@ const DetailsHeader = ({ ]) const renderCustomElements = useCallback(() => { - return ( - params.tab === DETAILS_ARTIFACTS_TAB && - detailsStore.iteration && - detailsStore.iterationOptions && - !isDetailsPopUp && ( - { + dispatch(setIteration(option)) + }} + options={detailsStore.iterationOptions} + selectedId={detailsStore.iteration} + /> + ) + ) + } + case DETAILS_LOGS_TAB: { + return ( + detailsStore.runAttempt && + !isEmpty(detailsStore.runAttemptOptions) && + !isDetailsPopUp && ( +
      - + + {parsedUri?.key && (parsedUri?.uid || parsedUri.tree) && ( +
      +
      handleOpenArtifactPopUp()}> + } textShow> + {parsedUri.key} + +
      +
      + )} + {parsedUri?.key && !parsedUri?.uid && !parsedUri.tree && ( + }>{parsedUri.key} + )} +
      { +export const generateOperatingFunctionsTable = (functions, projectName) => { const tableHeaders = [ { value: 'Name', @@ -51,23 +51,23 @@ export const generateOperatingFunctionsTable = functions => { return { name: { value: capitalize(func.name), - link: generateNuclioLink(`/projects/${func.nuclio_function_uri}`), + link: generateNuclioLink(`/projects/${projectName}/functions/${func.name}`), className: 'table-cell_big' }, status: { value: func.status, className: classnames('table-cell_small', 'status', `state-${func.status}`) }, - startedAt: { - value: formatDatetime(func.started_at, 'N/A'), + updatedTime: { + value: formatDatetime(func.updated_time, 'N/A'), className: 'table-cell_medium' }, lag: { - value: func.stats.lag, + value: func.stats.stream_stats.lag, className: 'table-cell_small' }, commitedOffset: { - value: func.stats.committed_offset, + value: func.stats.stream_stats.committed, className: 'table-cell_small' } } diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index 064a70063b..a8e01e5b22 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -17,17 +17,17 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useCallback, useMemo } from 'react' +import React, { useCallback, useEffect, useMemo } from 'react' import { Outlet, useNavigate, useParams, useSearchParams } from 'react-router-dom' -import { useDispatch, useSelector } from 'react-redux' +import { useDispatch } from 'react-redux' import ActionBar from '../ActionBar/ActionBar' import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' import MonitoringApplicationCounters from './MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCounters' import TableTop from '../../elements/TableTop/TableTop' -import { Loader } from 'igz-controls/components' import { + fetchMEPWithDetections, fetchMonitoringApplication, fetchMonitoringApplications, fetchMonitoringApplicationsSummary @@ -47,7 +47,6 @@ const MonitoringApplicationsPage = () => { const dispatch = useDispatch() const params = useParams() const navigate = useNavigate() - const monitoringApplicationsStore = useSelector(store => store.monitoringApplicationsStore) const filtersConfig = useMemo(() => getFiltersConfig(), []) const filters = useFiltersFromSearchParams(filtersConfig) const [, setSearchParams] = useSearchParams() @@ -64,6 +63,21 @@ const MonitoringApplicationsPage = () => { .catch(error => { showErrorNotification(dispatch, error, '', 'Failed to fetch monitoring applications') }) + dispatch( + fetchMEPWithDetections({ + project: params.projectName, + filters: filters + }) + ) + .unwrap() + .catch(error => { + showErrorNotification( + dispatch, + error, + '', + 'Failed to fetch Model Endpoints with suspected/detected issue' + ) + }) }, [dispatch, params.projectName] ) @@ -83,6 +97,7 @@ const MonitoringApplicationsPage = () => { .catch(error => { showErrorNotification(dispatch, error, '', 'Failed to fetch artifacts') }) + dispatch( fetchMonitoringApplication({ project: params.projectName, @@ -93,19 +108,22 @@ const MonitoringApplicationsPage = () => { .unwrap() .catch(error => { showErrorNotification(dispatch, error, '', 'Failed to fetch monitoring application') + navigate( + `/projects/${params.projectName}/${MONITORING_APP_PAGE}${window.location.search}`, + { replace: true } + ) }) }, - [dispatch, params.name, params.projectName] + [dispatch, navigate, params.name, params.projectName] ) - // TODO: uncomment in ML-10005 - // useEffect(() => { - // if (params.name) { - // refreshMonitoringApplication(filters) - // } else { - // refreshMonitoringApplications(filters) - // } - // }, [params.name, refreshMonitoringApplications, refreshMonitoringApplication, filters]) + useEffect(() => { + if (params.name) { + refreshMonitoringApplication(filters) + } else { + refreshMonitoringApplications(filters) + } + }, [params.name, refreshMonitoringApplications, refreshMonitoringApplication, filters]) return (
      @@ -147,7 +165,6 @@ const MonitoringApplicationsPage = () => { withoutExpandButton /> - {monitoringApplicationsStore.loading && }
      diff --git a/src/elements/SectionTable/SectionTable.jsx b/src/elements/SectionTable/SectionTable.jsx index c3205a7d76..bedafd369a 100644 --- a/src/elements/SectionTable/SectionTable.jsx +++ b/src/elements/SectionTable/SectionTable.jsx @@ -23,29 +23,34 @@ import classnames from 'classnames' import { Link } from 'react-router-dom' import { TableTypeCell } from 'igz-controls/elements' -import { TextTooltipTemplate, Tooltip, Tip } from 'igz-controls/components' +import { TextTooltipTemplate, Tooltip, Tip, Loader } from 'igz-controls/components' import ReadOnlyChips from '../ReadOnlyChips/ReadOnlyChips' import './SectionTable.scss' -const SectionTable = ({ params, table }) => { - return ( +const SectionTable = ({ loading = false, params, table }) => { + return loading ? ( + + ) : ( <>
      <> - {table.header.map(header => ( - - ))} + {table.header.map( + header => + !header.hidden && ( + + ) + )} @@ -68,76 +73,87 @@ const SectionTable = ({ params, table }) => { `status_${body?.[key]?.value?.toLowerCase?.()} capitalize` ) - return key === 'type' ? ( - - ) : ( - + {body[key].status && ( + } + > + + + )} + + )} + + )) ) })} @@ -151,6 +167,7 @@ const SectionTable = ({ params, table }) => { } SectionTable.propTypes = { + loading: PropTypes.bool, params: PropTypes.object.isRequired, table: PropTypes.object.isRequired } diff --git a/src/reducers/monitoringApplicationsReducer.js b/src/reducers/monitoringApplicationsReducer.js index 69924fc35c..ec6f42299b 100644 --- a/src/reducers/monitoringApplicationsReducer.js +++ b/src/reducers/monitoringApplicationsReducer.js @@ -24,248 +24,55 @@ import { splitApplicationsContent } from '../utils/applications.utils' import monitoringApplicationsApi from '../api/monitoringApplications-api' import { DATES_FILTER } from '../constants' -// TODO: delete initialState data in ML-10005 const initialState = { applicationsSummary: { - running_model_monitoring_functions: 16, - failed_model_monitoring_functions: 8, - real_time_model_endpoint_count: 75, - batch_model_endpoint_count: 44, loading: false, error: null }, - monitoringApplication: { - name: 'monitorAppV1', - application_class: 'MyAppV1', - started_at: '2025-05-01T12:00:00Z', - updated_time: '2025-05-07T10:00:00Z', - base_period: 10, - nuclio_function_uri: 'my-project/functions/my-project-monitorAppV1/', - stats: { - detections: 1245, - potential_detections: 98, - lag: 2, - committed_offset: 110, - shards: { - 1: { - committed: 50, - lag: 2 - }, - 2: { - committed: 60, - lag: 0 - } - }, - processed_model_endpoints: 8, - metrics: [ - { - type: 'result', - time: '2025-05-07T09:07:14+00:00', - name: 'some_result', - kind: 'data-drift', - status: '2', - value: 0.95 - }, - { - type: 'metric', - time: '2025-05-07T09:07:14+00:00', - name: 'some_metric', - value: 0.4 - } - ] - }, - status: 'ready' + endpointsWithDetections: { + data: [], + loading: false, + error: null }, + monitoringApplication: {}, monitoringApplications: { - applications: [ - { - name: 'monitorAppV1', - application_class: 'MyAppV1', - started_at: '2025-05-01T12:00:00Z', - updated_time: '2025-05-07T10:00:00Z', - base_period: 10, - nuclio_function_uri: 'my-project/functions/my-project-monitorAppV1/', - stats: { - detections: 1245, - potential_detections: 98, - lag: 2, - committed_offset: 110, - shards: { - 1: { - committed: 50, - lag: 2 - }, - 2: { - committed: 60, - lag: 0 - } - }, - processed_model_endpoints: 8, - metrics: [ - { - type: 'result', - time: '2025-05-07T09:07:14+00:00', - name: 'some_result', - kind: 'data-drift', - status: 'Detection', - value: 0.95 - }, - { - type: 'metric', - time: '2025-05-07T09:07:14+00:00', - name: 'some_metric', - value: 0.4 - } - ] - }, - status: 'ready' - }, - { - name: 'monitorAppV2', - application_class: 'MyAppV2', - started_at: '2025-05-01T08:00:00Z', - updated_time: '2025-05-06T20:00:00Z', - base_period: 10, - nuclio_function_uri: 'default/functions/default-monitorAppV2/', - stats: { - detections: 567, - potential_detections: 34, - lag: 0, - committed_offset: 10598, - shards: { - 1: { - committed: 50, - lag: 2 - }, - 2: { - committed: 60, - lag: 0 - } - }, - processed_model_endpoints: 8, - metrics: [ - { - type: 'result', - time: '2025-05-07T09:07:14+00:00', - name: 'some_result', - kind: 0, - status: 2, - value: 0.95 - }, - { - type: 'metric', - time: '2025-05-07T09:07:14+00:00', - name: 'some_metric', - value: 0.4 - } - ] - }, - status: 'ready' - }, - { - name: 'monitorAppV3', - application_class: 'MyAppV3', - started_at: '2025-05-02T09:00:00Z', - updated_time: '2025-05-08T11:00:00Z', - base_period: 15, - nuclio_function_uri: 'default/functions/default-monitorAppV3/', - stats: { - detections: 850, - potential_detections: 60, - lag: 5, - committed_offset: 203498, - shards: { - 1: { - committed: 50, - lag: 2 - }, - 2: { - committed: 60, - lag: 0 - } - }, - processed_model_endpoints: 8, - metrics: [ - { - type: 'result', - time: '2025-05-07T09:07:14+00:00', - name: 'some_result', - kind: 0, - status: 2, - value: 0.95 - }, - { - type: 'metric', - time: '2025-05-07T09:07:14+00:00', - name: 'some_metric', - value: 0.4 - } - ] - }, - status: 'ready' - } - ], - operatingFunctions: [ - { - name: 'model-monitoring-controller', - application_class: 'modelMonitoringController', - started_at: '2025-05-01T12:00:00Z', - updated_time: '2025-05-07T10:00:00Z', - base_period: 10, - nuclio_function_uri: 'default/functions/default-modelMonitoringController/', - stats: { - detections: 1245, - potential_detections: 98, - lag: 12, - committed_offset: 398742 - }, - status: 'ready' - }, - { - name: 'model-monitoring-stream', - application_class: 'modelMonitoringStream', - started_at: '2025-05-01T08:00:00Z', - updated_time: '2025-05-06T20:00:00Z', - base_period: 10, - nuclio_function_uri: 'default/functions/default-modelMonitoringStream/', - stats: { - detections: 567, - potential_detections: 34, - lag: 0, - committed_offset: 10598 - }, - status: 'ready' - }, - { - name: 'model-monitoring-writer', - application_class: 'modelMonitoringWriter', - started_at: '2025-05-01T08:00:00Z', - updated_time: '2025-05-06T20:00:00Z', - base_period: 10, - nuclio_function_uri: 'default/functions/default-modelMonitoringWriter/', - stats: { - detections: 2567, - potential_detections: 134, - lag: 10, - committed_offset: 110598 - }, - status: 'ready' - } - ] + applications: [], + operatingFunctions: [] }, loading: false, error: null } +export const fetchMEPWithDetections = createAsyncThunk( + 'fetchMEPWithDetections', + ({ project, filters }) => { + const params = { + start: filters[DATES_FILTER].value[0].getTime() + } + + if (filters[DATES_FILTER].value[1]) { + params.end = filters[DATES_FILTER].value[1].getTime() + } + + return monitoringApplicationsApi.getMEPWithDetections(project, params).then(response => { + return response.data.values.map(([date, suspected, detected]) => [date, suspected + detected]) + }) + } +) + export const fetchMonitoringApplication = createAsyncThunk( 'fetchMonitoringApplication', ({ project, functionName, filters }) => { - const params = { - start: filters[DATES_FILTER].value[0].getTime() + let params = {} + + if (filters[DATES_FILTER]) { + params = { + start: filters[DATES_FILTER].value[0].getTime() + } } return monitoringApplicationsApi - .getMonitoringApplication(project, functionName, params) + .getMonitoringApplication(project, functionName.toLowerCase(), params) .then(response => response.data) } ) @@ -300,6 +107,9 @@ const monitoringApplicationsSlice = createSlice({ name: 'monitoringApplicationsStore', initialState, reducers: { + removeMEPWithDetections(state) { + state.endpointsWithDetections = initialState.endpointsWithDetections + }, removeMonitoringApplication(state) { state.monitoringApplication = initialState.monitoringApplication }, @@ -308,16 +118,30 @@ const monitoringApplicationsSlice = createSlice({ } }, extraReducers: builder => { + builder.addCase(fetchMEPWithDetections.pending, state => { + state.endpointsWithDetections.loading = true + }) + builder.addCase(fetchMEPWithDetections.fulfilled, (state, { payload }) => { + state.endpointsWithDetections.data = payload + state.endpointsWithDetections.loading = false + state.endpointsWithDetections.error = null + }) + builder.addCase(fetchMEPWithDetections.rejected, (state, action) => { + state.endpointsWithDetections.loading = false + state.endpointsWithDetections.error = action.error + }) builder.addCase(fetchMonitoringApplication.pending, defaultPendingHandler) builder.addCase(fetchMonitoringApplication.fulfilled, (state, { payload }) => { state.monitoringApplication = payload state.loading = false + state.error = null }) builder.addCase(fetchMonitoringApplication.rejected, defaultRejectedHandler) builder.addCase(fetchMonitoringApplications.pending, defaultPendingHandler) builder.addCase(fetchMonitoringApplications.fulfilled, (state, { payload }) => { state.monitoringApplications = payload state.loading = false + state.error = null }) builder.addCase(fetchMonitoringApplications.rejected, defaultRejectedHandler) builder.addCase(fetchMonitoringApplicationsSummary.pending, state => { @@ -326,6 +150,7 @@ const monitoringApplicationsSlice = createSlice({ builder.addCase(fetchMonitoringApplicationsSummary.fulfilled, (state, { payload }) => { state.applicationsSummary = payload state.applicationsSummary.loading = false + state.applicationsSummary.error = null }) builder.addCase(fetchMonitoringApplicationsSummary.rejected, (state, action) => { state.applicationsSummary.loading = false @@ -334,7 +159,10 @@ const monitoringApplicationsSlice = createSlice({ } }) -export const { removeMonitoringApplication, removeMonitoringApplications } = - monitoringApplicationsSlice.actions +export const { + removeMEPWithDetections, + removeMonitoringApplication, + removeMonitoringApplications +} = monitoringApplicationsSlice.actions export default monitoringApplicationsSlice.reducer diff --git a/src/utils/createApplicationContent.jsx b/src/utils/createApplicationContent.jsx index 177c3d2181..3f255bad6b 100644 --- a/src/utils/createApplicationContent.jsx +++ b/src/utils/createApplicationContent.jsx @@ -22,9 +22,8 @@ import { capitalize } from 'lodash' import { formatDatetime } from 'igz-controls/utils/datetime.util' import { generateNuclioLink } from './parseUri' -export const createApplicationContent = application => { +export const createApplicationContent = (application, projectName) => { const identifierUnique = 'identifierUnique.' + application.name + application.application_class - const nuclioFunctionName = application.nuclio_function_uri.split('/')[2] return { data: { @@ -49,7 +48,7 @@ export const createApplicationContent = application => { headerId: 'lag', headerLabel: 'Lag', tip: "Number of messages currently waiting in the app's queue", - value: application.stats.lag, + value: application.stats.stream_stats?.lag ?? 0, className: 'table-cell-1' }, { @@ -57,21 +56,21 @@ export const createApplicationContent = application => { headerId: 'commitedOffset', tip: 'Total number of messages handled by the app', headerLabel: 'Commited offset', - value: application.stats.committed_offset, + value: application.stats.stream_stats.committed ?? 0, className: 'table-cell-2' }, { id: `detections.${identifierUnique}`, headerId: 'detections', headerLabel: 'Detections', - value: application.stats.detections, + value: application.stats.detected, className: 'table-cell-1' }, { id: `possibleDetections.${identifierUnique}`, headerId: 'possibleDetections', headerLabel: 'Possible detections', - value: application.stats.potential_detections, + value: application.stats.potential_detection, className: 'table-cell-2' }, { @@ -93,9 +92,9 @@ export const createApplicationContent = application => { id: `nuclioFunction.${identifierUnique}`, headerId: 'nuclioFunction', headerLabel: 'Nuclio function', - value: nuclioFunctionName, + value: application.name, className: 'table-cell-2', - getLink: () => generateNuclioLink(`/projects/${application.nuclio_function_uri}`), + getLink: () => generateNuclioLink(`/projects/${projectName}/functions/${application.name}`), showStatus: true } ] diff --git a/tests/mockServer/data/monitoringApplications.json b/tests/mockServer/data/monitoringApplications.json index 5a4c12422e..eb4eb0d869 100644 --- a/tests/mockServer/data/monitoringApplications.json +++ b/tests/mockServer/data/monitoringApplications.json @@ -8,10 +8,14 @@ "base_period": 10, "nuclio_function_uri": "default/functions/default-modelMonitoringController/", "stats": { - "detections": 1245, - "potential_detections": 98, - "lag": 12, - "committed_offset": 398742 + "detected": 1245, + "potential_detection": 98, + "stream_stats": { + "0": { + "lag": 12, + "committed": 398742 + } + } }, "status": "ready" }, @@ -23,10 +27,14 @@ "base_period": 10, "nuclio_function_uri": "default/functions/default-modelMonitoringStream/", "stats": { - "detections": 567, - "potential_detections": 34, - "lag": 0, - "committed_offset": 10598 + "detected": 567, + "potential_detection": 34, + "stream_stats": { + "0": { + "lag": 12, + "committed": 39874222 + } + } }, "status": "ready" }, @@ -38,10 +46,14 @@ "base_period": 10, "nuclio_function_uri": "default/functions/default-modelMonitoringWriter/", "stats": { - "detections": 2567, - "potential_detections": 134, - "lag": 10, - "committed_offset": 110598 + "detected": 2567, + "potential_detection": 134, + "stream_stats": { + "0": { + "lag": 11, + "committed": 328742 + } + } }, "status": "ready" }, @@ -53,10 +65,14 @@ "base_period": 10, "nuclio_function_uri": "my-project/functions/my-project-monitorAppV1/", "stats": { - "detections": 1245, - "potential_detections": 98, - "lag": 2, - "committed_offset": 110, + "detected": 1245, + "potential_detection": 98, + "stream_stats": { + "0": { + "lag": 1222, + "committed": 22742 + } + }, "shards": { "1": { "committed": 50, @@ -72,7 +88,7 @@ { "type": "result", "time": "2025-05-07T09:07:14+00:00", - "name": "some_result", + "result_name": "some_result", "kind": "data-drift", "status": "Detection", "value": 0.95 @@ -80,7 +96,7 @@ { "type": "metric", "time": "2025-05-07T09:07:14+00:00", - "name": "some_metric", + "metric_name": "some_metric", "value": 0.4 } ] @@ -95,10 +111,14 @@ "base_period": 10, "nuclio_function_uri": "default/functions/default-monitorAppV2/", "stats": { - "detections": 567, - "potential_detections": 34, - "lag": 0, - "committed_offset": 10598, + "detected": 567, + "potential_detection": 34, + "stream_stats": { + "0": { + "lag": 2, + "committed": 742 + } + }, "shards": { "1": { "committed": 50, @@ -114,7 +134,7 @@ { "type": "result", "time": "2025-05-07T09:07:14+00:00", - "name": "some_result", + "result_name": "some_result", "kind": 0, "status": 2, "value": 0.95 @@ -122,7 +142,7 @@ { "type": "metric", "time": "2025-05-07T09:07:14+00:00", - "name": "some_metric", + "metric_name": "some_metric", "value": 0.4 } ] @@ -137,10 +157,14 @@ "base_period": 15, "nuclio_function_uri": "default/functions/default-monitorAppV3/", "stats": { - "detections": 850, - "potential_detections": 60, - "lag": 5, - "committed_offset": 203498, + "detected": 850, + "potential_detection": 60, + "stream_stats": { + "0": { + "lag": 5, + "committed": 42 + } + }, "shards": { "1": { "committed": 50, @@ -156,7 +180,7 @@ { "type": "result", "time": "2025-05-07T09:07:14+00:00", - "name": "some_result", + "result_name": "some_result", "kind": 0, "status": 2, "value": 0.95 @@ -164,7 +188,7 @@ { "type": "metric", "time": "2025-05-07T09:07:14+00:00", - "name": "some_metric", + "metric_name": "some_metric", "value": 0.4 } ] diff --git a/tests/mockServer/data/summary.json b/tests/mockServer/data/summary.json index 39f881e417..2f9212a4f7 100644 --- a/tests/mockServer/data/summary.json +++ b/tests/mockServer/data/summary.json @@ -5,12 +5,16 @@ "endpoint_alerts_count": 4, "job_alerts_count": 2, "other_alerts_count": 6, + "failed_model_monitoring_functions": 2, "files_count": 13000, "feature_sets_count": 0, "models_count": 13000, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 3, "runs_running_count": 3, + "running_model_monitoring_functions": 3, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 1, "distinct_scheduled_pipelines_pending_count": 0, @@ -23,12 +27,16 @@ "endpoint_alerts_count": 4, "job_alerts_count": 2, "other_alerts_count": 6, + "failed_model_monitoring_functions": 6, "files_count": 2, "feature_sets_count": 0, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 3, "runs_running_count": 3, + "running_model_monitoring_functions": 3, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 1, "distinct_scheduled_pipelines_pending_count": 0, @@ -40,10 +48,14 @@ "name": "churn-project-admin", "files_count": 7, "feature_sets_count": 1, + "failed_model_monitoring_functions": 1, "models_count": 5, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, + "running_model_monitoring_functions": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 2, "distinct_scheduled_pipelines_pending_count": 0, @@ -56,12 +68,16 @@ "endpoint_alerts_count": 3, "project.job_alerts_count": 6, "other_alerts_count": 1, + "failed_model_monitoring_functions": 1, "files_count": 2, "feature_sets_count": 23, "models_count": 1, "runs_completed_recent_count": 0, "runs_failed_recent_count": 1, + "batch_model_endpoint_count": 1, + "real_time_model_endpoint_count": 7, "runs_running_count": 7, + "running_model_monitoring_functions": 7, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 2, "distinct_scheduled_pipelines_pending_count": 0, @@ -74,12 +90,16 @@ "endpoint_alerts_count": 1, "job_alerts_count": 8, "other_alerts_count": 2, + "failed_model_monitoring_functions": 2, "files_count": 0, "feature_sets_count": 1, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, + "running_model_monitoring_functions": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -89,12 +109,16 @@ }, { "name": "fsdemo-admin", + "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 4, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, + "running_model_monitoring_functions": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -104,12 +128,16 @@ }, { "name": "getting-started-tutorial-admin", + "failed_model_monitoring_functions": 1, "files_count": 1, "feature_sets_count": 0, "models_count": 2, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 1, "runs_running_count": 1, + "running_model_monitoring_functions": 1, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 1, "distinct_scheduled_pipelines_pending_count": 0, @@ -119,12 +147,16 @@ }, { "name": "hedi-proj", + "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, + "running_model_monitoring_functions": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -134,12 +166,16 @@ }, { "name": "mask-detection", + "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, + "running_model_monitoring_functions": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -149,12 +185,16 @@ }, { "name": "model-deployment-pipeline-admin", + "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, + "running_model_monitoring_functions": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -164,12 +204,16 @@ }, { "name": "moreofthesame", + "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 2, + "real_time_model_endpoint_count": 2, "runs_running_count": 2, + "running_model_monitoring_functions": 2, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -179,12 +223,16 @@ }, { "name": "network-operations", + "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, + "running_model_monitoring_functions": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -194,12 +242,16 @@ }, { "name": "network-operations-admin", + "failed_model_monitoring_functions": 13, "files_count": 13, "feature_sets_count": 0, "models_count": 6, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 3, + "real_time_model_endpoint_count": 3, "runs_running_count": 3, + "running_model_monitoring_functions": 3, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -209,12 +261,16 @@ }, { "name": "sk-project-admin", + "failed_model_monitoring_functions": 4, "files_count": 4, "feature_sets_count": 0, "models_count": 3, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 1, + "real_time_model_endpoint_count": 1, "runs_running_count": 1, + "running_model_monitoring_functions": 1, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 1, "distinct_scheduled_pipelines_pending_count": 0, @@ -224,12 +280,16 @@ }, { "name": "stocks", + "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 2, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, + "running_model_monitoring_functions": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, "distinct_scheduled_pipelines_pending_count": 0, @@ -239,11 +299,14 @@ }, { "name": "stocks-admin", + "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 2, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, @@ -254,11 +317,14 @@ }, { "name": "test-test", + "failed_model_monitoring_functions": 1, "files_count": 1, "feature_sets_count": 0, "models_count": 0, "runs_completed_recent_count": 0, "runs_failed_recent_count": 0, + "batch_model_endpoint_count": 0, + "real_time_model_endpoint_count": 0, "runs_running_count": 0, "distinct_schedules_count": 0, "distinct_scheduled_jobs_pending_count": 0, diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 8f4d752bda..55f1b60a43 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -45,6 +45,7 @@ import { set } from 'lodash' import mime from 'mime-types' +import moment from 'moment' import alerts from './data/alerts.json' import frontendSpec from './data/frontendSpec.json' @@ -854,11 +855,11 @@ function getMonitoringApplicationsSummary(req, res) { function getMonitoringApplicationData(req, res) { const monitoringApplication = (monitoringApplications[req.params['project']] || []).find( application => { - return application.name === req.params['func'] + return application.name.toLowerCase() === req.params['func'] } ) - if (monitoringApplication.length === 0) { + if (!monitoringApplication) { res.statusCode = 404 res.send({ detail: "MLRunNotFoundError('Monitoring application not found')" @@ -868,6 +869,27 @@ function getMonitoringApplicationData(req, res) { } } +function getMonitoringApplicationDrift(req, res) { + const data = [] + const endDate = moment(Number(req.query.end) || new Date()) + + for ( + const startDate = moment(Number(req.query.start)); + startDate < endDate; + startDate.add(1, 'minute') + ) { + data.push([ + startDate.utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]'), + Math.floor(Math.random() * 11), + Math.floor(Math.random() * 11) + ]) + } + + res.send({ + values: data + }) +} + function getRuns(req, res) { let collectedRuns = runs.runs //get runs for Projects Monitoring page @@ -2902,11 +2924,15 @@ app.get( `${mlrunAPIIngress}/projects/:project/model-monitoring/function-summaries`, getMonitoringApplications ) -app.get(`${mlrunAPIIngress}/project-summary/:project`, getMonitoringApplicationsSummary) +app.get(`${mlrunAPIIngress}/project-summaries/:project`, getMonitoringApplicationsSummary) app.get( - `${mlrunAPIIngress}/projects/:project/model-monitoring/function-summary/:func`, + `${mlrunAPIIngress}/projects/:project/model-monitoring/function-summaries/:func`, getMonitoringApplicationData ) +app.get( + `${mlrunAPIIngress}/projects/:project/model-endpoints/drift-over-time`, + getMonitoringApplicationDrift +) app.get(`${mlrunAPIIngress}/projects/:project/runs`, getRuns) app.get(`${mlrunAPIIngress}/projects/*/runs`, getRuns) From 439834e73dc711d87b2983f9733a0db5bc7657e2 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Sun, 20 Jul 2025 10:44:27 +0300 Subject: [PATCH 061/228] Tests [Mock] Add mock for owner component (#3335) --- tests/mockServer/data/iguazioProjects.json | 126 ++++++++++++++++++ tests/mockServer/data/iguazioSelf.json | 2 +- .../mockServer/data/iguazioUserRelations.json | 45 +++++++ tests/mockServer/data/projects.json | 34 ++--- 4 files changed, 189 insertions(+), 18 deletions(-) diff --git a/tests/mockServer/data/iguazioProjects.json b/tests/mockServer/data/iguazioProjects.json index 3014df2207..6d0cab3d9e 100644 --- a/tests/mockServer/data/iguazioProjects.json +++ b/tests/mockServer/data/iguazioProjects.json @@ -1,5 +1,131 @@ { "data": [ + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-4769680238386", + "attributes": { + "name": "auto-generated-data", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-476968023838622", + "attributes": { + "name": "model-deployment-pipeline-admin", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-4769680238386111", + "attributes": { + "name": "moreofthesame", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-867b867b867b867b2", + "attributes": { + "name": "network-operations", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-867b867b867b867b2221", + "attributes": { + "name": "network-operations-admin", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-867ba99a82jdk", + "attributes": { + "name": "sk-project-admin", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-ooos992ksl", + "attributes": { + "name": "stocks", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-2ososolzmn221l", + "attributes": { + "name": "stocks-admin", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-ooos992kslas2", + "attributes": { + "name": "test-test", + "created_at": "2022-03-10T10:24:36.235000+00:00", + "updated_at": "2022-03-14T14:01:13.399000+00:00", + "admin_status": "online", + "operational_status": "online", + "labels": [], + "annotations": [], + "mlrun_project": "{\"kind\": \"project\", \"metadata\": {}, \"spec\": {\"functions\": [{\"name\": \"step3\", \"spec\": {\"kind\": \"job\", \"metadata\": {\"name\": \"step3\", \"tag\": \"\", \"project\": \"proj1\"}, \"spec\": {\"command\": \"\", \"args\": [], \"image\": \"mlrun/mlrun\", \"build\": {\"functionSourceCode\": \"aW1wb3J0IHRpbWUKZGVmIGhhbmRsZXIgKGNvbnRleHQpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygnc3RhcnQnKQogICAgdGltZS5zbGVlcCgxMCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oJ2VuZCcp\", \"commands\": [], \"code_origin\": \"/User/demos/getting-started-tutorial/scale/step1.py\", \"origin_filename\": \"/User/demos/getting-started-tutorial/scale/step1.py\"}, \"entry_points\": {\"handler\": {\"name\": \"handler\", \"doc\": \"\", \"parameters\": [{\"name\": \"context\", \"default\": \"\"}], \"outputs\": [{\"default\": \"\"}], \"lineno\": 2}}, \"description\": \"\", \"default_handler\": \"handler\", \"disable_auto_mount\": false, \"env\": [], \"priority_class_name\": \"igz-workload-medium\", \"affinity\": null}, \"verbose\": false}}], \"workflows\": [{\"name\": \"dummy_workflow\", \"path\": \"/User/demos/getting-started-tutorial/scale/pipelines.py\", \"handler\": \"dummy_workflow\", \"engine\": null}], \"artifacts\": [], \"source\": \"\", \"subpath\": \"\", \"origin_url\": \"\", \"disable_auto_mount\": false}, \"status\": {}}" + } + }, { "type": "project", "id": "090b1327-ceff-45c7-867b-476968022be6", diff --git a/tests/mockServer/data/iguazioSelf.json b/tests/mockServer/data/iguazioSelf.json index ce77daf4b1..e6fad8548f 100644 --- a/tests/mockServer/data/iguazioSelf.json +++ b/tests/mockServer/data/iguazioSelf.json @@ -1,7 +1,7 @@ { "data": { "type": "user", - "id": "20ab4d74-3b45-447c-aef7-47797b7a31d5", + "id": "08debad1-e697-48b1-891c-6c9029aeee03", "attributes": { "username": "admin", "first_name": "Administrator", diff --git a/tests/mockServer/data/iguazioUserRelations.json b/tests/mockServer/data/iguazioUserRelations.json index 063ba48c99..d9f3495172 100644 --- a/tests/mockServer/data/iguazioUserRelations.json +++ b/tests/mockServer/data/iguazioUserRelations.json @@ -1,5 +1,50 @@ { "08debad1-e697-48b1-891c-6c9029aeee03": [ + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-4769680238386", + "relationships": null + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-476968023838622", + "relationships": null + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-4769680238386111", + "relationships": null + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-867b867b867b867b2", + "relationships": null + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-867b867b867b867b2221", + "relationships": null + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-867ba99a82jdk", + "relationships": null + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-ooos992ksl", + "relationships": null + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-2ososolzmn221l", + "relationships": null + }, + { + "type": "project", + "id": "090b1327-ceff-45c7-867b-ooos992kslas2", + "relationships": null + }, { "type": "project", "id": "1e287a06-3dd7-498d-ac0f-f38ce413a7eb", diff --git a/tests/mockServer/data/projects.json b/tests/mockServer/data/projects.json index 4d1941f5a2..fee8e0e84b 100644 --- a/tests/mockServer/data/projects.json +++ b/tests/mockServer/data/projects.json @@ -12,7 +12,7 @@ }, "spec": { "description": "auto generated data for different purposes", - "owner": null, + "owner": "admin", "goals": "test goals", "params": {}, "functions": null, @@ -40,7 +40,7 @@ }, "spec": { "description": "123", - "owner": null, + "owner": "igz_nobody", "goals": "321", "params": { "se": "fg" @@ -193,7 +193,7 @@ }, "spec": { "description": "", - "owner": null, + "owner": "igz_nobody", "goals": "bbbbb", "params": { "a": "a", @@ -360,7 +360,7 @@ }, "spec": { "description": "test summary", - "owner": null, + "owner": "igz_nobody", "goals": "test goals", "params": {}, "functions": null, @@ -388,7 +388,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "igz_nobody", "goals": null, "params": null, "functions": [], @@ -419,7 +419,7 @@ }, "spec": { "description": "", - "owner": null, + "owner": "igz_nobody", "goals": "", "params": {}, "functions": null, @@ -446,7 +446,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "igz_nobody", "goals": null, "params": null, "functions": [ @@ -500,7 +500,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "admin", "goals": null, "params": null, "functions": null, @@ -527,7 +527,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "igz_nobody", "goals": null, "params": null, "functions": [], @@ -555,7 +555,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "admin", "goals": null, "params": null, "functions": [ @@ -1272,7 +1272,7 @@ }, "spec": { "description": "test", - "owner": null, + "owner": "admin", "goals": null, "params": null, "functions": null, @@ -1303,7 +1303,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "admin", "goals": null, "params": null, "functions": null, @@ -1330,7 +1330,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "admin", "goals": null, "params": null, "functions": [ @@ -1425,7 +1425,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "admin", "goals": null, "params": null, "functions": [ @@ -1533,7 +1533,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "admin", "goals": null, "params": null, "functions": [], @@ -1561,7 +1561,7 @@ }, "spec": { "description": null, - "owner": null, + "owner": "admin", "goals": null, "params": { "PROJECT_NAME": "stocks-admin" @@ -1625,7 +1625,7 @@ }, "spec": { "description": "", - "owner": null, + "owner": "admin", "goals": null, "params": null, "functions": null, From ac5093d7cd32df16739abe790349e39560fa0c9c Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Sun, 20 Jul 2025 09:48:52 +0200 Subject: [PATCH 062/228] Tests [QA] v1.10.0-rc8 (#3336) --- package.json | 2 +- tests/features/MLFunction.feature | 11 ++-- tests/features/alertsMonitoring.feature | 31 ++++++--- tests/features/artifacts.feature | 6 +- tests/features/common-tools/common-consts.js | 28 ++++---- .../common/actions/dropdown.action.js | 21 +++++- .../common/page-objects/feature-store.po.js | 2 +- .../common/page-objects/info-pane.po.js | 7 +- .../page-objects/interactive-popup.po.js | 14 +++- .../common/page-objects/monitoring-app.po.js | 1 - .../common/page-objects/projects.po.js | 66 +++++++++++-------- tests/features/datasets.feature | 26 ++++---- tests/features/featureStore.feature | 13 +--- tests/features/jobsAndWorkflows.feature | 4 +- tests/features/jobsMonitoring.feature | 3 +- tests/features/monitoringApp.feature | 6 +- tests/features/projectMonitoring.feature | 21 +++++- tests/features/projectsPage.feature | 37 ++++++++--- tests/features/quickActions.feature | 21 ------ tests/features/step-definitions/steps.js | 16 ++++- .../features/step-definitions/table.steps.js | 8 +++ 21 files changed, 214 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index 631fded06c..a1f7959e7e 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "babel-runtime": "^6.26.0", "body-parser": "^1.19.0", "chai": "^4.3.4", - "chromedriver": "^136.0.0", + "chromedriver": "^138.0.0", "cross-env": "^7.0.3", "css-loader": "^6.5.1", "cucumber-html-reporter": "^5.3.0", diff --git a/tests/features/MLFunction.feature b/tests/features/MLFunction.feature index 0f11d0f3cc..b374c1d777 100644 --- a/tests/features/MLFunction.feature +++ b/tests/features/MLFunction.feature @@ -1369,14 +1369,14 @@ Feature: ML Functions And wait load page When click on cell with row index 2 in "name" column in "Functions_Table" table on "ML_Functions" wizard And wait load page - Then verify redirection from "projects/default/functions/model-monitoring-stream/latest/INVALID" to "projects/default/functions/model-monitoring-stream/latest/overview" + Then verify redirection from "projects/default/functions/model-monitoring-stream/latest/INVALID?dates=anyTime" to "projects/default/functions/model-monitoring-stream/latest/overview?dates=anyTime" Then select "Code" tab in "Info_Pane_Tab_Selector" on "ML_Function_Info_Pane" wizard And wait load page - Then verify redirection from "projects/default/functions/model-monitoring-stream/latest/INVALID" to "projects/default/functions/model-monitoring-stream/latest/overview" + Then verify redirection from "projects/default/functions/model-monitoring-stream/latest/CodeINVALID?dates=anyTime" to "projects/default/functions/model-monitoring-stream/latest/overview?dates=anyTime" Then select "Build Log" tab in "Info_Pane_Tab_Selector" on "ML_Function_Info_Pane" wizard And wait load page - Then verify redirection from "projects/default/functions/model-monitoring-stream/latest/INVALID" to "projects/default/functions/model-monitoring-stream/latest/overview" - Then verify redirection from "projects/default/INVALID/model-monitoring-stream/latest/overview" to "projects" + Then verify redirection from "projects/default/functions/model-monitoring-stream/latest/BuildLogINVALID?dates=anyTime" to "projects/default/functions/model-monitoring-stream/latest/overview?dates=anyTime" + Then verify redirection from "projects/default/INVALID/model-monitoring-stream/latest/overview?dates=anyTime" to "projects" @MLF @smoke @@ -1445,6 +1445,8 @@ Feature: ML Functions Then verify "New_Function_Build_Commands_Text_Area" not input element in "Code_Accordion" on "New_Function" wizard is enabled Then click on "Save_Button" element on "New_Function" wizard And wait load page + When turn on staging mode with query params "true" + And wait load page Then check "demo-function-02" value in "name" column in "Functions_Table" table on "ML_Functions" wizard Then verify "Table_FilterBy_Button" element visibility on "ML_Functions" wizard Then click on "Table_FilterBy_Button" element on "ML_Functions" wizard @@ -1456,6 +1458,7 @@ Feature: ML Functions And wait load page Then check "demo-function-02" value in "name" column in "Functions_Table" table on "ML_Functions" wizard When click on cell with value "demo-function-02" in "name" column in "Functions_Table" table on "ML_Functions" wizard + And wait load page Then check "demo-function-02" value in "name" column in "Overview_Table" table on "ML_Function_Info_Pane" wizard Then "Header" element on "ML_Function_Info_Pane" should contains "demo-function-02" value diff --git a/tests/features/alertsMonitoring.feature b/tests/features/alertsMonitoring.feature index 7ea7488fdc..049ff554bc 100644 --- a/tests/features/alertsMonitoring.feature +++ b/tests/features/alertsMonitoring.feature @@ -342,7 +342,6 @@ Feature: Alerts Monitoring Page @MLAM @smoke - # TODO: Add data to the mock to check the following elements Scenario: MLAM007 - Check components on Endpoints alert detail pane Given open url And wait load page @@ -379,20 +378,34 @@ Feature: Alerts Monitoring Page Then verify "Overview_Trigger_Criteria" on "Alerts_Endpoint_Info_Pane" wizard should contains "Alerts_Jobs_Info_Pane"."Overview_Trigger_Criteria_Headers" Then verify "Notifications_Header" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then verify "Notifications_Item" element visibility on "Alerts_Endpoint_Info_Pane" wizard - Then verify "Date_Picker_Filter_Dropdown" element visibility on "Alerts_Endpoint_Info_Pane" wizard - Then verify "Date_Picker_Filter_Dropdown" dropdown on "Alerts_Endpoint_Info_Pane" wizard selected option value "Past 24 hours" - Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Alerts_Endpoint_Info_Pane" wizard should contains "Dropdown_Options"."Date_Picker_Filter_Options_Endpoint" - Then click on "Header" element on "Alerts_Endpoint_Info_Pane" wizard - And wait load page - # Add data to the mock to check the following elements - # Then verify "Metrics_App_Name" element visibility on "Alerts_Endpoint_Info_Pane" wizard - # Then verify "Metrics_Stats_Card" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then verify "Metrics_Stats_Card_Empty" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then "Metrics_Stats_Card_Empty" element on "Alerts_Endpoint_Info_Pane" should contains "Metrics data not found" value Then click on "Cross_Close_Button" element on "Alerts_Endpoint_Info_Pane" wizard Then verify "Header" element not exists on "Alerts_Endpoint_Info_Pane" wizard When click on cell with row index 1 in "alertName" column in "Alerts_Table" table on "Alerts_Monitoring" wizard And wait load page Then verify "Header" element visibility on "Alerts_Endpoint_Info_Pane" wizard + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Alerts_Monitoring" wizard + And wait load page + When click on cell with value "alert-name-uqbxb-proj-default" in "alertName" column in "Alerts_Table" table on "Alerts_Monitoring" wizard + And wait load page + Then verify "Header" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Overview_General_Headers" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Overview_General_Headers" on "Alerts_Endpoint_Info_Pane" wizard should contains "Alerts_Endpoint_Info_Pane"."Overview_General_Headers" + Then verify "Overview_Trigger_Criteria" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Overview_Trigger_Criteria" on "Alerts_Endpoint_Info_Pane" wizard should contains "Alerts_Jobs_Info_Pane"."Overview_Trigger_Criteria_Headers" + Then verify "Notifications_Header" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Notifications_Item" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Alerts_Endpoint_Info_Pane" wizard selected option value "Past 24 hours" + Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Alerts_Endpoint_Info_Pane" wizard should contains "Dropdown_Options"."Date_Picker_Filter_Options_Endpoint" + Then click on "Header" element on "Alerts_Endpoint_Info_Pane" wizard + And wait load page + Then verify "Metrics_App_Name" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Metrics_Stats_Card" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Metrics_Stats_Card_Metric_Name" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Metrics_Stats_Card_Metric_BodyBar" element visibility on "Alerts_Endpoint_Info_Pane" wizard + Then verify "Metrics_Stats_Card_Metric_BodyLine" element visibility on "Alerts_Endpoint_Info_Pane" wizard @MLAM @smoke diff --git a/tests/features/artifacts.feature b/tests/features/artifacts.feature index 941178179d..cf16832b42 100644 --- a/tests/features/artifacts.feature +++ b/tests/features/artifacts.feature @@ -480,11 +480,11 @@ Feature: Artifacts Page When click on cell with row index 1 in "name" column in "Files_Table" table on "Files" wizard And wait load page Then verify "Header" element visibility on "Files_Info_Pane" wizard - Then "Header" element on "Files_Info_Pane" should contains "test-file" value - #TODO: Verify text message 'The you are viewing was updated. Close the detail panel and refresh the list to see the current version.' on Files_Info_Pane + Then "Header" element on "Files_Info_Pane" should contains "survival-curves_km-survival" value + Then verify "Not_In_Filtered_List_Message" element visibility on "Files_Info_Pane" wizard + Then "Not_In_Filtered_List_Message" component on "Files_Info_Pane" should be equal "Files_Info_Pane"."Info_Banner_Message" #TODO: Verify that editing the tag to an empty string '' will delete the artifact instance - @MLA @passive @inProgress diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index 1b68abc227..2b18e7e480 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -74,8 +74,7 @@ export default { }, Feature_Sets_Info_Pane: { Created_State: 'Created', - Tab_List: ['Overview', 'Features', 'Transformations', 'Preview', 'Statistics'], - Tab_List_Demo: ['Overview', 'Features', 'Transformations', 'Preview', 'Statistics', 'Analysis'], + Tab_List: ['Overview', 'Features', 'Transformations', 'Preview', 'Statistics', 'Analysis'], Overview_General_Headers: [ 'Description:', 'Labels:', @@ -90,7 +89,7 @@ export default { ] }, Feature_Vectors_Info_Pane: { - Tab_List: ['Overview', 'Requested Features'], + Tab_List: ['Overview', 'Requested Features', 'Analysis'], Overview_General_Headers: [ 'Description:', 'Labels:', @@ -116,8 +115,8 @@ export default { Ranking_Criteria_List: ['Min', 'Max'] }, Datasets_Info_Pane: { - Tab_List: ['Overview', 'Preview', 'Metadata'], - Info_Banner_Message: /The (.+?) is not in the filtered list\. Closing the details panel will return you to the current list\./, + Tab_List: ['Overview', 'Preview', 'Metadata', 'Analysis'], + Info_Banner_Message: /The dataset is not in the filtered list\. Closing the details panel will return you to the current list\./, Overview_General_Headers: [ 'Hash:', 'Key:', @@ -385,13 +384,14 @@ export default { Refresh_Button: 'Refresh', Back_Button: 'Back', Expand_All_Button: 'Expand all', - In_Process_Jobs: 'Aborting, Pending, Running', + In_Process_Jobs: 'Aborting, Pending, Pending retry, Running', Running_Tip: 'Running', Failed_Tip: 'Failed', Failed_Jobs: 'Aborted, Error', Failed_Worflows: 'Error, Failed', Succeeded: 'Completed', Statistics_Tab_Tip: 'Statistics reflect the data for the latest ingestion. \n Note that some values may be empty due to the use of different engines for calculating statistics', + Monitoring_Jobs_Box_Title_Tip: 'Number of Job runs, clicking on the counters navigates to jobs screen.', Error_Content: 'Error. Columns must be same length as key', Error_Content_Workflow: "Error. 2021-08-29 20:01:36.582972: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib: 2021-08-29 20:01:36.583019: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine. 2021-08-29 20:01:46.470042: I tensorflow/compiler/jit/xla_cpu_device.cc:41] Not creating XLA devices, tf_xla_enable_xla_devices not set 2021-08-29 20:01:46.470263: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib:/usr/local/lib: 2021-08-29 20:01:46.470283: W tensorflow/stream_executor/cuda/cuda_driver.cc:326] failed call to cuInit: UNKNOWN ERROR (303) 2021-08-29 20:01:46.470306: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (train-1193bacd-worker-0): /proc/driver/nvidia/version does not exist 2021-08-29 20:01:46.518782: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags. 2021-08-29 20:01:46.518927: I tensorflow/compiler/jit/xla_gpu_device.cc:99] Not creating XLA devices, tf_xla_enable_xla_devices not set Some callbacks may not have access to the averaged metrics, see https://github.com/horovod/horovod/issues/2440 Traceback (most recent call last): File \"/User/demos/image-classification-with-distributed-training/src-tfv2/horovod-training.py\", line 116, in hvd.callbacks.LearningRateWarmupCallback(warmup_epochs=5, verbose=1), TypeError: __init__() missing 1 required positional argument: 'initial_lr'" @@ -533,9 +533,8 @@ export default { Operating_Functions: 'System functions that are used for the monitoring application operation', Lag: 'Number of messages currently waiting in the app\'s queue', Commited_Offset: 'Total number of messages handled by the app', - App_Status_Tip: 'Some tip', Endpoints_Tip: 'Model endpoints processed by the monitoring app during the selected time frame', - Metrics_Tip: 'Metrics tip', + Metrics_Tip: 'This table displays the values of the last metrics captured by the monitoring application. If there are metrics for more than one model endpoint at the same time, the table displays only one of those.', Shards_Partitions_Status_Tip: 'This table displays the current status of each shard' }, Descriptions: { @@ -639,18 +638,19 @@ export default { 'Completed', 'Error', 'Running', - 'Pending' + 'Pending', + 'Pending retry' ], Workflows_Status_Filter_Options: ['All', 'Error', 'Failed', 'Running', 'Completed'], Jobs_Type_Filter_Options: [ 'All', - 'Local', - 'Dask', - 'Databricks', - 'Handler', 'Job', + 'Spark', 'Horovod', - 'Spark' + 'Dask', + 'Databricks', + 'Local', + 'Handler' ], Scheduled_Type_Filter_Options: [ 'All', diff --git a/tests/features/common/actions/dropdown.action.js b/tests/features/common/actions/dropdown.action.js index 5fadbb95a8..dab8af11eb 100644 --- a/tests/features/common/actions/dropdown.action.js +++ b/tests/features/common/actions/dropdown.action.js @@ -102,13 +102,32 @@ export const checkDropdownContainsOptions = async (driver, dropdown, values) => notPresent.push(option) } } + + let extraPresent = [] + for (let option of options) { + if (values.every(item => item !== option)) { + extraPresent.push(option) + } + } + expect(notPresent.length).equal( 0, '\nOptions not present: ' + notPresent + '\noptions: ' + options + - '\nconst: ' + + '\nexpected: ' + + values + + '\n' + ) + + expect(extraPresent.length).equal( + 0, + '\nExtra unexpected options: ' + + extraPresent + + '\noptions: ' + + options + + '\nexpected: ' + values + '\n' ) diff --git a/tests/features/common/page-objects/feature-store.po.js b/tests/features/common/page-objects/feature-store.po.js index d4f6cd9b7f..bccd4f6d1a 100644 --- a/tests/features/common/page-objects/feature-store.po.js +++ b/tests/features/common/page-objects/feature-store.po.js @@ -47,7 +47,7 @@ const tabSelector = { const actionMenuStructure = { root: '.actions-menu__container', menuElements: { - open_button: 'button', + open_button: '[data-testid="actions-menu"]', options: '.actions-menu__body .actions-menu__option' } } diff --git a/tests/features/common/page-objects/info-pane.po.js b/tests/features/common/page-objects/info-pane.po.js index 3fa4609baf..abf58665ea 100644 --- a/tests/features/common/page-objects/info-pane.po.js +++ b/tests/features/common/page-objects/info-pane.po.js @@ -1030,8 +1030,11 @@ export default { false ) ), - Metrics_App_Name: By.css('.item-info__details-metrics .alerts-table__metrics .metrics__app-name'), - Metrics_Stats_Card: By.css('.item-info__details-metrics .alerts-table__metrics .metrics__card'), + Metrics_App_Name: By.css('[data-testid="detailsPanel"] .metrics .alerts-table__metrics-header'), + Metrics_Stats_Card: By.css('[data-testid="detailsPanel"] .metrics .metrics__card'), + Metrics_Stats_Card_Metric_Name: By.css('[data-testid="detailsPanel"] .metrics .metrics__card .stats-card__title .stats-card__title-wrapper'), + Metrics_Stats_Card_Metric_BodyBar: By.css('[data-testid="detailsPanel"] .metrics .metrics__card .metrics__card-body .metrics__card-body-bar'), + Metrics_Stats_Card_Metric_BodyLine: By.css('[data-testid="detailsPanel"] .metrics .metrics__card .metrics__card-body .metrics__card-body-line'), Metrics_Stats_Card_Empty: By.css('[data-testid="detailsPanel"] .metrics__empty-select') }, alertsApplicationInfoPane: { diff --git a/tests/features/common/page-objects/interactive-popup.po.js b/tests/features/common/page-objects/interactive-popup.po.js index 3e38b435fc..888df3cb86 100644 --- a/tests/features/common/page-objects/interactive-popup.po.js +++ b/tests/features/common/page-objects/interactive-popup.po.js @@ -1488,7 +1488,7 @@ export default { } }), Discard_Button: By.css('.apply-discard-buttons .pop-up-dialog__btn_cancel'), - Apply_Button: By.css('.apply-discard-buttons button.btn-secondary') + Apply_Button: By.css('.apply-discard-buttons .btn-primary') }, projectMembersPopup: { Cross_Cancel_Button: commonCrossCancelButton, @@ -1551,7 +1551,7 @@ export default { } }), Discard_Button: By.css('.apply-discard-buttons .pop-up-dialog__btn_cancel'), - Apply_Button: By.css('.apply-discard-buttons button.btn-secondary'), + Apply_Button: By.css('.apply-discard-buttons .btn-primary'), Footer_Annotation_Label: By.css('.footer-annotation') }, createNewSecretPopup: { @@ -1737,7 +1737,7 @@ export default { generateDropdownGroup( '[data-testid="type-form-field-select"]', '[data-testid="select-header"]', - '[data-testid="select-option"] [data-testid="tooltip-wrapper"]' + '.options-list .select__item:not(.hidden) .tooltip-wrapper' ) ), Show_Iterations_Checkbox: checkboxComponent({ @@ -1796,6 +1796,14 @@ export default { icon: '' } }), + Status_Pending_retry_Checkbox: checkboxComponent({ + root: '[data-testid="select-checkbox"]:nth-of-type(8)', + elements: { + checkbox: 'input', + name: 'label', + icon: '' + } + }), Status_Aborted_Checkbox: checkboxComponent({ root: '[data-testid="select-checkbox"]:nth-of-type(2)', elements: { diff --git a/tests/features/common/page-objects/monitoring-app.po.js b/tests/features/common/page-objects/monitoring-app.po.js index bd3f4d0ab3..94b3eb5e84 100644 --- a/tests/features/common/page-objects/monitoring-app.po.js +++ b/tests/features/common/page-objects/monitoring-app.po.js @@ -322,7 +322,6 @@ export default { Application_Metrics_Button: By.css('.action-bar [data-testid="btn"] span'), Refresh_Button: By.css('.action-bar [data-testid="refresh"] button'), App_Status_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__title span'), - App_Status_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) [data-testid="tip"] svg'), App_Status_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) [data-testid="monitoring-app-appStatus"] .stats__counter'), Endpoints_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__title span'), Endpoints_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) [data-testid="tip"] svg'), diff --git a/tests/features/common/page-objects/projects.po.js b/tests/features/common/page-objects/projects.po.js index 7f780fc86b..113267f1d6 100644 --- a/tests/features/common/page-objects/projects.po.js +++ b/tests/features/common/page-objects/projects.po.js @@ -101,7 +101,22 @@ const ProjectsTableSelector = { } } +const projectsTabSelector = { + root: '.projects-content-header .content-menu', + header: {}, + body: { + root: '.content-menu__tabs', + row: { + root: '.content-menu__tab', + fields: { + key: '' + } + } + } +} + export default { + Projects_Tab_Selector: commonTable(projectsTabSelector), Retrieving_Projects_Message: By.css('[data-testid=no-data]'), No_Archived_Projects_Message: By.css('.no-filtered-data'), New_Project_Button: By.css( @@ -150,41 +165,41 @@ export default { }, Monitoring_Jobs_Box: { Monitoring_Jobs_Box_Title: By.css( - '.projects-monitoring-stats .stats-card:nth-of-type(1) .stats-card__title' + '.projects-monitoring-stats > div:nth-child(2) .stats-card__title .tooltip-wrapper' ), - Filtering_Time_Period: By.css('.stats-card:nth-of-type(1) .stats-card__col > div > span'), - Total_Counter_Title: By.css( - '.stats-card:nth-of-type(1) .stats-card__col > div > div > span' + Monitoring_Jobs_Box_Title_Tip: By.css( + '.projects-monitoring-stats > div:nth-child(2) .stats-card__title [data-testid="tip"] svg' ), + Filtering_Time_Period: By.css('.projects-monitoring-stats > div:nth-child(2) span'), Total_Counter_Number: By.css( - '.stats-card:nth-of-type(1) .stats-card__col > div > div .stats__counter' + '.projects-monitoring-stats > div:nth-child(2) [data-testid="scheduled_total_counter"]' ), Counter_Running_Status_Number: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_running_counter"] .stats__counter' + '.projects-monitoring-stats > div:nth-child(2) .stats__details .stats-card__row:nth-of-type(1) .stats__counter' ), Counter_Running_Status_Subtitle: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_running_counter"] .stats__subtitle' + '.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(1) .stats__subtitle' ), Counter_Running_Status_Icon: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_running_counter"] .state-running' + '.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(1) .state-running' ), Counter_Failed_Status_Number: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_failed_counter"] .stats__counter' + '.projects-monitoring-stats > div:nth-child(2) .stats__details .stats-card__row:nth-of-type(2) .stats__counter' ), Counter_Failed_Status_Subtitle: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_failed_counter"] .stats__subtitle' + '.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(2) .stats__subtitle' ), Counter_Failed_Status_Icon: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_failed_counter"] .state-failed' + '.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(2) .state-failed' ), Counter_Completed_Status_Number: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_completed_counter"] .stats__counter' + '.projects-monitoring-stats > div:nth-child(2) .stats__details .stats-card__row:nth-of-type(3) .stats__counter' ), Counter_Completed_Status_Subtitle: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_completed_counter"] .stats__subtitle' + '.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(3) .stats__subtitle' ), Counter_Completed_Status_Icon: By.css( - '.stats-card:nth-of-type(1) [data-testid="jobs_completed_counter"] .state-completed' + '.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(3) .state-completed' ) }, Monitoring_Workflows_Box: { @@ -192,11 +207,8 @@ export default { '.projects-monitoring-stats .stats-card:nth-of-type(2) .stats-card__title' ), Filtering_Time_Period: By.css('.stats-card:nth-of-type(2) .stats-card__col > div > span'), - Total_Counter_Title: By.css( - '.stats-card:nth-of-type(2) .stats-card__col > div > div > span' - ), Total_Counter_Number: By.css( - '.stats-card:nth-of-type(2) .stats-card__col > div > div .stats__counter' + '.projects-monitoring-stats > div:nth-child(3) [data-testid="scheduled_total_counter"]' ), Counter_Running_Status_Number: By.css( '.stats-card:nth-of-type(2) [data-testid="wf_running_counter"] .stats__counter' @@ -247,40 +259,40 @@ export default { '.stats-card:nth-of-type(3) [data-testid="scheduled_wf_counter"] .stats__counter' ), Total_Scheduled_Number: By.css( - '.stats-card:nth-of-type(3) .stats-card__col > div > div .stats__counter' + '.projects-monitoring-stats > div:nth-child(4) [data-testid="scheduled_total_counter"]' ) }, Monitoring_Alerts_Box: { Monitoring_Alerts_Box_Title: By.css( - '.projects-monitoring-stats .stats-card:nth-of-type(4) .stats-card__title' + '.projects-monitoring-stats .alerts-card .stats-card__title .data-ellipsis' ), Monitoring_Alerts_Box_Title_Icon: By.css( '.projects-monitoring-stats .stats-card:nth-of-type(4) .stats-card__title svg' ), Filtering_Time_Period: By.css('.stats-card:nth-of-type(4) .stats-card__col > div > span'), Total_Endpoint_Counter_Number: By.css( - '.stats-card:nth-of-type(4) [data-testid="alerts_endpoint_counter"] .stats__counter' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_endpoints_counter"]' ), Total_Endpoint_Counter_Title: By.css( - '.stats-card:nth-of-type(4) [data-testid="alerts_endpoint_counter"] .stats__subtitle' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_endpoints_counter"] h6' ), Total_Jobs_Counter_Number: By.css( - '.stats-card:nth-of-type(4) [data-testid="alerts_jobs_counter"] .stats__counter' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_job_counter"]' ), Total_Jobs_Counter_Title: By.css( - '.stats-card:nth-of-type(4) [data-testid="alerts_jobs_counter"] .stats__subtitle' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_job_counter"] h6' ), Total_Application_Counter_Number: By.css( - '.stats-card:nth-of-type(4) [data-testid="alerts_application_counter stats__counter-large"] .stats__counter' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_application_counter"]' ), Total_Application_Counter_Title: By.css( - '.stats-card:nth-of-type(4) [data-testid="alerts_application_counter stats__counter-large"] .stats__subtitle' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_application_counter"] .stats__subtitle' ), Total_Alerts_Title: By.css( '.stats-card:nth-of-type(4) .stats-card__col > div > div > span' ), Total_Alerts_Number: By.css( - '.stats-card:nth-of-type(4) .stats-card__col > div > div .stats__counter' + '.projects-monitoring-stats .alerts-card [data-testid="alerts_total_counter"]' ) } } diff --git a/tests/features/datasets.feature b/tests/features/datasets.feature index d1e932e1e1..da894c1002 100644 --- a/tests/features/datasets.feature +++ b/tests/features/datasets.feature @@ -88,6 +88,7 @@ Feature: Datasets Page @MLD @passive @smoke + #TODO: Datasets Analysis tab - add the data to verify Scenario: MLD003 - Check all mandatory components in Item infopane on Overview tab table on Datasets page Given open url And wait load page @@ -142,6 +143,7 @@ Feature: Datasets Page @MLD @passive @smoke + #TODO: Datasets Analysis tab - add the data to verify Scenario: MLD005 - Check Details panel still active on page refresh # * set tear-down property "dataset" created in "automation-test" project with "test-file" value * create "test-dataset" Dataset with "v1" tag in "default" project with code 200 @@ -468,7 +470,6 @@ Feature: Datasets Page When select "V3IO" option in "Path_Scheme_Combobox" combobox on "Target_Path" accordion on "Register_Dataset" wizard When type value "target/path" to "Path_Scheme_Combobox" field on "Target_Path" on "Register_Dataset" wizard Then click on "Register_Button" element on "Register_Dataset" wizard - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Overwrite dataset?" value When click on "Overwrite_Button" element on "Confirm_Popup" wizard @@ -482,19 +483,22 @@ Feature: Datasets Page Then click on "History_Back_Button" element on "Datasets" wizard When click on cell with row index 1 in "name" column in "Datasets_Table" table on "Datasets" wizard And wait load page - Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - And wait load page - Then "Notification_Pop_Up" element on "Notification_Popup" should contains "An error occurred while retrieving the dataset." value - And wait load page - Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard - Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Header" element visibility on "Datasets_Info_Pane" wizard + Then "Header" element on "Datasets_Info_Pane" should contains "test-regressor_cox-test-summary" value + Then verify "Not_In_Filtered_List_Message" element visibility on "Datasets_Info_Pane" wizard + Then "Not_In_Filtered_List_Message" component on "Datasets_Info_Pane" should be equal "Datasets_Info_Pane"."Info_Banner_Message" Then click on "Table_Refresh_Button" element on "Datasets" wizard And wait load page + Then "Header" element on "Datasets_Info_Pane" should contains "test-regressor_cox-test-summary" value + Then verify "Not_In_Filtered_List_Message" element not exists on "Datasets_Info_Pane" wizard + Then click on "Cross_Close_Button" element on "Datasets_Info_Pane" wizard + And wait load page + Then verify "Datasets_Table" element visibility on "Datasets" wizard When click on cell with row index 1 in "name" column in "Datasets_Table" table on "Datasets" wizard And wait load page - Then verify "Header" element visibility on "Files_Info_Pane" wizard + Then verify "Header" element visibility on "Datasets_Info_Pane" wizard Then "Header" element on "Files_Info_Pane" should contains "test-regressor_cox-test-summary" value - #TODO: Verify text message 'The you are viewing was updated. Close the detail panel and refresh the list to see the current version.' on Files_Info_Pane + Then verify "Not_In_Filtered_List_Message" element not exists on "Datasets_Info_Pane" wizard #TODO: Verify that editing the tag to an empty string '' will delete the artifact instance @MLD @@ -668,6 +672,7 @@ Feature: Datasets Page @MLD @smoke + #TODO: check the loader after click on "Register_Button" element on "Register_Dataset" wizard Scenario: MLD011 - Check that version tag has "Click to add" status when it's empty after edited Given open url And wait load page @@ -691,7 +696,6 @@ Feature: Datasets Page When select "V3IO" option in "Path_Scheme_Combobox" combobox on "Target_Path" accordion on "Register_Dataset" wizard When type value "target/path" to "Path_Scheme_Combobox" field on "Target_Path" on "Register_Dataset" wizard Then click on "Register_Button" element on "Register_Dataset" wizard - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Overwrite dataset?" value When click on "Overwrite_Button" element on "Confirm_Popup" wizard @@ -705,6 +709,7 @@ Feature: Datasets Page @MLD @smoke + #TODO: check the loader after click on "Register_Button" element on "Register_Dataset" wizard Scenario: MLD012 - Check filter by "All" tag is performed when version tag was edited Given open url And wait load page @@ -743,7 +748,6 @@ Feature: Datasets Page When select "V3IO" option in "Path_Scheme_Combobox" combobox on "Target_Path" accordion on "Register_Dataset" wizard When type value "target/path" to "Path_Scheme_Combobox" field on "Target_Path" on "Register_Dataset" wizard Then click on "Register_Button" element on "Register_Dataset" wizard - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Overwrite dataset?" value When click on "Overwrite_Button" element on "Confirm_Popup" wizard diff --git a/tests/features/featureStore.feature b/tests/features/featureStore.feature index 00c3a282b9..61d354f342 100644 --- a/tests/features/featureStore.feature +++ b/tests/features/featureStore.feature @@ -209,7 +209,6 @@ Feature: Feature Store Page @passive @inProgress @smoke - # Moved analyses tabs to Demo mode in `1.8.0` ML-9059 Scenario: MLFS005 - Check all mandatory components in Item infopane on Overview tab table on Feature Vectors tab Given open url And wait load page @@ -2300,6 +2299,7 @@ Feature: Feature Store Page @MLFS @smoke + #TODO: check the loader after select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table Scenario: MLFS061 - Check Feature vector deletion Given open url And wait load page @@ -2313,7 +2313,6 @@ Feature: Feature Store Page And wait load page Then verify "Feature Vectors" tab is active in "Feature_Store_Tab_Selector" on "Feature_Store_Feature_Sets_Tab" wizard Then select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table at row with "patient-deterioration" value in "name" column - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Delete feature vector?" value Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard @@ -2328,7 +2327,6 @@ Feature: Feature Store Page When click on "Cancel_Button" element on "Confirm_Popup" wizard And wait load page Then select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table at row with "patient-deterioration" value in "name" column - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard When click on "Cross_Cancel_Button" element on "Confirm_Popup" wizard @@ -2341,13 +2339,11 @@ Feature: Feature Store Page And wait load page Then check "expand_btn" visibility in "Feature_Vectors_Table" on "Feature_Store_Features_Vectors_Tab" wizard with 0 offset Then select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table at row with "patient-deterioration" value in "name" column - And wait load page Then verify if "Confirm_Popup" popup dialog appears When click on "Cancel_Button" element on "Confirm_Popup" wizard And wait load page Then click on cell with row index 2 in "expand_btn" column in "Feature_Vectors_Table" table on "Feature_Store_Features_Vectors_Tab" wizard Then select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table at row with "latest" value in "name_expand_btn" column - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Delete feature vector?" value Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard @@ -2362,13 +2358,11 @@ Feature: Feature Store Page When click on "Cancel_Button" element on "Confirm_Popup" wizard And wait load page Then select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table at row with "latest" value in "name_expand_btn" column - And wait load page When click on "Cancel_Button" element on "Confirm_Popup" wizard And wait load page When click on cell with row index 2 in "name" column in "Feature_Vectors_Table" table on "Feature_Store_Features_Vectors_Tab" wizard Then verify "Header" element visibility on "Feature_Vectors_Info_Pane" wizard Then select "Delete" option in action menu on "Feature_Vectors_Info_Pane" wizard - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Delete feature vector?" value Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard @@ -2385,13 +2379,11 @@ Feature: Feature Store Page When click on cell with row index 2 in "name" column in "Feature_Vectors_Table" table on "Feature_Store_Features_Vectors_Tab" wizard Then verify "Header" element visibility on "Feature_Vectors_Info_Pane" wizard Then select "Delete" option in action menu on "Feature_Vectors_Info_Pane" wizard - And wait load page When click on "Cancel_Button" element on "Confirm_Popup" wizard And wait load page When click on cell with row index 2 in "name" column in "Feature_Vectors_Table" table on "Feature_Store_Features_Vectors_Tab" wizard Then verify "Header" element visibility on "Feature_Vectors_Info_Pane" wizard Then select "Delete" option in action menu on "Feature_Vectors_Info_Pane" wizard - And wait load page Then verify if "Confirm_Popup" popup dialog appears When click on "Delete_Button" element on "Confirm_Popup" wizard And wait load page @@ -2404,7 +2396,6 @@ Feature: Feature Store Page Then verify that 3 row elements are displayed in "Feature_Vectors_Table" on "Feature_Store_Features_Vectors_Tab" wizard Then click on cell with row index 1 in "expand_btn" column in "Feature_Vectors_Table" table on "Feature_Store_Features_Vectors_Tab" wizard Then select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table at row with "7" value in "name_expand_btn" column - And wait load page Then verify if "Confirm_Popup" popup dialog appears When click on "Delete_Button" element on "Confirm_Popup" wizard And wait load page @@ -2415,7 +2406,6 @@ Feature: Feature Store Page Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard Then verify that 2 row elements are displayed in "Feature_Vectors_Table" on "Feature_Store_Features_Vectors_Tab" wizard Then select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table at row with "erann-fv" value in "name" column - And wait load page Then verify if "Confirm_Popup" popup dialog appears When click on "Delete_Button" element on "Confirm_Popup" wizard And wait load page @@ -2429,7 +2419,6 @@ Feature: Feature Store Page Then click on "Clear_Button" element on "FilterBy_Popup" wizard And wait load page Then select "Delete" option in action menu on "Feature_Store_Features_Vectors_Tab" wizard in "Feature_Vectors_Table" table at row with "patient-deterioration" value in "name" column - And wait load page Then verify if "Confirm_Popup" popup dialog appears When click on "Delete_Button" element on "Confirm_Popup" wizard And wait load page diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index 8170d0e071..0b546c0cbd 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -627,6 +627,7 @@ Feature: Jobs and workflows And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Jobs and workflows" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And wait load page + And wait load page Then verify "Monitor Jobs" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitor_Tab" wizard @@ -672,6 +673,7 @@ Feature: Jobs and workflows And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Jobs and workflows" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And wait load page + And wait load page Then verify "Monitor Jobs" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "BE_Pagination_Navigate_Prev" element visibility on "Pagination_Info_Pane" wizard Then verify "BE_Pagination_Navigate_Prev" element on "Pagination_Info_Pane" wizard is disabled @@ -749,7 +751,7 @@ Feature: Jobs and workflows Then verify "Title" element visibility on "Modal_Transition_Popup" wizard Then "Title" element on "Modal_Transition_Popup" should contains "aggregate" value Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard - Then "Data_Status" element on "Modal_Transition_Popup" should contains "Nov 25, 2021, 04:20:00 PM" value + Then "Data_Status" element on "Modal_Transition_Popup" should contains "Nov 25, 2021, 05:20:00 PM" value Then verify "State_Icon" element visibility on "Modal_Transition_Popup" wizard Then verify "State_Icon" element on "Modal_Transition_Popup" wizard should display hover tooltip "ML_Function_Info_Pane"."Initialized_State" Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard diff --git a/tests/features/jobsMonitoring.feature b/tests/features/jobsMonitoring.feature index 91fbd51eee..29df3fb998 100644 --- a/tests/features/jobsMonitoring.feature +++ b/tests/features/jobsMonitoring.feature @@ -58,7 +58,7 @@ Feature: Jobs Monitoring Page Then verify "Jobs" tab is active in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Jobs_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Workflows_Tab" wizard selected option value "Any time" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard - Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "3 items selected" + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "4 items selected" Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" And wait load page Then click on "Status_Filter_Element" element on "FilterBy_Popup" wizard @@ -66,6 +66,7 @@ Feature: Jobs Monitoring Page Then "Status_Aborting_Checkbox" element should be checked on "FilterBy_Popup" wizard Then "Status_Jobs_Running_Checkbox" element should be checked on "FilterBy_Popup" wizard Then "Status_Pending_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Status_Pending_retry_Checkbox" element should be checked on "FilterBy_Popup" wizard Then verify "Jobs_Table" element visibility on "Jobs_Monitoring_Jobs_Tab" wizard Then click on breadcrumbs "projectsPage" label on "commonPagesHeader" wizard And wait load page diff --git a/tests/features/monitoringApp.feature b/tests/features/monitoringApp.feature index 8abfaff272..074bc854d8 100644 --- a/tests/features/monitoringApp.feature +++ b/tests/features/monitoringApp.feature @@ -82,7 +82,7 @@ Feature: Monitoring app Page Then "Endpoints_RealTime_SubTitle" element on "Monitoring_App" should contains "Real-time" value Then verify "Endpoints_RealTime_Counter" element visibility on "Monitoring_App" wizard Then verify "RunningFrequency_Stats_Title" element visibility on "Monitoring_App" wizard - Then "RunningFrequency_Stats_Title" element on "Monitoring_App" should contains "Running frequency" value + Then "RunningFrequency_Stats_Title" element on "Monitoring_App" should contains "Running interval" value Then verify "RunningFrequency_Value_Title" element visibility on "Monitoring_App" wizard Then "RunningFrequency_Value_Title" element on "Monitoring_App" should contains "Every 10 minutes" value @@ -231,8 +231,6 @@ Feature: Monitoring app Page Then verify "Back_Button" element visibility on "Application_Monitoring" wizard Then verify "App_Status_Title" element visibility on "Application_Monitoring" wizard Then "App_Status_Title" element on "Application_Monitoring" should contains "App Status" value - Then verify "App_Status_Tip" element visibility on "Application_Monitoring" wizard - Then verify "App_Status_Tip" element on "Application_Monitoring" wizard should display hover hint "Label_Hint"."App_Status_Tip" Then verify "App_Status_SubTitle" element visibility on "Application_Monitoring" wizard Then "App_Status_SubTitle" element on "Application_Monitoring" should contains "Ready" value Then verify "Endpoints_Title" element visibility on "Application_Monitoring" wizard @@ -337,7 +335,6 @@ Feature: Monitoring app Page @MLMA @smoke - #TODO: Scroll to the Shards/partitions status section Scenario: MLMA010 - Check Shards/partitions status section components on Application monitoring page Given open url And wait load page @@ -355,6 +352,7 @@ Feature: Monitoring app Page Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page + When scroll to the "Shards_Partitions_Status_Title" element on "Application_Monitoring" wizard Then verify "Shards_Partitions_Status_Title" element visibility on "Application_Monitoring" wizard Then "Shards_Partitions_Status_Title" element on "Application_Monitoring" should contains "Shards/partitions status" value Then verify "Shards_Partitions_Status_Tip" element visibility on "Application_Monitoring" wizard diff --git a/tests/features/projectMonitoring.feature b/tests/features/projectMonitoring.feature index b97d00ab18..b3f8307a5c 100644 --- a/tests/features/projectMonitoring.feature +++ b/tests/features/projectMonitoring.feature @@ -674,13 +674,27 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on cell with value "Running jobs" in "name" column in "Jobs_Info_Card_Statistics" table on "Project" wizard + Then click on cell with value "Running" in "name" column in "Jobs_Info_Card_Statistics" table on "Project" wizard And wait load page Then verify "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard should contains "Jobs_And_Workflows"."Tab_List" Then verify "Monitor Jobs" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "Table_Name_Filter_Input" element visibility on "Jobs_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitor_Tab" wizard selected option value "Any time" Then verify "Table_FilterBy_Button" element visibility on "Jobs_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Jobs_Monitor_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "4 items selected" + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + And wait load page + Then click on "Status_Filter_Element" element on "FilterBy_Popup" wizard + Then "Status_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Status_Aborting_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Status_Jobs_Running_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Status_Pending_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Status_Pending_retry_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Status_Aborted_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Status_Jobs_Error_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Status_Jobs_Completed_Checkbox" element should be unchecked on "FilterBy_Popup" wizard Then verify "Batch_Run_Button" element visibility on "Jobs_Monitor_Tab" wizard Then "Batch_Run_Button" element on "Jobs_Monitor_Tab" should contains "Batch run" value Then verify "Resource_Monitoring_Button" element visibility on "Jobs_Monitor_Tab" wizard @@ -688,8 +702,11 @@ Feature: Project Monitoring Page Then "Auto_Refresh_Checkbox" element should be unchecked on "Jobs_Monitor_Tab" wizard Then verify "Table_Refresh_Button" element visibility on "Jobs_Monitor_Tab" wizard Then verify "Jobs_Monitor_Table" element visibility on "Jobs_Monitor_Tab" wizard + Then navigate back + And wait load page + Then click on cell with value "Failed" in "name" column in "Jobs_Info_Card_Statistics" table on "Project" wizard + And wait load page - @MLPM @passive @smoke diff --git a/tests/features/projectsPage.feature b/tests/features/projectsPage.feature index 6d446f628f..05fbea66f3 100644 --- a/tests/features/projectsPage.feature +++ b/tests/features/projectsPage.feature @@ -90,6 +90,8 @@ Feature: Projects Page Scenario: MLPr005 - Verify all mandatory components on Archive ML Project Given open url And wait load page + When scroll to the element with "churn-project-admin" value in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page Then select "Archive" option in action menu on "Projects" wizard in "Projects_Table" table at row with "churn-project-admin" value in "name" column Then verify if "Common_Popup" popup dialog appears Then "Description" component on "Common_Popup" should contains "Descriptions"."Archive_Project" @@ -104,6 +106,8 @@ Feature: Projects Page Scenario: MLPr006 - Verify all mandatory components on Delete existing ML Project Given open url And wait load page + When scroll to the element with "churn-project-admin" value in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page Then select "Delete" option in action menu on "Projects" wizard in "Projects_Table" table at row with "churn-project-admin" value in "name" column And wait load page Then verify if "Common_Popup" popup dialog appears @@ -143,12 +147,16 @@ Feature: Projects Page Then "Description" component on "Common_Popup" should be equal "Descriptions"."Delete_Project_Confirm_Message" Then click on "Delete_Button" element on "Common_Popup" wizard And wait load page + And select "Archived" tab in "Projects_Tab_Selector" on "Projects" wizard + Then verify "Archived" tab is active in "Projects_Tab_Selector" on "Projects" wizard Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Project deletion in progress" value And wait load page Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard And wait load page + And select "Active" tab in "Projects_Tab_Selector" on "Projects" wizard + Then verify "Active" tab is active in "Projects_Tab_Selector" on "Projects" wizard Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Project \"empty-project\" was deleted successfully" value @@ -171,10 +179,15 @@ Feature: Projects Page And click on "Add_Label_Button" element on "Create_New_Project" wizard Then type value "/" to "Labels_Key" field on "Create_New_Project" wizard Then verify labels warning should display options "Input_Hint"."Projects_Labels_Warning_Key" + Then type value "/" to "Labels_Value" field on "Create_New_Project" wizard + Then verify labels warning should display options "Input_Hint"."Projects_Labels_Warning_Value" Then verify "Labels_Key" options rules on "Create_New_Project" wizard with labels + And wait load page + Then type into "Description_Input" on "Create_New_Project" popup dialog "automation test description new" value Then type value "/" to "Labels_Value" field on "Create_New_Project" wizard Then verify labels warning should display options "Input_Hint"."Projects_Labels_Warning_Value" Then verify "Labels_Value" options rules on "Create_New_Project" wizard with labels + And wait load page Then type value "/" to "Labels_Key" field on "Create_New_Project" wizard Then type value "/" to "Labels_Value" field on "Create_New_Project" wizard When click on "Title" element on "Create_New_Project" wizard @@ -211,12 +224,16 @@ Feature: Projects Page Then select "Delete" option in action menu on "Projects" wizard in "Projects_Table" table at row with "automation-test-name2" value in "name" column Then verify if "Common_Popup" popup dialog appears Then click on "Delete_Button" element on "Common_Popup" wizard + And select "Archived" tab in "Projects_Tab_Selector" on "Projects" wizard + Then verify "Archived" tab is active in "Projects_Tab_Selector" on "Projects" wizard And wait load page Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Project deletion in progress" value Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard And wait load page + And select "Active" tab in "Projects_Tab_Selector" on "Projects" wizard + Then verify "Active" tab is active in "Projects_Tab_Selector" on "Projects" wizard And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard @@ -266,6 +283,7 @@ Feature: Projects Page Scenario: MLPr011 - Verify View YAML action Given open url And wait load page + When scroll to the element with "default" value in "name" column in "Projects_Table" table on "Projects" wizard Then select "View YAML" option in action menu on "Projects" wizard in "Projects_Table" table at row with "default" value in "name" column Then verify if "View_YAML" popup dialog appears Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard @@ -380,15 +398,15 @@ Feature: Projects Page Then "Monitoring_Container_Title" element in "Projects_Monitoring_Container" on "Projects" should contains "Monitoring" value Then verify "Monitoring_Jobs_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Jobs_Box_Title" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then "Monitoring_Jobs_Box_Title" element in "Monitoring_Jobs_Box" on "Projects" should contains "Jobs" value + Then "Monitoring_Jobs_Box_Title" element in "Monitoring_Jobs_Box" on "Projects" should contains "Runs" value + Then verify "Monitoring_Jobs_Box_Title_Tip" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard + Then verify "Monitoring_Jobs_Box_Title_Tip" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover hint "Common_Tooltips"."Monitoring_Jobs_Box_Title_Tip" Then verify "Filtering_Time_Period" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then "Filtering_Time_Period" element in "Monitoring_Jobs_Box" on "Projects" should contains "Past 24 hours" value - Then verify "Total_Counter_Title" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then "Total_Counter_Title" element in "Monitoring_Jobs_Box" on "Projects" should contains "Total" value + Then "Filtering_Time_Period" element in "Monitoring_Jobs_Box" on "Projects" should contains "Past 24 hrs" value Then verify "Total_Counter_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Running_Status_Subtitle" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then "Counter_Running_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "In Process" value + Then "Counter_Running_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "Running" value Then verify "Counter_Running_Status_Icon" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Running_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard @@ -400,11 +418,12 @@ Feature: Projects Page Then verify "Counter_Completed_Status_Subtitle" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then "Counter_Completed_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "Succeeded" value Then verify "Counter_Completed_Status_Icon" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard + Then verify "Counter_Running_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" Then verify "Counter_Completed_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."Succeeded" Then "Counter_Completed_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" should contains "1" value When click on "Counter_Running_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=running%2Cpending%2Caborting&dates=anyTime&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=running%2Cpending%2CpendingRetry%2Caborting&dates=anyTime&bePage=1&fePage=1" Then navigate back And wait load page When click on "Counter_Failed_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard @@ -443,8 +462,6 @@ Feature: Projects Page Then "Monitoring_Workflows_Box_Title" element in "Monitoring_Workflows_Box" on "Projects" should contains "Workflows" value Then verify "Filtering_Time_Period" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Filtering_Time_Period" element in "Monitoring_Workflows_Box" on "Projects" should contains "Past 24 hours" value - Then verify "Total_Counter_Title" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then "Total_Counter_Title" element in "Monitoring_Workflows_Box" on "Projects" should contains "Total" value Then verify "Total_Counter_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then verify "Counter_Running_Status_Subtitle" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard @@ -613,9 +630,9 @@ Feature: Projects Page Then verify "Monitoring_Workflows_Box_Title" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Monitoring_Workflows_Box_Title" element in "Monitoring_Workflows_Box" on "Projects" should contains "Workflows" value Then verify "Total_Counter_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "3" value + Then "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "4" value Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then "Counter_Running_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "0" value + Then "Counter_Running_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "1" value Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Counter_Failed_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "1" value Then verify "Counter_Completed_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard diff --git a/tests/features/quickActions.feature b/tests/features/quickActions.feature index 3ec06b0022..dffc53b5d6 100644 --- a/tests/features/quickActions.feature +++ b/tests/features/quickActions.feature @@ -3,7 +3,6 @@ Feature: Quick actions Page Testcases that verifies functionality on MLRun Quick actions Page @MLPH - @smoke Scenario: MLPH001 - Check all mandatory components on Project Home * set tear-down property "project" created with "automation-test-1002" value * create "automation-test-1002" MLRun Project with code 201 @@ -84,7 +83,6 @@ Feature: Quick actions Page | Monitoring | @MLPH - @smoke Scenario: MLPH002 - Verify behaviour on Register Model Popup on Project Home Page Given open url And wait load page @@ -139,7 +137,6 @@ Feature: Quick actions Page Then check "v3io:///target/" value in "path" column in "Overview_Table" table on "Models_Info_Pane" wizard @MLPH - @smoke @passive Scenario: MLPH003 - Check all mandatory components on Create New Feature Set on Project Home Page Given open url @@ -191,7 +188,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH004 - Check all mandatory components on Register Dataset Popup on Project Home Page Given open url And wait load page @@ -250,7 +246,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH005 - Check all mandatory components on Create ML Function on Project Home Page * set tear-down property "project" created with "automation-test-1003" value * create "automation-test-1003" MLRun Project with code 201 @@ -285,7 +280,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH006 - Check all mandatory components on Batch run wizard Given open url And wait load page @@ -452,7 +446,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH008 - Check all mandatory components on Create a Feature Vector Popup on Project Home Page Given open url And wait load page @@ -477,7 +470,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH009 - Check all mandatory components on Feature Set tab on Project Home Page Given open url And wait load page @@ -520,7 +512,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH010 - Check all mandatory components on Files tab on Project Home Page Given open url And wait load page @@ -547,7 +538,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH011 - Check all mandatory components on Datasets tab on Project Home Page Given open url And wait load page @@ -573,7 +563,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH012 - Check all mandatory components on Feature Vectors tab on Project Home Page Given open url And wait load page @@ -603,7 +592,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH013 - Check all mandatory components on ML Functions tab on Project Home Page Given open url And wait load page @@ -639,7 +627,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH014 - Check all mandatory components on Monitor Jobs tab on Project Home Page Given open url And wait load page @@ -681,7 +668,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH015 - Check all mandatory components on Models tab on Project Home Page Given open url And wait load page @@ -712,7 +698,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH016 - Check all mandatory components on Monitor Workflows tab on Project Home Page Given open url And wait load page @@ -735,7 +720,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH017 - Check all mandatory components on Models Endpoint tab on Project Home Page Given open url And wait load page @@ -772,7 +756,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH018 - Check all mandatory components on Real-Time Piplines tab on Project Home Page Given open url And wait load page @@ -793,7 +776,6 @@ Feature: Quick actions Page @MLPH @passive - @smoke Scenario: MLPH019 - Check all mandatory components on Monitoring tab on Project Home Page Given open url And wait load page @@ -819,7 +801,6 @@ Feature: Quick actions Page Then verify "General_Info_Quick_Links" element visibility on "commonPagesHeader" wizard @MLPH - @smoke Scenario: MLPH020 - Check all mandatory components on Batch inference in Advanced section Given open url And wait load page @@ -934,7 +915,6 @@ Feature: Quick actions Page @MLPH @inProgress - @smoke Scenario: MLPH023 - Check components - batch inference_v2, preview text, path type Given open url And wait load page @@ -961,7 +941,6 @@ Feature: Quick actions Page #TODO: check Data Inputs path type (Data_Inputs_Inference_Table) @MLPH - @smoke Scenario: MLPH024 - Check Train model wizard opens up Given open url And wait load page diff --git a/tests/features/step-definitions/steps.js b/tests/features/step-definitions/steps.js index 4ba1c93160..8cc0b91a39 100644 --- a/tests/features/step-definitions/steps.js +++ b/tests/features/step-definitions/steps.js @@ -144,10 +144,10 @@ When('turn on demo mode with query params {string}', async function(state) { await navigateToPage(this.driver, `${url}${state === 'true' ? '&' : '?'}mode=demo`) }) -When('turn on staging mode', async function() { +When('turn on staging mode with query params {string}', async function(state) { const url = await this.driver.getCurrentUrl() - await navigateToPage(this.driver, `${url}?mode=staging`) + await navigateToPage(this.driver, `${url}${state === 'true' ? '&' : '?'}mode=staging`) }) Then('turn Off MLRun CE mode', async function() { @@ -1111,6 +1111,18 @@ Then( } ) +Then( + 'verify {string} element in {string} on {string} wizard should display hover hint {string}.{string}', + async function(inputField, accordion, wizard, constStorage, constValue) { + await checkComponentHintTextWithHover( + this.driver, + pageObjects[wizard][accordion][inputField], + pageObjects['commonPagesHeader']['Common_Hint'], + pageObjectsConsts[constStorage][constValue] + ) + } +) + Then( 'verify {string} on {string} wizard should display {string}.{string} in {string}', async function(inputField, wizard, constStorage, constValue, commonTipType) { diff --git a/tests/features/step-definitions/table.steps.js b/tests/features/step-definitions/table.steps.js index 3c815e38a6..d1ab1d3ab8 100644 --- a/tests/features/step-definitions/table.steps.js +++ b/tests/features/step-definitions/table.steps.js @@ -90,6 +90,14 @@ Then( } ) +When( + 'scroll to the {string} element on {string} wizard', + async function (component, wizard) { + await waiteUntilComponent(this.driver, pageObjects[wizard][component]) + await scrollToElement(this.driver, pageObjects[wizard][component]) + } +) + When( 'scroll to the element with {string} value in {string} column in {string} table on {string} wizard', async function (value, columnName, table, wizard) { From 0ff553496ae8e2d813008027dab0227d7a50719a Mon Sep 17 00:00:00 2001 From: adi-gini Date: Tue, 22 Jul 2025 16:11:05 +0300 Subject: [PATCH 063/228] Fix [Workflows] Incorrect message shown when workflow termination fails (#3338) --- src/components/Workflow/workflow.util.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Workflow/workflow.util.js b/src/components/Workflow/workflow.util.js index 5c63c007e7..df599c407f 100644 --- a/src/components/Workflow/workflow.util.js +++ b/src/components/Workflow/workflow.util.js @@ -287,7 +287,7 @@ export const handleTerminateWorkflow = async (job, dispatch) => { setNotification({ status: success ? 200 : 400, id: Math.random(), - message: `Workflow "${job.name}" ${success ? 'terminated successfully' : 'failed to terminate'}` + message: `Workflow "${job.name}" ${success ? 'terminated successfully' : 'was not terminated since it already reached its end state'}` }) ) } catch { @@ -295,7 +295,7 @@ export const handleTerminateWorkflow = async (job, dispatch) => { setNotification({ status: 400, id: Math.random(), - message: `Workflow "${job.name} failed to terminate` + message: `Workflow "${job.name} was not terminated since it already reached its end state` }) ) } From 21be1b49c1f0aa3846be220de0ae598b6f86e5d1 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Tue, 22 Jul 2025 16:13:08 +0300 Subject: [PATCH 064/228] Fix [Counters] data-testid for running / failed runs counter (#3339) --- .../ProjectsMonitoringCounters/ArtifactsCounters.jsx | 2 +- src/elements/ProjectsMonitoringCounters/JobsCounters.jsx | 2 +- src/elements/ProjectsMonitoringCounters/RunsCounters.jsx | 6 +++--- .../ProjectsMonitoringCounters/WorkflowsCounters.jsx | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx index 605d7515d7..338e76497a 100644 --- a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx @@ -82,7 +82,7 @@ const ArtifactsCounters = () => {
      -
      +
      {projectStore.projectsSummary.loading ? ( diff --git a/src/elements/ProjectsMonitoringCounters/JobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/JobsCounters.jsx index 8b62ec1362..c58c7b744a 100644 --- a/src/elements/ProjectsMonitoringCounters/JobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/JobsCounters.jsx @@ -52,7 +52,7 @@ const JobsCounters = () => {
      Total diff --git a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx index 51fabdfb57..1e5856feea 100644 --- a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx @@ -86,13 +86,13 @@ const RunCounter = () => { {jobStats?.counters?.map( ({ counter, className, counterClassName, label, link, statusClass, tooltip }) => { return ( - +
      -
      +
      }>
      {label}
      diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index 082c97a7b0..4e0b5e7ddd 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -102,7 +102,7 @@ const WorkflowsCounters = () => {
      From 97fb216ed942ae52210196fdc25b833b3bcb82f2 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Wed, 23 Jul 2025 13:03:49 +0300 Subject: [PATCH 065/228] Fix [Workflows] Retry option should not be available during "In Process" states (#3341) --- src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx index e9b57c2b2e..33b1c2881d 100644 --- a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx +++ b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx @@ -144,7 +144,7 @@ export const generateActionsMenu = ( ] ] } else { - const runningStates = ['running', 'pending'] + const runningStates = ['running', 'pending', 'terminating'] return [ [ From b5e6dbbce1abc6792646abb8dc1702625e040849 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Wed, 23 Jul 2025 13:05:26 +0300 Subject: [PATCH 066/228] Fix [Project monitoring] 'Pending retry' status missing in tooltip (#3337) * [Retry Job] 'Pending retry' status missing in tooltip on Project monitoring page * Change for, Progress->Process --- src/elements/ProjectJobs/projectJobs.utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elements/ProjectJobs/projectJobs.utils.js b/src/elements/ProjectJobs/projectJobs.utils.js index 5e68319bc6..69f8f1a7bc 100644 --- a/src/elements/ProjectJobs/projectJobs.utils.js +++ b/src/elements/ProjectJobs/projectJobs.utils.js @@ -28,14 +28,14 @@ export const getJobsStatistics = (projectCounter, projectName) => { return { running: { value: projectCounter.error ? 'N/A' : projectCounter.data.runs_running_count, - label: 'In Progress', + label: 'In Process', className: projectCounter.error || projectCounter.data.runs_running_count === 0 ? 'default' : 'running', status: 'running', link: `/projects/${projectName}/jobs/${MONITOR_JOBS_TAB}`, - counterTooltip: 'Aborting, Pending, Running', + counterTooltip: 'Aborting, Pending, Pending retry, Running', loading: projectCounter.loading }, failed: { From 7b0ee1d4f458decb36462b8c1d9ddeb446032a6e Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Thu, 24 Jul 2025 16:28:36 +0300 Subject: [PATCH 067/228] Impl [LLM Prompt Artifact] Change UI view for Prompt template (#3342) --- src/common/ExpandableText/ExpandableText.jsx | 83 ++++++++++++++ src/common/ExpandableText/expandableText.scss | 55 ++++++++++ .../SearchNavigator/SearchNavigator.jsx | 17 +-- .../SearchNavigator/searchNavigator.util.jsx | 20 +++- .../DetailsGenerationConfiguration.jsx | 8 +- .../detailsGenerationConfiguration.scss | 2 + .../DetailsPromptTemplate/ArgumentsTab.jsx | 15 ++- .../DetailsPromptTemplate/PromptTab.jsx | 102 ++++++++++-------- .../detailsPromptTemplate.scss | 33 +++++- src/layout/Navbar/navbar.util.jsx | 3 +- 10 files changed, 270 insertions(+), 68 deletions(-) create mode 100644 src/common/ExpandableText/ExpandableText.jsx create mode 100644 src/common/ExpandableText/expandableText.scss diff --git a/src/common/ExpandableText/ExpandableText.jsx b/src/common/ExpandableText/ExpandableText.jsx new file mode 100644 index 0000000000..493d2442cb --- /dev/null +++ b/src/common/ExpandableText/ExpandableText.jsx @@ -0,0 +1,83 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import { useState, useRef, useEffect } from 'react' +import PropTypes from 'prop-types' + +import './expandableText.scss' + +const ExpandableText = ({ children, collapsedHeight = 95, forceExpand = false }) => { + const [expanded, setExpanded] = useState(false) + const [isOverflowing, setIsOverflowing] = useState(false) + const contentRef = useRef(null) + + useEffect(() => { + if (forceExpand) { + setExpanded(forceExpand) + } + }, [forceExpand]) + + useEffect(() => { + const element = contentRef.current + + if (element) { + setIsOverflowing(element.scrollHeight > collapsedHeight + 1) + } + }, [children, collapsedHeight]) + + return ( +
      +
      + {children} +
      + {!expanded && isOverflowing && ( + <> +
      +
      + ... + +
      + + )} + {expanded && isOverflowing && ( +
      + +
      + )} +
      + ) +} + +ExpandableText.propTypes = { + children: PropTypes.node.isRequired, + collapsedHeight: PropTypes.number, + forceExpand: PropTypes.bool +} + +export default ExpandableText diff --git a/src/common/ExpandableText/expandableText.scss b/src/common/ExpandableText/expandableText.scss new file mode 100644 index 0000000000..efb3b2e6f1 --- /dev/null +++ b/src/common/ExpandableText/expandableText.scss @@ -0,0 +1,55 @@ +@use 'igz-controls/scss/colors'; + +.expandable-wrapper { + position: relative; +} + +.expandable-text { + display: flex; + transition: max-height 0.3s ease; + position: relative; + overflow: hidden; +} + +.fade-overlay { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 40px; + background: linear-gradient(to bottom, rgba(255, 255, 255, 0), #fff); + pointer-events: none; +} + +.see-more-button-overlay { + position: absolute; + bottom: 4px; + right: 0; + background: white; + padding-left: 8px; + display: flex; + align-items: center; + gap: 4px; +} + +.dots { + font-weight: bold; + color: colors.$doveGrayTwo; +} + +.see-more-button, +.see-less-button { + background: none; + border: none; + color: colors.$cornflowerBlueTwo; + font-weight: 500; + font-size: 14px; + cursor: pointer; + padding: 0; +} + +.see-less-container { + margin-top: 4px; + text-align: right; +} diff --git a/src/common/SearchNavigator/SearchNavigator.jsx b/src/common/SearchNavigator/SearchNavigator.jsx index 9af94d3597..70cef108dd 100644 --- a/src/common/SearchNavigator/SearchNavigator.jsx +++ b/src/common/SearchNavigator/SearchNavigator.jsx @@ -24,14 +24,14 @@ import classnames from 'classnames' import Search from '../Search/Search' import { RoundedIcon } from 'igz-controls/components' -import { highlightMatches } from './searchNavigator.util' +import { countMatchesInTemplate, highlightMatches } from './searchNavigator.util' import Arrow from 'igz-controls/images/arrow.svg?react' import Close from 'igz-controls/images/close.svg?react' import './searchNavigator.scss' -const SearchNavigator = ({ promptTemplate, rawPromptString, setSearchResult }) => { +const SearchNavigator = ({ promptTemplate, setSearchResult, searchOnChange = null }) => { const [matchCount, setMatchCount] = useState(0) const [activeMatchIndex, setActiveMatchIndex] = useState(0) const [matches, setMatches] = useState([]) @@ -56,16 +56,17 @@ const SearchNavigator = ({ promptTemplate, rawPromptString, setSearchResult }) = } const regex = new RegExp(`(${value})`, 'gi') - const allMatches = [...rawPromptString.matchAll(regex)] const highlighted = highlightMatches(promptTemplate, regex, 0) + const jsxMatchCount = countMatchesInTemplate(highlighted, regex) setSearchResult(highlighted) - setMatchCount(allMatches.length) - setMatches(allMatches) + setMatchCount(jsxMatchCount) + setMatches(new Array(jsxMatchCount).fill(null)) setActiveMatchIndex(0) setSearchValue(value) + searchOnChange?.() }, - [clearResults, rawPromptString, promptTemplate, setSearchResult] + [promptTemplate, setSearchResult, searchOnChange, clearResults] ) const highlightMatch = useCallback( @@ -150,8 +151,8 @@ const SearchNavigator = ({ promptTemplate, rawPromptString, setSearchResult }) = SearchNavigator.propTypes = { promptTemplate: PropTypes.array.isRequired, - rawPromptString: PropTypes.string.isRequired, - setSearchResult: PropTypes.func.isRequired + setSearchResult: PropTypes.func.isRequired, + searchOnChange: PropTypes.func } export default SearchNavigator diff --git a/src/common/SearchNavigator/searchNavigator.util.jsx b/src/common/SearchNavigator/searchNavigator.util.jsx index 2131bcaf58..9cd2912122 100644 --- a/src/common/SearchNavigator/searchNavigator.util.jsx +++ b/src/common/SearchNavigator/searchNavigator.util.jsx @@ -70,7 +70,7 @@ export function highlightMatches(template, regex, activeIndex = 0) { newChildren = children } - return React.cloneElement(element, { key: keyPrefix }, newChildren) + return React.cloneElement(element, { ...element.props, key: keyPrefix }, newChildren) } return element @@ -78,3 +78,21 @@ export function highlightMatches(template, regex, activeIndex = 0) { return template.map((el, index) => processElement(el, `root-${index}`)) } + +export function countMatchesInTemplate(template, regex) { + let count = 0 + + const traverse = node => { + if (typeof node === 'string') { + count += (node.match(regex) || []).length + } else if (Array.isArray(node)) { + node.forEach(child => traverse(child)) + } else if (React.isValidElement(node)) { + traverse(node.props.children) + } + } + + template.forEach(el => traverse(el)) + + return count +} diff --git a/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx b/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx index c05e9386fb..499277209e 100644 --- a/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx +++ b/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx @@ -23,10 +23,12 @@ import { isEmpty } from 'lodash' import NoData from '../../../common/NoData/NoData' +import './detailsGenerationConfiguration.scss' + const DetailsGenerationConfiguration = ({ selectedItem }) => { return ( -
      - {Object.entries(selectedItem.generation_configuration || {}).map(([key, value]) => { +
      + {Object.entries(selectedItem.model_configuration || {}).map(([key, value]) => { return (
      {key}
      @@ -34,7 +36,7 @@ const DetailsGenerationConfiguration = ({ selectedItem }) => {
      ) })} - {isEmpty(selectedItem.generation_configuration) && } + {isEmpty(selectedItem.model_configuration) && }
      ) } diff --git a/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss b/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss index 52cf710dfb..4a7fbf0039 100644 --- a/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss +++ b/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss @@ -2,6 +2,8 @@ @use 'igz-controls/scss/colors'; .generation-configuration-tab { + margin-top: 15px; + &__row { display: flex; padding: 10px 0; diff --git a/src/components/Details/DetailsPromptTemplate/ArgumentsTab.jsx b/src/components/Details/DetailsPromptTemplate/ArgumentsTab.jsx index 48c4447378..52667d356f 100644 --- a/src/components/Details/DetailsPromptTemplate/ArgumentsTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/ArgumentsTab.jsx @@ -24,6 +24,7 @@ import { isEmpty } from 'lodash' import ContentMenu from '../../../elements/ContentMenu/ContentMenu' import NoData from '../../../common/NoData/NoData' +import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' const ArgumentsTab = ({ handleTabChange, @@ -40,14 +41,18 @@ const ArgumentsTab = ({ {Object.values(selectedItem.prompt_legend ?? {}).map(legend => { const rowClassNames = classNames( 'arguments-tab__row', - selectedArgument.field + selectedArgument.des === legend.field + legend.des && - 'arguments-tab__row_selected' + selectedArgument.field + selectedArgument.description === + legend.field + legend.description && 'arguments-tab__row_selected' ) return ( -
      -
      {legend.field}
      -
      {legend.des}
      +
      +
      + }> + {legend.field} + +
      +
      {legend.description}
      ) })} diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx index 1a1fbf58c1..91384cc591 100644 --- a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -19,15 +19,15 @@ such restriction. */ import { useEffect, useState } from 'react' import PropTypes from 'prop-types' -import { isEmpty } from 'lodash' +import { capitalize, isEmpty } from 'lodash' -import { CopyToClipboard, Tooltip, TextTooltipTemplate } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' import ContentMenu from '../../../elements/ContentMenu/ContentMenu' import SearchNavigator from '../../../common/SearchNavigator/SearchNavigator' import { ARGUMENTS_TAB } from '../../../constants' -import Copy from 'igz-controls/images/copy-to-clipboard-icon.svg?react' +import ExpandableText from '../../../common/ExpandableText/ExpandableText' const PromptTab = ({ handleTabChange, @@ -39,47 +39,59 @@ const PromptTab = ({ }) => { const [promptTemplate, setPromptTemplate] = useState([]) const [searchResult, setSearchResult] = useState('') - const [rawPromptString, setRawPromptString] = useState('') + const [forceExpandAll, setForceExpandAll] = useState(false) useEffect(() => { - if (!isEmpty(selectedItem.prompt_string) && !isEmpty(selectedItem.prompt_legend)) { + if (Array.isArray(selectedItem.prompt_template) && !isEmpty(selectedItem.prompt_legend)) { const legendMap = { ...selectedItem.prompt_legend } - const regex = new RegExp(`\\b(${Object.keys(selectedItem.prompt_legend).join('|')})\\b`, 'g') - - const jsxContent = selectedItem.prompt_string.split(regex).map((part, index) => { - if (legendMap[part]) { - const currentArgument = selectedItem.prompt_legend[part] - - return ( - } - textShow - > - { - setSelectedArgument(currentArgument) - setSelectedTab(ARGUMENTS_TAB) - }} + const regex = new RegExp(`\\b(${Object.keys(legendMap).join('|')})\\b`, 'g') + + const jsxContent = selectedItem.prompt_template.map((item, idx) => { + const parts = item.content.split(regex).map((part, i) => { + if (legendMap[part]) { + const currentArgument = legendMap[part] + + return ( + } + textShow > - {`{${part}}`} - - - ) - } + { + setSelectedArgument(currentArgument) + setSelectedTab(ARGUMENTS_TAB) + }} + > + {`{${part}}`} + + + ) + } - return part + return part + }) + + return ( +
      +
      {capitalize(item.role)}
      +
      + {parts} +
      +
      + ) }) setPromptTemplate(jsxContent) - setRawPromptString(selectedItem.prompt_string) - } else if (!isEmpty(selectedItem.prompt_string)) { - setPromptTemplate([selectedItem.prompt_string]) - setRawPromptString(selectedItem.prompt_string) } - }, [selectedItem.prompt_string, selectedItem.prompt_legend, setSelectedArgument, setSelectedTab]) + }, [ + selectedItem.prompt_legend, + setSelectedArgument, + setSelectedTab, + forceExpandAll, + selectedItem.prompt_template + ]) return (
      @@ -87,21 +99,17 @@ const PromptTab = ({ setForceExpandAll(true)} /> - - - - Copy prompt - -
      -
      {searchResult || promptTemplate}
      +
      +
      +
      Role
      +
      Content
      +
      + {searchResult || promptTemplate} +
      ) } diff --git a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss index b3f55221ed..19eba2474e 100644 --- a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss +++ b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss @@ -11,6 +11,10 @@ background-color: white; } + &__table-header { + font-weight: bold; + } + &__template { max-height: 425px; padding: 25px 15px; @@ -65,8 +69,9 @@ } &-key { - min-width: 150px; - font-weight: 500; + width: 150px; + font-weight: bold; + padding-right: 10px; } &-value { @@ -74,4 +79,28 @@ } } } + + .prompt-tab__table { + display: flex; + flex-direction: column; + width: 100%; + margin-top: 8px; + } + + .prompt-tab__row { + display: flex; + padding: 8px 0; + border-bottom: borders.$dividerBorder; + } + + .prompt-tab__role { + flex: 0 0 100px; + padding-right: 16px; + font-weight: 500; + } + + .prompt-tab__content { + display: flex; + flex: 1; + } } \ No newline at end of file diff --git a/src/layout/Navbar/navbar.util.jsx b/src/layout/Navbar/navbar.util.jsx index 5267570fcc..0cab739398 100644 --- a/src/layout/Navbar/navbar.util.jsx +++ b/src/layout/Navbar/navbar.util.jsx @@ -82,8 +82,7 @@ export const getLinks = (projectName, isDemoMode) => { icon: , id: LLM_PROMPTS_PAGE, label: 'LLM prompts', - link: `${pathname}/${LLM_PROMPTS_PAGE}`, - hidden: !isDemoMode + link: `${pathname}/${LLM_PROMPTS_PAGE}` }, { icon: , From c16060c308e077e67edc0fcb410792775ccc17a5 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Sun, 27 Jul 2025 11:06:54 +0300 Subject: [PATCH 068/228] Fix [Projects, Project monitoring] Monitoring app issues (#3343) --- .../AlertsCounters.jsx | 22 +++++++------- .../ApplicationCounters.jsx | 29 ++++++++++--------- .../ArtifactsCounters.jsx | 12 ++++---- .../RunsCounters.jsx | 28 +++++++++--------- .../ScheduledJobsCounters.jsx | 22 +++++++------- .../WorkflowsCounters.jsx | 22 +++++++------- .../projectsMonitoringCounters.scss | 4 +-- src/utils/generateMonitoringData.js | 4 ++- 8 files changed, 74 insertions(+), 69 deletions(-) diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index fdea11e54d..c565926bfc 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -99,15 +99,15 @@ const AlertsCounters = () => { ) return ( -
      - -
      - } iconClass="stats-card__title-icon"> -
      - - {timeLabel} -
      -
      + +
      + } iconClass="stats-card__title-icon"> +
      + + {timeLabel} +
      +
      +
      { )}
      - -
      +
      +
      ) } diff --git a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx index 8faccc5a35..0d8d4525b3 100644 --- a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx @@ -74,10 +74,10 @@ const ApplicationCounter = () => { ) return ( -
      - -
      - + +
      + +
      { headerIsHidden >
      - {applicationStats?.counters?.map(({ link, counter, label, popUpClassName }) => ( -
      - - {label}: {counter} - -
      - ))} + {applicationStats?.counters?.map( + ({ link, counter, label, statusClass, popUpClassName }) => ( +
      + {' '} + + {label}: {counter} + +
      + ) + )}
      )}
      - -
      +
      +
      ) } diff --git a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx index 338e76497a..cc7b3dd2a5 100644 --- a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx @@ -77,10 +77,10 @@ const ArtifactsCounters = () => { ) return ( -
      - -
      - + +
      + +
      @@ -166,8 +166,8 @@ const ArtifactsCounters = () => { )}
      - -
      +
      + ) } diff --git a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx index 1e5856feea..f5723388c4 100644 --- a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx @@ -54,18 +54,18 @@ const RunCounter = () => { ) return ( -
      - -
      - -
      - - Past 24 hrs -
      -
      + +
      + +
      + + Past 24 hrs +
      +
      +
      { )}
      - -
      +
      +
      ) } diff --git a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx index bd5069997e..afc24fd80f 100644 --- a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx @@ -87,15 +87,15 @@ const ScheduledJobsCounters = () => { ) return ( -
      - -
      - -
      - - {timeLabel} -
      -
      + +
      + +
      + + {timeLabel} +
      +
      +
      { )}
      - -
      +
      +
      ) } diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index 4e0b5e7ddd..a7b66ecc98 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -90,15 +90,15 @@ const WorkflowsCounters = () => { ) return ( -
      - -
      - -
      - - {timeLabel} -
      -
      + +
      + +
      + + {timeLabel} +
      +
      +
      { )}
      - -
      +
      +
      ) } diff --git a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss index 344ba87303..c5eb913065 100644 --- a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss +++ b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss @@ -42,7 +42,7 @@ .stats { &__failed { - color: colors.$ceriseRed; + color: colors.$amaranth; } &__subtitle { @@ -217,7 +217,7 @@ gap: 6px; align-items: center; color: colors.$topaz; - font-size: 12px; + font-size: 14px; } } } diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index e0abf52f2c..1d934cc6a9 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -198,7 +198,9 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }, { counter: data.failed || 0, - className: classNames('stats__counter', projectName && 'stats__link'), + className: classNames('stats__counter', projectName && 'stats__link', { + stats__failed: data.failed > 0 + }), link: () => navigateToTab(projectName, MONITORING_APP_PAGE), statusClass: 'failed', label: FAILED, From 5a3d392dc2a19aae97840a19ad4fa3109724fc4d Mon Sep 17 00:00:00 2001 From: adi-gini Date: Sun, 27 Jul 2025 11:07:06 +0300 Subject: [PATCH 069/228] Fix [Workflows] Revise text of "Terminating" notification (#3344) --- src/components/Workflow/workflow.util.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/Workflow/workflow.util.js b/src/components/Workflow/workflow.util.js index df599c407f..813738bfae 100644 --- a/src/components/Workflow/workflow.util.js +++ b/src/components/Workflow/workflow.util.js @@ -263,7 +263,7 @@ export const handleTerminateWorkflow = async (job, dispatch) => { setNotification({ status: 400, id: Math.random(), - message: `Failed to start termination for workflow "${job.name}"` + message: `Workflow "${job.name} was not terminated since it already reached its end state` }) ) return @@ -287,7 +287,9 @@ export const handleTerminateWorkflow = async (job, dispatch) => { setNotification({ status: success ? 200 : 400, id: Math.random(), - message: `Workflow "${job.name}" ${success ? 'terminated successfully' : 'was not terminated since it already reached its end state'}` + message: success + ? `A request to terminate workflow "${job.name}" was issued` + : `Workflow "${job.name}" was not terminated because it already reached its end state` }) ) } catch { From 705ea97ecfabdf6cdf313c2a91a7b1f4a7b80a7a Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Sun, 27 Jul 2025 11:07:18 +0300 Subject: [PATCH 070/228] Fix [Projects] Incorrect counter data on project cards for N/A projects (#3345) --- .../ProjectStatisticsCounter/ProjectStatisticsCounter.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx index b08f10154e..eec9d4baad 100644 --- a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx +++ b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx @@ -35,7 +35,7 @@ const ProjectStatisticsCounter = ({ counterObject }) => { ) const generatedCountersContent = useMemo(() => { - if (!isNil(counterObject.value)) { + if (!isNil(counterObject.value) && isFinite(Number(counterObject.value))) { const displayValue = counterObject.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') if (Number(counterObject.value) < MAX_VISIBLE_COUNTER) { From 2b6a124835b0bdd70acfb23ff81b94c48996c72a Mon Sep 17 00:00:00 2001 From: adi-gini Date: Sun, 27 Jul 2025 11:16:31 +0300 Subject: [PATCH 071/228] Fix [Counters] runs and workflows counters are missing stats__counter class (#3346) --- .../ApplicationCounters.jsx | 6 +- .../ArtifactsCounters.jsx | 56 +++++++++++-------- src/utils/generateMonitoringData.js | 16 ++++-- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx index 0d8d4525b3..679a13fb91 100644 --- a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx @@ -97,7 +97,11 @@ const ApplicationCounter = () => { {applicationStats.counters.map(({ counter, className, label, statusClass, link }) => (
      -
      +
      {projectStore?.projectsSummary?.loading ? ( ) : ( diff --git a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx index cc7b3dd2a5..bbefbeba0e 100644 --- a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx @@ -94,50 +94,58 @@ const ArtifactsCounters = () => {
      -
      +
      Datasets
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( -
      {data?.datasets.counter?.toLocaleString()}
      - )} -
      + {projectStore.projectsSummary.loading ? ( + + ) : ( + data?.datasets.counter?.toLocaleString() + )}
      -
      +
      Documents
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( -
      - {data?.documents?.counter?.toLocaleString()} -
      - )} -
      + {projectStore.projectsSummary.loading ? ( + + ) : ( + data?.documents?.counter?.toLocaleString() + )}
      -
      +
      LLM Prompts
      {projectStore.projectsSummary.loading ? ( ) : ( -
      - {data?.llm_prompt?.counter?.toLocaleString()} -
      + data?.llm_prompt?.counter?.toLocaleString() )}
      -
      +
      Other Artifacts
      {projectStore.projectsSummary.loading ? ( ) : ( -
      {data?.files?.counter?.toLocaleString()}
      + data?.files?.counter?.toLocaleString() )}
      diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index 1d934cc6a9..c502b15fbc 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -76,7 +76,8 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }), statusClass: 'running', tooltip: 'Aborting, Pending, Pending retry, Running', - label: IN_PROCESS + label: IN_PROCESS, + counterClassName: 'stats__counter' }, { counter: data.failed || 0, @@ -85,7 +86,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { statusClass: 'failed', tooltip: 'Aborted, Error', label: FAILED, - counterClassName: classNames({ + counterClassName: classNames('stats__counter', { stats__failed: data.failed > 0 }) }, @@ -95,7 +96,8 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['completed'] }), statusClass: 'completed', tooltip: 'Completed', - label: SUCCEEDED + label: SUCCEEDED, + counterClassName: 'stats__counter' } ] } @@ -116,7 +118,8 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { className: classNames('stats__link', 'stats__line'), statusClass: 'running', tooltip: 'Running, Terminating', - label: IN_PROCESS + label: IN_PROCESS, + counterClassName: 'stats__counter' }, { counter: data.failed || 0, @@ -126,7 +129,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { statusClass: 'failed', tooltip: 'Error, Failed', label: FAILED, - counterClassName: classNames({ + counterClassName: classNames('stats__counter', { stats__failed: data.failed > 0 }) }, @@ -136,7 +139,8 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['completed'] }), statusClass: 'completed', tooltip: 'Completed', - label: SUCCEEDED + label: SUCCEEDED, + counterClassName: 'stats__counter' } ] } From 9f7e954836b23aaef803f68f7d2e9d2d9b3570cc Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:08:36 +0300 Subject: [PATCH 072/228] Impl [Monitoring app] remove page from Demo mode (#3347) --- src/common/Breadcrumbs/breadcrumbs.util.js | 2 +- src/layout/Navbar/Navbar.jsx | 6 ++---- src/layout/Navbar/navbar.util.jsx | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/common/Breadcrumbs/breadcrumbs.util.js b/src/common/Breadcrumbs/breadcrumbs.util.js index d57a222c6f..ae246f8151 100644 --- a/src/common/Breadcrumbs/breadcrumbs.util.js +++ b/src/common/Breadcrumbs/breadcrumbs.util.js @@ -57,7 +57,7 @@ export const generateMlrunScreens = (params, isDemo) => { label: 'LLM prompts', id: LLM_PROMPTS_PAGE, hidden: !isDemo }, { label: 'Artifacts', id: 'files' }, { label: 'Models', id: 'models' }, - { label: 'Monitoring app', id: MONITORING_APP_PAGE, hidden: !isDemo }, + { label: 'Monitoring app', id: MONITORING_APP_PAGE }, { label: 'Jobs and workflows', id: 'jobs' }, { label: 'ML functions', id: 'functions' }, { diff --git a/src/layout/Navbar/Navbar.jsx b/src/layout/Navbar/Navbar.jsx index db383d8b64..8451c1579a 100644 --- a/src/layout/Navbar/Navbar.jsx +++ b/src/layout/Navbar/Navbar.jsx @@ -27,7 +27,6 @@ import { RoundedIcon } from 'igz-controls/components' import { ALERTS_PAGE_PATH, NAVBAR_WIDTH_CLOSED, NAVBAR_WIDTH_OPENED } from '../../constants' import localStorageService from '../../utils/localStorageService' import { getLinks } from './navbar.util' -import { useMode } from '../../hooks/mode.hook' import Alerts from 'igz-controls/images/navbar/alerts-icon.svg?react' import PinIcon from 'igz-controls/images/pin-icon.svg?react' @@ -41,7 +40,6 @@ const Navbar = ({ projectName, setIsNavbarPinned }) => { const [isPinned, setIsPinned] = useState( localStorageService.getStorageValue('mlrunUi.navbarStatic', false) === 'true' ) - const { isDemoMode } = useMode() const navbarClasses = classNames( 'navbar', @@ -55,8 +53,8 @@ const Navbar = ({ projectName, setIsNavbarPinned }) => { } const links = useMemo(() => { - return projectName ? getLinks(projectName, isDemoMode) : [] - }, [isDemoMode, projectName]) + return projectName ? getLinks(projectName) : [] + }, [projectName]) const handlePinClick = () => { setIsPinned(prevIsPinned => { diff --git a/src/layout/Navbar/navbar.util.jsx b/src/layout/Navbar/navbar.util.jsx index 0cab739398..ea71474e0c 100644 --- a/src/layout/Navbar/navbar.util.jsx +++ b/src/layout/Navbar/navbar.util.jsx @@ -43,7 +43,7 @@ import ModelMonitoringIcon from 'igz-controls/images/navbar/model-monitoring.svg // import RTPiplinesIcon from 'igz-controls/images/timer-outline-icon.svg?react' -export const getLinks = (projectName, isDemoMode) => { +export const getLinks = projectName => { const pathname = `/projects/${projectName}` return [ @@ -100,8 +100,7 @@ export const getLinks = (projectName, isDemoMode) => { icon: , id: 'monitoring-app', label: 'Monitoring app', - link: `${pathname}/monitoring-app`, - hidden: !isDemoMode + link: `${pathname}/monitoring-app` }, { icon: , From 388145cc31d303f53742d4884a0b04e23aa2d888 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:38:04 +0300 Subject: [PATCH 073/228] Impl [LLM prompts] llm-prompt MEP will link to the llm-prompt artifact and not to the model artifact (#3349) --- .../ModelEndpoints/modelEndpoints.util.jsx | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx index 0f0e510078..debbec99cb 100644 --- a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx +++ b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx @@ -31,17 +31,22 @@ export const filtersConfig = { [LABELS_FILTER]: { label: 'Labels:', initialValue: '', isModal: true } } -const infoHeaders = [ - { label: 'UID', id: 'uid' }, - { label: 'Model class', id: 'model_class' }, - { label: 'Model artifact', id: 'model_artifact' }, - { label: 'Function URI', id: 'function_uri' }, - { label: 'Function Tag', id: 'function_tag' }, - { label: 'Feature set', id: 'monitoring_feature_set_uri' }, - { label: 'Sampling percentage', id: 'sampling_percentage' }, - { label: 'Last prediction', id: 'last_prediction' }, - { label: 'Error count', id: 'error_count' } -] +const generateInfoHeaders = model_path => { + return [ + { label: 'UID', id: 'uid' }, + { label: 'Model class', id: 'model_class' }, + { + label: model_path.includes('llm-prompts') ? 'LLM Prompt artifact' : 'Model artifact', + id: 'model_artifact' + }, + { label: 'Function URI', id: 'function_uri' }, + { label: 'Function Tag', id: 'function_tag' }, + { label: 'Feature set', id: 'monitoring_feature_set_uri' }, + { label: 'Sampling percentage', id: 'sampling_percentage' }, + { label: 'Last prediction', id: 'last_prediction' }, + { label: 'Error count', id: 'error_count' } + ] +} const detailsMenu = [ { @@ -74,7 +79,7 @@ export const generatePageData = ( hidePageActionMenu: true, details: { menu: detailsMenu, - infoHeaders, + infoHeaders: generateInfoHeaders(selectedItem?.spec?.model_path || ''), type: MODEL_ENDPOINTS_TAB, actionButton: { label: 'Resource monitoring', From a1be872b957a4446cc82c8793894dc24bcd93d99 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:42:05 +0300 Subject: [PATCH 074/228] Fix [LLM Prompt Artifact] Broken view of content when typing search (#3350) --- .../detailsPromptTemplate.scss | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss index 19eba2474e..7b4647e572 100644 --- a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss +++ b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss @@ -11,16 +11,10 @@ background-color: white; } - &__table-header { - font-weight: bold; - } - - &__template { - max-height: 425px; - padding: 25px 15px; - overflow-y: auto; - border: borders.$primaryBorder; - border-radius: 4px; + &__table { + &-header { + font-weight: bold; + } .tooltip-wrapper { display: inline; From f64d109a78283a715c993dd631c99b790c1f1b00 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:48:25 +0300 Subject: [PATCH 075/228] Fix [Projects, Monitoring container] [Cross projects]Change text on project card info (#3348) --- src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx | 2 +- src/elements/ProjectsMonitoringCounters/RunsCounters.jsx | 2 +- src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index c565926bfc..eec9293a9e 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -39,7 +39,7 @@ const AlertsCounters = () => { const { projectName: paramProjectName } = useParams() const navigate = useNavigate() const projectStore = useSelector(store => store.projectStore) - const timeLabel = paramProjectName ? '24 hrs' : 'Past 24 hrs' + const timeLabel = paramProjectName ? '24 hrs' : 'Last 24 hrs' const handleOpenPopUp = () => { const isHidden = !detailsRef.current?.offsetParent diff --git a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx index f5723388c4..4be9f0f323 100644 --- a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx @@ -62,7 +62,7 @@ const RunCounter = () => { >
      - Past 24 hrs + Last 24 hrs
      diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index a7b66ecc98..75fe82f93e 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -37,7 +37,7 @@ const WorkflowsCounters = () => { const { projectName } = useParams() const navigate = useNavigate() const projectStore = useSelector(store => store.projectStore) - const timeLabel = projectName ? '24 hrs' : 'Past 24 hrs' + const timeLabel = projectName ? '24 hrs' : 'Last 24 hrs' const handleOpenPopUp = () => { const isHidden = !detailsRef.current?.offsetParent From 31f7727b4ca10686c10da33c93e4a201d61edc44 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:19:49 +0300 Subject: [PATCH 076/228] Fix [LLM Prompt artifact] model name field not listed in llm prompt overview page (#3351) --- src/components/Details/details.util.js | 9 ++++++++- src/components/LLMPrompts/llmPrompts.util.jsx | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/Details/details.util.js b/src/components/Details/details.util.js index 97b6069e8e..5591d83c83 100644 --- a/src/components/Details/details.util.js +++ b/src/components/Details/details.util.js @@ -42,7 +42,6 @@ import { TAG_LATEST } from '../../constants' import { generateLinkPath, parseUri } from '../../utils' -import { isArtifactTagUnique } from '../../utils/artifacts.util' import { getFunctionImage } from '../FunctionsPage/functions.util' import { openPopUp } from 'igz-controls/utils/common.util' import { formatDatetime } from 'igz-controls/utils/datetime.util' @@ -123,6 +122,14 @@ export const generateArtifactsContent = ( db_key: { value: selectedItem.db_key }, + model_artifact: { + value: !isEmpty(selectedItem?.parent_uri) ? parseUri(selectedItem.parent_uri).key : '', + shouldPopUp: !isEmpty(selectedItem?.parent_uri), + handleClick: () => + openPopUp(ArtifactPopUp, { + artifactData: parseUri(selectedItem?.parent_uri) + }) + }, tag: { value: selectedItem.tag ?? '', editModeEnabled: true, diff --git a/src/components/LLMPrompts/llmPrompts.util.jsx b/src/components/LLMPrompts/llmPrompts.util.jsx index e671b4e839..756126a505 100644 --- a/src/components/LLMPrompts/llmPrompts.util.jsx +++ b/src/components/LLMPrompts/llmPrompts.util.jsx @@ -70,6 +70,7 @@ export const detailsMenu = [ export const infoHeaders = [ { label: 'Key', id: 'db_key' }, + { label: 'Model name', id: 'model_artifact' }, { label: 'Hash', id: 'hash', From 3fb7083e7cb911ca1ae2a65c20bf29c8351a61d0 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:35:25 +0300 Subject: [PATCH 077/228] Fix [Models] Disable delete for models with children (#3352) --- src/components/ModelsPage/Models/models.util.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/ModelsPage/Models/models.util.jsx b/src/components/ModelsPage/Models/models.util.jsx index 32dd82ebab..a6298c0671 100644 --- a/src/components/ModelsPage/Models/models.util.jsx +++ b/src/components/ModelsPage/Models/models.util.jsx @@ -277,6 +277,7 @@ export const generateActionsMenu = ( icon: , className: 'danger', hidden: isDetailsPopUp, + disabled: modelMin?.has_children, onClick: () => openDeleteConfirmPopUp( 'Delete model?', @@ -300,6 +301,7 @@ export const generateActionsMenu = ( label: 'Delete all versions', icon: , hidden: isAllVersions || isDetailsPopUp, + disabled: modelMin?.has_children, className: 'danger', onClick: () => openDeleteConfirmPopUp( From 0a4370ac7cc340a62b2e7af72fe24d1864d235da Mon Sep 17 00:00:00 2001 From: adi-gini Date: Tue, 29 Jul 2025 11:07:57 +0300 Subject: [PATCH 078/228] Tests [Counters] Add mock for project monitoring counters (#3353) --- tests/mockServer/data/summary.json | 80 ++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/tests/mockServer/data/summary.json b/tests/mockServer/data/summary.json index 2f9212a4f7..1f73884801 100644 --- a/tests/mockServer/data/summary.json +++ b/tests/mockServer/data/summary.json @@ -20,7 +20,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 3, + "llm_prompts_count": 1 }, { "name": "cat-vs-dog-classification", @@ -42,7 +45,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 1, + "documents_count": 4, + "llm_prompts_count": 2 }, { "name": "churn-project-admin", @@ -61,7 +67,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 4, + "documents_count": 2, + "llm_prompts_count": 3 }, { "name": "default", @@ -83,7 +92,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "fraud-demo2-admin", @@ -105,7 +117,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 3, + "documents_count": 2, + "llm_prompts_count": 2 }, { "name": "fsdemo-admin", @@ -143,7 +158,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "hedi-proj", @@ -162,7 +180,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "mask-detection", @@ -181,7 +202,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "model-deployment-pipeline-admin", @@ -200,7 +224,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "moreofthesame", @@ -219,7 +246,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "network-operations", @@ -238,7 +268,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "network-operations-admin", @@ -257,7 +290,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "sk-project-admin", @@ -276,7 +312,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "stocks", @@ -295,7 +334,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "stocks-admin", @@ -313,7 +355,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 }, { "name": "test-test", @@ -331,7 +376,10 @@ "distinct_scheduled_pipelines_pending_count": 0, "pipelines_completed_recent_count": 0, "pipelines_failed_recent_count": 0, - "pipelines_running_count": 0 + "pipelines_running_count": 0, + "datasets_count": 2, + "documents_count": 1, + "llm_prompts_count": 4 } ] } From a7295d03bc30b5e668ab9cc5f5f2c0ee764e2570 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 29 Jul 2025 13:55:51 +0300 Subject: [PATCH 079/228] Fix [Retry Job] The retries counter (1 out 1 ) present on job, that has not retry setting (#3354) --- src/components/Jobs/jobs.util.js | 4 ++-- src/utils/createJobsContent.js | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/Jobs/jobs.util.js b/src/components/Jobs/jobs.util.js index a975b43fb4..7f2fa458ef 100644 --- a/src/components/Jobs/jobs.util.js +++ b/src/components/Jobs/jobs.util.js @@ -74,8 +74,8 @@ export const getInfoHeaders = (isSpark, selectedJob) => { { label: 'Log level', id: LOG_LEVEL_ID }, { label: 'Output path', id: 'outputPath' }, { label: 'Total iterations', id: 'iterations' }, - { label: 'Retry count', id: 'retryCountWithInitialAttempt' }, - { label: 'Maximum retries', id: 'maxRetriesWithInitialAttempt' } + { label: 'Attempt count', id: 'retryCountWithInitialAttempt', tip: 'Number of attempts to run kubejobs' }, + { label: 'Maximum attempts', id: 'maxRetriesWithInitialAttempt', tip: 'Maximin number of attempts to run kubejobs' } ] if (isSpark) { diff --git a/src/utils/createJobsContent.js b/src/utils/createJobsContent.js index 57da151c3d..29beb8626c 100644 --- a/src/utils/createJobsContent.js +++ b/src/utils/createJobsContent.js @@ -164,11 +164,12 @@ export const createJobsMonitorTabContent = (jobs, jobName, isStagingMode) => { type: 'hidden' }, { - headerId: 'retries', - headerLabel: 'Retries', - id: `retries.${identifierUnique}`, + headerId: 'attempts', + headerLabel: 'Attempts', + id: `attempts.${identifierUnique}`, value: `${job.retryCountWithInitialAttempt} out of ${job.maxRetriesWithInitialAttempt}`, className: 'table-cell-1', + tip: 'Number of attempts to run kubejobs' } ] } @@ -565,11 +566,12 @@ export const createJobsMonitoringContent = (jobs, jobName, isStagingMode) => { type: 'hidden' }, { - headerId: 'retries', - headerLabel: 'Retries', - id: `retries.${identifierUnique}`, + headerId: 'attempts', + headerLabel: 'Attempts', + id: `attempts.${identifierUnique}`, value: `${job.retryCountWithInitialAttempt} out of ${job.maxRetriesWithInitialAttempt}`, className: 'table-cell-1', + tip: 'Number of attempts to run kubejobs' } ] } From 54d049238e179e4f04cec83ee209111b49828a5f Mon Sep 17 00:00:00 2001 From: adi-gini Date: Tue, 29 Jul 2025 17:22:08 +0300 Subject: [PATCH 080/228] Fix [Terminate wf] The terminate workflow option is not available for Project user with admin and editor permissions (#3356) --- src/api/projects-iguazio-api.js | 9 +++++++++ src/components/Workflow/workflow.util.js | 24 +++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/api/projects-iguazio-api.js b/src/api/projects-iguazio-api.js index 614475ace2..d0ab2eabab 100644 --- a/src/api/projects-iguazio-api.js +++ b/src/api/projects-iguazio-api.js @@ -49,6 +49,15 @@ const projectsIguazioApi = { } }) }, + getProjectWorkflowsUpdateAuthorization: project => { + return iguazioHttpClient.get(`/projects/__name__/${project}/authorization`, { + params: { + action: 'update', + sub_resource: 'authorization/workflow' + } + }) + }, + updateProjectMembers: data => { return iguazioHttpClient.post('/async_transactions', data) }, diff --git a/src/components/Workflow/workflow.util.js b/src/components/Workflow/workflow.util.js index 813738bfae..3d8871b6ac 100644 --- a/src/components/Workflow/workflow.util.js +++ b/src/components/Workflow/workflow.util.js @@ -315,7 +315,12 @@ export const fetchMissingProjectsPermissions = async (projectNames, currentMap, await projectsIguazioApi.getProjectOwnerVisibility(projectName) return [projectName, true] } catch { - return [projectName, false] + try { + await projectsIguazioApi.getProjectWorkflowsUpdateAuthorization(projectName) + return [projectName, true] + } catch { + return [projectName, false] + } } }) ) @@ -328,10 +333,15 @@ export const fetchMissingProjectsPermissions = async (projectNames, currentMap, export const fetchMissingProjectPermission = async (projectName, currentMap, dispatch) => { if (projectName in currentMap) return - try { - await projectsIguazioApi.getProjectOwnerVisibility(projectName) - dispatch(setAccessibleProjectsMap({ [projectName]: true })) - } catch { - dispatch(setAccessibleProjectsMap({ [projectName]: false })) - } + const hasPermission = await projectsIguazioApi + .getProjectOwnerVisibility(projectName) + .then(() => true) + .catch(() => + projectsIguazioApi + .getProjectWorkflowsUpdateAuthorization(projectName) + .then(() => true) + .catch(() => false) + ) + + dispatch(setAccessibleProjectsMap({ [projectName]: hasPermission })) } From 610b01c18c429ae51c27500f015c1f7c152d3496 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Tue, 29 Jul 2025 22:31:50 +0300 Subject: [PATCH 081/228] Fix [Schedule] Scheduled tab doesn't display all jobs (#3358) --- src/components/JobWizard/JobWizard.jsx | 4 ++-- .../Jobs/ScheduledJobs/ScheduledJobs.jsx | 16 ++++++++++------ .../ScheduledMonitoring.jsx | 18 ++++++++++-------- src/elements/JobsTable/JobsTable.jsx | 9 +++++---- .../ScheduledJobsTable/ScheduledJobsTable.jsx | 16 ++++++++++++++-- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/components/JobWizard/JobWizard.jsx b/src/components/JobWizard/JobWizard.jsx index 5caccb1994..ed7b3dc436 100644 --- a/src/components/JobWizard/JobWizard.jsx +++ b/src/components/JobWizard/JobWizard.jsx @@ -327,7 +327,7 @@ const JobWizard = ({ setShowSchedule(state => !state) } resolveModal() - onSuccessRequest && onSuccessRequest(true) + onSuccessRequest && onSuccessRequest(true, isSchedule) dispatch( setNotification({ status: 200, @@ -337,7 +337,7 @@ const JobWizard = ({ ) }) .then(() => { - return navigate( + navigate( `/projects/${params.projectName}/jobs/${isSchedule ? SCHEDULE_TAB : MONITOR_JOBS_TAB}` ) }) diff --git a/src/components/Jobs/ScheduledJobs/ScheduledJobs.jsx b/src/components/Jobs/ScheduledJobs/ScheduledJobs.jsx index 1364052fe8..bc46676375 100644 --- a/src/components/Jobs/ScheduledJobs/ScheduledJobs.jsx +++ b/src/components/Jobs/ScheduledJobs/ScheduledJobs.jsx @@ -30,7 +30,7 @@ import { setFilters } from '../../../reducers/filtersReducer' import { useFiltersFromSearchParams } from '../../../hooks/useFiltersFromSearchParams.hook' const ScheduledJobs = () => { - const [dataIsLoaded, setDataIsLoaded] = useState(false) + const [, setDataIsLoaded] = useState(false) const { abortControllerRef, initialTabData, @@ -48,11 +48,15 @@ const ScheduledJobs = () => { ) useEffect(() => { - if (!dataIsLoaded) { - refreshJobs(filters) - setDataIsLoaded(true) - } - }, [dataIsLoaded, filters, refreshJobs]) + setDataIsLoaded((prevState) => { + if (!prevState) { + refreshJobs(filters) + return true + } else { + return prevState + } + }) + }, [filters, refreshJobs]) useEffect(() => { const abortControllerRefCurrent = abortControllerRef.current diff --git a/src/components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoring.jsx b/src/components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoring.jsx index b3d01ad66e..e681bea2a0 100644 --- a/src/components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoring.jsx +++ b/src/components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoring.jsx @@ -18,7 +18,6 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import React, { useEffect, useState } from 'react' -import { useDispatch } from 'react-redux' import ScheduledJobsTable from '../../../elements/ScheduledJobsTable/ScheduledJobsTable' import { ProjectJobsMonitoringContext } from '../ProjectsJobsMonitoring' @@ -28,8 +27,7 @@ import { JOBS_MONITORING_SCHEDULED_TAB } from '../../../constants' import { useFiltersFromSearchParams } from '../../../hooks/useFiltersFromSearchParams.hook' const ScheduledMonitoring = () => { - const [dataIsLoaded, setDataIsLoaded] = useState(false) - const dispatch = useDispatch() + const [, setDataIsLoaded] = useState(false) const { initialTabData, requestErrorMessage, @@ -45,11 +43,15 @@ const ScheduledMonitoring = () => { ) useEffect(() => { - if (!dataIsLoaded) { - refreshScheduled(filters) - setDataIsLoaded(true) - } - }, [dataIsLoaded, dispatch, refreshScheduled, filters]) + setDataIsLoaded((prevState) => { + if (!prevState) { + refreshScheduled(filters) + return true + } else { + return prevState + } + }) + }, [filters, refreshScheduled]) useEffect(() => { return () => { diff --git a/src/elements/JobsTable/JobsTable.jsx b/src/elements/JobsTable/JobsTable.jsx index fc7c58bc91..5cb692818b 100644 --- a/src/elements/JobsTable/JobsTable.jsx +++ b/src/elements/JobsTable/JobsTable.jsx @@ -284,9 +284,11 @@ const JobsTable = React.forwardRef( ]) const refreshJobsWithFilters = useCallback( - useInitialFilter => { - const initialJobFilters = getInitialFiltersByConfig(filtersConfig) - refreshJobs(useInitialFilter ? initialJobFilters : filters, { forceFetchJobs: true }) + (useInitialFilter, isSchedule) => { + if (!isSchedule) { + const initialJobFilters = getInitialFiltersByConfig(filtersConfig) + refreshJobs(useInitialFilter ? initialJobFilters : filters, { forceFetchJobs: true }) + } }, [filters, refreshJobs, filtersConfig] ) @@ -320,7 +322,6 @@ const JobsTable = React.forwardRef( editableItem?.rerun_object, jobWizardIsOpened, jobWizardMode, - filters, params, refreshJobsWithFilters, setEditableItem, diff --git a/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx b/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx index 635f876c86..9766799346 100644 --- a/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx +++ b/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx @@ -33,6 +33,7 @@ import { FILTERS_CONFIG } from '../../types' import { JOB_KIND_WORKFLOW, JOBS_PAGE, PANEL_EDIT_MODE, SCHEDULE_TAB } from '../../constants' import { fetchFunctionTemplate } from '../../reducers/functionReducer' import { getErrorMsg, openPopUp, getScssVariableValue } from 'igz-controls/utils/common.util' +import { getInitialFiltersByConfig } from '../../hooks/useFiltersFromSearchParams.hook' import { getJobFunctionData } from '../../components/Jobs/jobs.util' import { getNoDataMessage } from '../../utils/getNoDataMessage' import { handleRunScheduledJob, removeScheduledJob } from '../../reducers/jobReducer' @@ -89,6 +90,17 @@ const ScheduledJobsTable = ({ return createTableContent() }, [createTableContent]) + + const refreshJobsWithFilters = useCallback( + (useInitialFilter, isSchedule) => { + if (isSchedule) { + const initialJobFilters = getInitialFiltersByConfig(filtersConfig) + refreshJobs(useInitialFilter ? initialJobFilters : filters) + } + }, + [refreshJobs, filtersConfig, filters] + ) + const toggleConvertedYaml = useCallback( data => { return dispatch(toggleYaml(data)) @@ -238,7 +250,7 @@ const ScheduledJobsTable = ({ defaultData: jobWizardMode === PANEL_EDIT_MODE ? editableItem?.scheduled_object : {}, mode: jobWizardMode, wizardTitle: jobWizardMode === PANEL_EDIT_MODE ? 'Edit job' : undefined, - onSuccessRequest: () => refreshJobs(filters) + onSuccessRequest: refreshJobsWithFilters }) setJobWizardIsOpened(true) @@ -246,9 +258,9 @@ const ScheduledJobsTable = ({ }, [ editableItem?.project, editableItem?.scheduled_object, - filters, jobWizardIsOpened, jobWizardMode, + refreshJobsWithFilters, params, refreshJobs, setEditableItem, From a38e4283d691571780f44bc7a8b4b1e9e0de59fe Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Tue, 29 Jul 2025 21:33:13 +0200 Subject: [PATCH 082/228] Tests [QA] v1.10.0-rc9 (#3357) --- tests/features/MLFunction.feature | 2 +- tests/features/alerts.feature | 6 +- tests/features/artifacts.feature | 5 +- tests/features/common-tools/common-consts.js | 38 +- tests/features/common/actions/table.action.js | 15 + .../page-objects/commonPagesHeader.po.js | 5 - .../common/page-objects/project.po.js | 189 +++--- tests/features/featureStore.feature | 17 +- tests/features/projectMonitoring.feature | 548 ++++++++++++++---- tests/features/step-definitions/steps.js | 10 +- .../features/step-definitions/table.steps.js | 10 + 11 files changed, 632 insertions(+), 213 deletions(-) diff --git a/tests/features/MLFunction.feature b/tests/features/MLFunction.feature index b374c1d777..24213c32f7 100644 --- a/tests/features/MLFunction.feature +++ b/tests/features/MLFunction.feature @@ -1112,7 +1112,7 @@ Feature: ML Functions Then click on "Cross_Cancel_Button" element on "View_YAML" wizard Then click on cell with row index 8 in "expand_btn" column in "Functions_Table" table on "ML_Functions" wizard And wait load page - Then select "View YAML" option in action menu on "ML_Functions" wizard in "Functions_Table" table at row with "Nov 23, 2021, 11:31:51 AM" value in "name" column + Then select "View YAML" option in action menu on "ML_Functions" wizard in "Functions_Table" table at row with "Nov 23, 2021, 10:31:51 AM" value in "name" column Then verify if "View_YAML" popup dialog appears Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard diff --git a/tests/features/alerts.feature b/tests/features/alerts.feature index ef2e0508f9..62ffa2eb23 100644 --- a/tests/features/alerts.feature +++ b/tests/features/alerts.feature @@ -285,17 +285,17 @@ Feature: Alerts Page When select "Job" option in "Entity_Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page - Then type value "alertd0beb8b0b8" to "Search_By_Name_Filter_Input" field on "Alerts" wizard + Then type value "alertd478b0739b" to "Search_By_Name_Filter_Input" field on "Alerts" wizard Then click on "Refresh_Button" element on "Alerts" wizard And wait load page - Then value in "alertName" column with "text" in "Alerts_Table" on "Alerts" wizard should contains "alertd0beb8b0b8" + Then value in "alertName" column with "text" in "Alerts_Table" on "Alerts" wizard should contains "alertd478b0739b" And wait load page Then verify "Alerts_Table" element visibility on "Alerts" wizard Then value in "entityType" column with "tooltip" in "Alerts_Table" on "Alerts" wizard should contains "Job" When click on cell with row index 1 in "alertName" column in "Alerts_Table" table on "Alerts" wizard And wait load page Then verify "Header" element visibility on "Alerts_Jobs_Info_Pane" wizard - Then "Header" element on "Alerts_Jobs_Info_Pane" should contains "alertd0beb8b0b8" value + Then "Header" element on "Alerts_Jobs_Info_Pane" should contains "alertd478b0739b" value Then verify "Overview_General_Headers" element visibility on "Alerts_Jobs_Info_Pane" wizard Then verify "Overview_General_Headers" on "Alerts_Jobs_Info_Pane" wizard should contains "Alerts_Jobs_Info_Pane"."Overview_General_Headers_PerProject" Then verify "Job_Detail_PopUp_Link" element visibility on "Alerts_Jobs_Info_Pane" wizard diff --git a/tests/features/artifacts.feature b/tests/features/artifacts.feature index cf16832b42..8953e5f775 100644 --- a/tests/features/artifacts.feature +++ b/tests/features/artifacts.feature @@ -471,7 +471,6 @@ Feature: Artifacts Page When select "V3IO" option in "Path_Scheme_Combobox" combobox on "Target_Path" accordion on "Register_File_Popup" wizard When type value "target/path" to "Path_Scheme_Combobox" field on "Target_Path" on "Register_File_Popup" wizard Then click on "Register_Button" element on "Register_File_Popup" wizard - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Overwrite artifact?" value When click on "Overwrite_Button" element on "Confirm_Popup" wizard @@ -513,7 +512,7 @@ Feature: Artifacts Page Then verify "Title" element visibility on "Modal_Transition_Popup" wizard Then "Title" element on "Modal_Transition_Popup" should contains "survival-curves_km-timelines" value Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard - Then "Data_Status" element on "Modal_Transition_Popup" should contains "Aug 29, 2021, 10:54:15 PM" value + Then "Data_Status" element on "Modal_Transition_Popup" should contains "Aug 29, 2021, 07:54:15 PM" value Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard Then click on "Refresh_Button" element on "Modal_Transition_Popup" wizard And wait load page @@ -823,7 +822,6 @@ Feature: Artifacts Page When select "V3IO" option in "Path_Scheme_Combobox" combobox on "Target_Path" accordion on "Register_File_Popup" wizard When type value "target/path" to "Path_Scheme_Combobox" field on "Target_Path" on "Register_File_Popup" wizard Then click on "Register_Button" element on "Register_File_Popup" wizard - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Overwrite artifact?" value When click on "Overwrite_Button" element on "Confirm_Popup" wizard @@ -875,7 +873,6 @@ Feature: Artifacts Page When select "V3IO" option in "Path_Scheme_Combobox" combobox on "Target_Path" accordion on "Register_File_Popup" wizard When type value "target/path" to "Path_Scheme_Combobox" field on "Target_Path" on "Register_File_Popup" wizard Then click on "Register_Button" element on "Register_File_Popup" wizard - And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Overwrite artifact?" value When click on "Overwrite_Button" element on "Confirm_Popup" wizard diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index 2b18e7e480..8b5d2fc62a 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -19,19 +19,24 @@ such restriction. */ export default { Project: { - Create_New_Options: [ - 'Batch run', - 'Feature set', + Quick_Actions_Options: [ + 'Register dataset', 'Register artifact', - 'Register dataset' + 'Batch run', + 'Train model', + 'Batch inference', + 'Create real-time function' ], - Create_New_Options_Demo: [ + Quick_Actions_Options_Demo: [ + 'Register dataset', + 'Register artifact', 'Batch run', + 'Train model', + 'Batch inference', + 'Create real-time function', 'ML function', 'Feature set', - 'Register artifact', - 'Register model', - 'Register dataset' + 'Register model' ], Online_Status: 'online', Data_Collection_Description: @@ -385,7 +390,7 @@ export default { Back_Button: 'Back', Expand_All_Button: 'Expand all', In_Process_Jobs: 'Aborting, Pending, Pending retry, Running', - Running_Tip: 'Running', + Running_Tip: 'Running, Terminating', Failed_Tip: 'Failed', Failed_Jobs: 'Aborted, Error', Failed_Worflows: 'Error, Failed', @@ -535,7 +540,8 @@ export default { Commited_Offset: 'Total number of messages handled by the app', Endpoints_Tip: 'Model endpoints processed by the monitoring app during the selected time frame', Metrics_Tip: 'This table displays the values of the last metrics captured by the monitoring application. If there are metrics for more than one model endpoint at the same time, the table displays only one of those.', - Shards_Partitions_Status_Tip: 'This table displays the current status of each shard' + Shards_Partitions_Status_Tip: 'This table displays the current status of each shard', + Runs_Statistic_Section_Title_Tip: 'Number of Job runs, clicking on the counters navigates to jobs screen.' }, Descriptions: { Archive_Project: @@ -595,7 +601,9 @@ export default { 'Labels:', 'Log level:', 'Output path:', - 'Total iterations:' + 'Total iterations:', + 'Retry count:', + 'Maximum retries:' ] }, Jobs_Monitor_Tab: { @@ -641,7 +649,7 @@ export default { 'Pending', 'Pending retry' ], - Workflows_Status_Filter_Options: ['All', 'Error', 'Failed', 'Running', 'Completed'], + Workflows_Status_Filter_Options: ['All', 'Error', 'Failed', 'Running', 'Completed', 'Terminating'], Jobs_Type_Filter_Options: [ 'All', 'Job', @@ -741,12 +749,18 @@ export default { /No data matches the filter: "Created at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, Common_Message_Jobs_Monitoring_Status: /No data matches the filter: "Created at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Status: (.+?)"/, + Common_Message_Monitoring_Workflow: + /No data matches the filter: "Created at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}"/, + Common_Message_Monitoring_Workflow_Status: + /No data matches the filter: "Status: (.+?)"/, Common_Message_Jobs_Monitoring_Type: /No data matches the filter: "Start time: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Type: (.+?)"/, Common_Message_Monitor_Jobs: /No data matches the filter: "Start time: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}"/, Common_Message_Jobs_Monitoring_Scheduled: /No data matches the filter: "Scheduled at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, + Common_Message_Scheduled_Type: + /No data matches the filter: "Type: (.+?)"/, Common_Message: 'No data matches the filter: "Version Tag: latest, Name: ccccc"', Common_Message_Feature: 'No data matches the filter: "Version Tag: latest"', Common_Message_Feature_Vector_Tab: diff --git a/tests/features/common/actions/table.action.js b/tests/features/common/actions/table.action.js index 05d0003159..0a8a1a1cf9 100644 --- a/tests/features/common/actions/table.action.js +++ b/tests/features/common/actions/table.action.js @@ -45,6 +45,12 @@ export const getColumnValues = async (driver, table, columnName) => { }) } +export const getHeaderColumnValue = async (driver, table, columnName) => { + const element = await driver.findElement(table.headerSorters[columnName]) + + return await element.getText() +} + export const getTableRows = async (driver, table) => { const arr = await driver .findElements(table.tableColumns[table.tableCulumnNames[0]]) @@ -60,6 +66,15 @@ export const isContainsValueInColumn = async (driver, table, columnName, value) expect(arr.includes(value)).equal(true, `Column values [${arr}] is not equal with "${value}" `) } +export const isContainsValueInHeaderColumn = async (driver, table, columnName, value) => { + const actualValue = await getHeaderColumnValue(driver, table, columnName) + + expect(actualValue.includes(value)).equal( + true, + `Header column "${columnName}" value "${actualValue}" does not include "${value}"` + ) +} + export const isNotContainsValueInColumn = async (driver, table, columnName, value) => { const arr = await getColumnValues(driver, table, columnName) expect(arr.includes(value)).equal(false) diff --git a/tests/features/common/page-objects/commonPagesHeader.po.js b/tests/features/common/page-objects/commonPagesHeader.po.js index 3a4c3b0aef..44a63cd5f1 100644 --- a/tests/features/common/page-objects/commonPagesHeader.po.js +++ b/tests/features/common/page-objects/commonPagesHeader.po.js @@ -90,11 +90,6 @@ export default { Alerts_Button: By.css('[data-testid="nav-link-alerts"] .nav-link__label'), Alerts_Icon: By.css('[data-testid="nav-link-alerts"] svg'), General_Info_Quick_Panel: By.css('.ml-app .navbar .navbar__body'), - Project_Quick_Actions_Instance: By.css('.project-details__details .link'), - Quick_actions_Active: By.css('#quick-actions'), - Project_Monitoring_First_Instance: By.css('.project-details__details .link'), - Project_Monitoring_Second_Instance: By.css('.project-overview-card:nth-of-type(3) .link:nth-of-type(4)'), - Project_Monitoring_Active: By.css('#monitor'), Step_1_Button: By.css('.modal .modal__content .modal__body .wizard-steps .btn:nth-of-type(1)'), Step_1_Button_text: By.css('.modal .modal__content .modal__body .wizard-steps .btn:nth-of-type(1) .data-ellipsis span'), Step_2_Button: By.css('.modal .modal__content .modal__body .wizard-steps .btn:nth-of-type(2)'), diff --git a/tests/features/common/page-objects/project.po.js b/tests/features/common/page-objects/project.po.js index 8c91a06d9b..4235e6a469 100644 --- a/tests/features/common/page-objects/project.po.js +++ b/tests/features/common/page-objects/project.po.js @@ -29,11 +29,11 @@ import { } from '../../common-tools/common-tools' import inputGroup from '../components/input-group.component' -const createNewObject = dropdownComponent( +const quickActionsObject = dropdownComponent( generateDropdownGroup( '.main-info__toolbar .create-new-menu', '.select__header', - false, + '[data-testid="select-body"] [data-testid="select-option"] .tooltip-wrapper', false ) ) @@ -46,11 +46,22 @@ const actionMenuStructure = { } } -const projectDashboardRealtimeFunctionsTable = { - root: '.main-info__statistics-section .d-flex:nth-of-type(2) .project-data-card', +const realtimeFunctionsNuclioTable = { + root: '.d-flex:nth-of-type(2) .project-data-card', header: { - root: '.project-data-card__table-header', + root: '.project-data-card__header', sorters: { + title: '.project-data-card__header-text a', + running_counter_number: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-value .tooltip-wrapper', + running_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label span', + running_counter_icon: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label i', + failed_counter_number: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-value .tooltip-wrapper', + failed_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-label span', + failed_counter_icon: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-label i', + api_gateways_counter_number: '.project-data-card__statistics-item:nth-of-type(3) .project-data-card__statistics-value .tooltip-wrapper', + api_gateways_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(3) .project-data-card__statistics-label span', + consumer_groups_counter_number: '.project-data-card__statistics-item:nth-of-type(4) .project-data-card__statistics-value .tooltip-wrapper', + consumer_groups_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(4) .project-data-card__statistics-label span', name: '.table-header__item:nth-of-type(1) .data-ellipsis', status: '.table-header__item:nth-of-type(2) .data-ellipsis' } @@ -66,12 +77,23 @@ const projectDashboardRealtimeFunctionsTable = { } } } - -const projectJobsAndWorkflows = { - root: '.main-info__statistics-section:nth-of-type(4) .d-flex:nth-of-type(1) .project-data-card', + +const runsTable = { + root: '.d-flex:nth-of-type(1) .project-data-card', header: { - root: '.project-data-card__table-header', + root: '.project-data-card__header', sorters: { + title: '.project-data-card__header-text span a', + time_period: '.project-data-card__header-info span', + in_process_counter_number: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-value', + in_process_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label span', + in_process_counter_icon: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label i', + failed_counter_number: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-value', + failed_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-label span', + failed_counter_icon: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-label i', + succeeded_counter_number: '.project-data-card__statistics-item:nth-of-type(3) .project-data-card__statistics-value', + succeeded_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(3) .project-data-card__statistics-label span', + succeeded_counter_icon: '.project-data-card__statistics-item:nth-of-type(3) .project-data-card__statistics-label i', name: '.table-header__item:nth-of-type(1) .data-ellipsis', type: '.table-header__item:nth-of-type(2) .data-ellipsis', status: '.table-header__item:nth-of-type(3) .data-ellipsis', @@ -95,36 +117,6 @@ const projectJobsAndWorkflows = { } } -const generalInfoJobsCardStat = { - root: '.main-info__statistics-section .project-data-card:nth-of-type(1)', - header: {}, - body: { - root: '.project-data-card__statistics', - row: { - root: '.project-data-card__statistics-item', - fields: { - name: '.project-data-card__statistics-label', - value: '.project-data-card__statistics-value' - } - } - } -} - -const generalInfoRealTimeFunctionsCardStat = { - root: '.main-info__statistics-section .d-flex:nth-of-type(2) .project-data-card', - header: {}, - body: { - root: '.project-data-card__statistics', - row: { - root: '.project-data-card__statistics-item', - fields: { - name: '.project-data-card__statistics-label', - value: '.project-data-card__statistics-value' - } - } - } -} - const DataCollectionActionsTable = { root: '.project-overview .project-overview__content .project-overview-card:nth-of-type(1) .project-overview-actions:nth-of-type(1)', @@ -284,42 +276,89 @@ const shardLagsTable = { export default { project: { - Create_New: createNewObject, - Refresh_Button: By.css('.main-info__toolbar [data-testid="refresh"]'), - Dashboard_Realtime_Functions_Table: commonTable( - projectDashboardRealtimeFunctionsTable - ), - Jobs_And_Workflows: commonTable(projectJobsAndWorkflows), - Recent_text: By.css('.project-data-card .project-data-card__recent-text'), - See_All_Jobs_Link: By.css( - '.project-data-card:nth-of-type(1) .project-data-card__see-all-link' - ), - Mono_Values_Cards: By.css('.main-info__statistics-section:nth-of-type(3)'), - Model_Stats_Title: By.css('.main-info__statistics-section_left .stats-card:nth-of-type(1) .stats-card__row:nth-of-type(1) .stats-card__title span'), - Model_Stats_Tip: By.css('.stats-card:nth-of-type(1) .stats-card__row:nth-of-type(1) [data-testid="tip"]'), - Model_Stats_Counter: By.css('.stats-card:nth-of-type(1) .stats-card__row:nth-of-type(2) [data-testid="monitoring-Models"] .stats__counter'), - FeatureSets_Stats_Title: By.css('.main-info__statistics-section_left .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(1) .stats-card__title span'), - FeatureSets_Stats_Tip: By.css('.stats-card:nth-of-type(2) .stats-card__row:nth-of-type(1) [data-testid="tip"]'), - FeatureSets_Stats_Counter: By.css('.stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="monitoring-Feature sets"] .stats__counter'), - Artifacts_Stats_Title: By.css('.main-info__statistics-section_left .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(1) .stats-card__title span'), - Artifacts_Stats_Tip: By.css('.stats-card:nth-of-type(3) .stats-card__row:nth-of-type(1) [data-testid="tip"]'), - Artifacts_Stats_Counter: By.css('.stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="monitoring-Artifacts"] .stats__counter'), - ConsumerGroups_Stats_Title: By.css('.main-info__statistics-section:nth-of-type(4) .d-flex:nth-of-type(2) .project-data-card__header .project-data-card__statistics-item:nth-of-type(4) .project-data-card__statistics-label'), - ConsumerGroups_Stats_Counter: By.css('.main-info__statistics-section:nth-of-type(4) .d-flex:nth-of-type(2) .project-data-card__header .project-data-card__statistics-item:nth-of-type(4) .project-data-card__statistics-value'), - Alerts_Stats_Title: By.css('.main-info__statistics-section_right .stats-card__title span'), - Alerts_Stats_Total_Title: By.css('.main-info__statistics-section_right [data-testid="alerts_total_counter"] span'), - Alerts_Stats_Total_Number: By.css('.main-info__statistics-section_right [data-testid="alerts_total_counter"] .stats__counter'), - Alerts_Stats_Endpoint_Number: By.css('.main-info__statistics-section_right [data-testid="alerts_endpoint_counter"] .stats__counter'), - Alerts_Stats_Endpoint_Title: By.css('.main-info__statistics-section_right [data-testid="alerts_endpoint_counter"] .stats__subtitle'), - Alerts_Stats_Jobs_Number: By.css('.main-info__statistics-section_right [data-testid="alerts_jobs_counter"] .stats__counter'), - Alerts_Stats_Jobs_Title: By.css('.main-info__statistics-section_right [data-testid="alerts_jobs_counter"] .stats__subtitle'), - Alerts_Stats_Application_Number: By.css('.main-info__statistics-section_right [data-testid="alerts_application_counter stats__counter-large"] .stats__counter'), - Alerts_Stats_Application_Title: By.css('.main-info__statistics-section_right [data-testid="alerts_application_counter stats__counter-large"] .stats__subtitle'), - Jobs_Info_Card_Statistics: commonTable(generalInfoJobsCardStat), - Real_Time_Functions_Card_Statistics: commonTable( - generalInfoRealTimeFunctionsCardStat - ), - Add_Source_URL_Label: By.css('.general-info .general-info__source') + Project_Name: By.css('.main-info .project-details__header'), + Created_Details: By.css('.project-details__details-label:nth-of-type(1)'), + Owner_Details: By.css('.project-details__details-label:nth-of-type(2)'), + Info_Baner: By.css('.main-info__toolbar .main-info__toolbar-banner'), + Quick_Actions: quickActionsObject, + Refresh_Button: By.css('[data-testid="refresh"]'), + Mono_Values_Cards: By.css('.projects-monitoring-container .projects-monitoring-stats'), + Artifacts_Stats_Container: { + Artifacts_Stats_Title: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__title .tooltip-wrapper'), + Artifacts_Stats_Counter: By.css('.projects-monitoring-stats > div:nth-child(1) [data-testid="data_total_counter"] .stats__counter'), + Datasets_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(1) h6'), + Datasets_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(1) .stats__counter'), + Documents_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(2) h6'), + Documents_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(1) .stats__details .stats-card__row:nth-of-type(2) .stats__counter'), + LLM_Prompts_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(3) h6'), + LLM_Prompts_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(3) .stats__counter'), + Other_Artifacts_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(4) h6'), + Other_Artifacts_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(4) .stats__counter') + }, + Workflows_Stats_Container: { + Workflows_Stats_Title: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__title .tooltip-wrapper'), + Filtering_Time_Period: By.css('.projects-monitoring-stats > div:nth-child(2) .project-card__info span'), + Workflows_Stats_Counter: By.css('.projects-monitoring-stats > div:nth-child(2) [data-testid="scheduled_total_counter"] .stats__counter'), + In_Process_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(1) h6'), + In_Process_Counter_Status_Icon: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(1) i.state-running'), + In_Process_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(2) .stats__details .stats-card__row:nth-of-type(1) div:nth-child(2)'), + Failed_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(2) h6'), + Failed_Counter_Status_Icon: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(2) i.state-failed'), + Failed_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(2) div:nth-child(2)'), + Succeeded_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(3) h6'), + Succeeded_Counter_Status_Icon: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(3) i.state-completed'), + Succeeded_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(3) div:nth-child(2)') + }, + Scheduled_Stats_Container: { + Scheduled_Stats_Title: By.css('.projects-monitoring-stats > div:nth-child(3) .stats-card__title .tooltip-wrapper'), + Filtering_Time_Period: By.css('.projects-monitoring-stats > div:nth-child(3) .project-card__info span'), + Scheduled_Stats_Counter: By.css('.projects-monitoring-stats > div:nth-child(3) [data-testid="scheduled_total_counter"] .stats__counter'), + Jobs_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(3) .stats-card__row:nth-of-type(1) h6'), + Jobs_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(3) .stats__details .stats-card__row:nth-of-type(1) div:nth-child(2)'), + Workflows_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(3) .stats-card__row:nth-of-type(2) h6'), + Workflows_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(3) .stats-card__row:nth-of-type(2) div:nth-child(2)') + }, + Models_Stats_Container: { + Models_Stats_Title: By.css('.card__small-container > div.stats-card.monitoring-stats .stats-card__title .tooltip-wrapper'), + Model_Stats_Counter: By.css('.projects-monitoring-stats [data-testid="models_total_counter"] .stats__counter') + }, + Monitoring_App_Stats_Container: { + Monitoring_App_Stats_Title: By.css('.projects-monitoring-stats .application-card .stats-card__title .tooltip-wrapper'), + Monitoring_App_Succeeded_Stats_Counter: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(1) .stats__counter'), + Monitoring_App_Succeeded_Counter_Subtitle: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(1) .stats__label'), + Monitoring_App_Succeeded_Counter_Status_Icon: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(1) .stats__label .state-completed'), + Monitoring_App_Failed_Stats_Counter: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(2) .stats__counter'), + Monitoring_App_Failed_Counter_Subtitle: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(2) .stats__label'), + Monitoring_App_Failed_Counter_Status_Icon: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(2) .stats__label .state-failed') + }, + Alerts_Stats_Container: { + Alerts_Stats_Title: By.css('.projects-monitoring-stats > div:nth-child(5) .stats-card__title .tooltip-wrapper'), + Alerts_Stats_Title_Icon: By.css('.projects-monitoring-stats > div:nth-child(5) .stats-card__title-icon'), + Filtering_Time_Period: By.css('.projects-monitoring-stats > div:nth-child(5) .project-card__info span'), + Alerts_Stats_Counter: By.css('.projects-monitoring-stats > div:nth-child(5) [data-testid="alerts_total_counter"]'), + Alerts_Stats_Endpoint_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(5) .stats-card__row:nth-of-type(1) h6'), + Alerts_Stats_Endpoint_Counter: By.css('.projects-monitoring-stats > div:nth-child(5) .stats__details .stats-card__row:nth-of-type(1) div:nth-child(2)'), + Alerts_Stats_Jobs_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(5) .stats-card__row:nth-of-type(2) h6'), + Alerts_Stats_Jobs_Counter: By.css('.projects-monitoring-stats > div:nth-child(5) .stats-card__row:nth-of-type(2) div:nth-child(2)'), + Alerts_Stats_Application_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(5) .stats-card__row:nth-of-type(3) .stats__subtitle'), + Alerts_Stats_Application_Counter: By.css('.projects-monitoring-stats > div:nth-child(5) .stats-card__row:nth-of-type(3) div:nth-child(2)') + }, + Runs_Statistic_Table: commonTable(runsTable), + Runs_Statistic_Section_Container: { + Runs_Statistic_Section_Title_Tip: By.css('.d-flex:nth-of-type(1) [data-testid="tip"]'), + In_Process_Counter_Subtitle: By.css('.d-flex:nth-of-type(1) .project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label span'), + Failed_Counter_Subtitle: By.css('.d-flex:nth-of-type(1) .project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-label span'), + Succeeded_Counter_Subtitle: By.css('.d-flex:nth-of-type(1) .project-data-card__statistics-item:nth-of-type(3) .project-data-card__statistics-label span'), + Recent_Text: By.css('.d-flex:nth-of-type(1) .project-data-card .project-data-card__recent-text span'), + Recent_Text_Sm: By.css('.d-flex:nth-of-type(1) .project-data-card .project-data-card__recent-text .text-sm'), + All_Jobs_Link: By.css('.d-flex:nth-of-type(1) .project-data-card__see-all-link') + }, + Realtime_Functions_Nuclio_Table: commonTable(realtimeFunctionsNuclioTable), + Realtime_Functions_Nuclio_Statistic_Section: { + ConsumerGroups_Stats_Counter: By.css('.d-flex:nth-of-type(2) .project-data-card__header .project-data-card__statistics-item:nth-of-type(4) .project-data-card__statistics-value'), + Recent_Text: By.css('.d-flex:nth-of-type(2) .project-data-card__recent-text span'), + All_Realtime_Functions_Link: By.css('.d-flex:nth-of-type(2) .project-data-card__see-all-link') + } }, demoProject: { Header_Name_Label: labelComponent( diff --git a/tests/features/featureStore.feature b/tests/features/featureStore.feature index 61d354f342..e1f6e9927d 100644 --- a/tests/features/featureStore.feature +++ b/tests/features/featureStore.feature @@ -8,9 +8,9 @@ Feature: Feature Store Page Scenario: MLFS001 - Check all mandatory components on Feature Store tab Given open url And wait load page - And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "fraud-demo2-admin" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify breadcrumbs "project" label should be equal "default" value + Then verify breadcrumbs "project" label should be equal "fraud-demo2-admin" value And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Feature store" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard @@ -53,9 +53,9 @@ Feature: Feature Store Page Scenario: MLFS002 - Check all mandatory components on Features tab Given open url And wait load page - And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "fraud-demo2-admin" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify breadcrumbs "project" label should be equal "default" value + Then verify breadcrumbs "project" label should be equal "fraud-demo2-admin" value And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Feature store" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard @@ -101,9 +101,9 @@ Feature: Feature Store Page Scenario: MLFS003 - Check all mandatory components on Feature Vectors tab Given open url And wait load page - And click on row root with value "fsdemo-admin" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "fraud-demo2-admin" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify breadcrumbs "project" label should be equal "fsdemo-admin" value + Then verify breadcrumbs "project" label should be equal "fraud-demo2-admin" value And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Feature store" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard @@ -127,6 +127,8 @@ Feature: Feature Store Page Then verify "Clear_Button" element on "FilterBy_Popup" wizard is disabled Then click on "Table_FilterBy_Button" element on "Feature_Store_Feature_Sets_Tab" wizard Then verify "Table_Refresh_Button" element visibility on "Feature_Store_Features_Vectors_Tab" wizard + Then select "project" with "fsdemo-admin" value in breadcrumbs menu + And wait load page Then verify "Feature_Vectors_Table" element visibility on "Feature_Store_Features_Vectors_Tab" wizard @MLFS @@ -381,7 +383,6 @@ Feature: Feature Store Page @passive @inProgress @smoke - # Moved analyses tabs to Demo mode in `1.8.0` ML-9059 Scenario: MLFS011 - Check all mandatory components in Item infopane on Analysis tab table Given open url And wait load page @@ -397,7 +398,7 @@ Feature: Feature Store Page Then select "Analysis" tab in "Info_Pane_Tab_Selector" on "Feature_Sets_Info_Pane" wizard Then verify "Analysis" tab is active in "Info_Pane_Tab_Selector" on "Analysis_Info_Pane" wizard Then verify "Feature Sets" tab is active in "Feature_Store_Tab_Selector" on "Feature_Store_Feature_Sets_Tab" wizard - Then verify "Info_Pane_Tab_Selector" on "Analysis_Info_Pane" wizard should contains "Feature_Sets_Info_Pane"."Tab_List_Demo" + Then verify "Info_Pane_Tab_Selector" on "Analysis_Info_Pane" wizard should contains "Feature_Sets_Info_Pane"."Tab_List" Then verify "Info_Pane_Tab_Selector" element visibility on "Analysis_Info_Pane" wizard Then verify "Header" element visibility on "Analysis_Info_Pane" wizard Then verify "Updated" element visibility on "Analysis_Info_Pane" wizard diff --git a/tests/features/projectMonitoring.feature b/tests/features/projectMonitoring.feature index b3f8307a5c..ed783387ca 100644 --- a/tests/features/projectMonitoring.feature +++ b/tests/features/projectMonitoring.feature @@ -5,49 +5,171 @@ Feature: Project Monitoring Page @MLPM @passive @smoke - Scenario: MLPM002 - Check all mandatory components + Scenario: MLPM002 - Check components on the header details and the project monitoring container Given open url And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page Then verify breadcrumbs "project" label should be equal "default" value - Then verify "Create_New" element visibility on "Project" wizard + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify "Project_Name" element visibility on "Project" wizard + Then "Project_Name" element on "Project" should contains "default" value + Then verify "Created_Details" element visibility on "Project" wizard + Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 15:21:14 PM" value + Then verify "Owner_Details" element visibility on "Project" wizard + Then "Owner_Details" element on "Project" should contains "Owner: igz_nobody" value + Then verify "Info_Baner" element visibility on "Project" wizard + Then "Info_Baner" element on "Project" should contains "Counters use a caching mechanism, and are not auto-refreshed." value + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options" Then verify "Refresh_Button" element visibility on "Project" wizard - Then verify "Dashboard_Realtime_Functions_Table" element visibility on "Project" wizard - Then verify "Jobs_And_Workflows" element visibility on "Project" wizard + Then verify "Refresh_Button" element on "Project" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" Then verify "Mono_Values_Cards" element visibility on "Project" wizard - Then verify "Model_Stats_Title" element visibility on "Project" wizard - Then "Model_Stats_Title" element on "Project" should contains "Models" value - Then verify "Model_Stats_Tip" element visibility on "Project" wizard - Then verify "Model_Stats_Tip" element on "Project" wizard should display hover hint "Label_Hint"."Model_Stats_Tip" - Then verify "Model_Stats_Counter" element visibility on "Project" wizard - Then verify "FeatureSets_Stats_Title" element visibility on "Project" wizard - Then verify "FeatureSets_Stats_Tip" element visibility on "Project" wizard - Then verify "FeatureSets_Stats_Tip" element on "Project" wizard should display hover hint "Label_Hint"."FeatureSets_Stats_Tip" - Then verify "FeatureSets_Stats_Counter" element visibility on "Project" wizard - Then verify "Artifacts_Stats_Title" element visibility on "Project" wizard - Then verify "Artifacts_Stats_Tip" element visibility on "Project" wizard - Then verify "Artifacts_Stats_Tip" element on "Project" wizard should display hover hint "Label_Hint"."Artifacts_Stats_Tip" - Then verify "Artifacts_Stats_Counter" element visibility on "Project" wizard - Then verify "Alerts_Stats_Title" element visibility on "Project" wizard - Then "Alerts_Stats_Title" element on "Project" should contains "Alerts" value - Then verify "Alerts_Stats_Total_Title" element visibility on "Project" wizard - Then "Alerts_Stats_Total_Title" element on "Project" should contains "Total" value - Then verify "Alerts_Stats_Total_Number" element visibility on "Project" wizard - Then verify "Alerts_Stats_Endpoint_Title" element visibility on "Project" wizard - Then "Alerts_Stats_Endpoint_Title" element on "Project" should contains "Endpoint" value - Then verify "Alerts_Stats_Endpoint_Number" element visibility on "Project" wizard - Then verify "Alerts_Stats_Jobs_Title" element visibility on "Project" wizard - Then "Alerts_Stats_Jobs_Title" element on "Project" should contains "Jobs" value - Then verify "Alerts_Stats_Jobs_Number" element visibility on "Project" wizard - Then verify "Alerts_Stats_Application_Title" element visibility on "Project" wizard - Then "Alerts_Stats_Application_Title" element on "Project" should contains "Application" value - Then verify "Alerts_Stats_Application_Number" element visibility on "Project" wizard - Then verify "ConsumerGroups_Stats_Title" element visibility on "Project" wizard - Then "ConsumerGroups_Stats_Title" element on "Project" should contains "Consumer groups" value - Then verify "ConsumerGroups_Stats_Counter" element visibility on "Project" wizard - Then verify "Jobs_Info_Card_Statistics" element visibility on "Project" wizard - Then verify "Real_Time_Functions_Card_Statistics" element visibility on "Project" wizard + Then verify "Artifacts_Stats_Title" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then "Artifacts_Stats_Title" element in "Artifacts_Stats_Container" on "Project" should contains "Artifacts" value + Then verify "Artifacts_Stats_Counter" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then verify "Datasets_Counter_Subtitle" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then "Datasets_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "Datasets" value + Then verify "Datasets_Counter_Number" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then verify "Documents_Counter_Subtitle" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then "Documents_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "Documents" value + Then verify "Documents_Counter_Number" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then verify "LLM_Prompts_Counter_Subtitle" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then "LLM_Prompts_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "LLM Prompts" value + Then verify "LLM_Prompts_Counter_Number" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then verify "Other_Artifacts_Counter_Subtitle" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then "Other_Artifacts_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "Other Artifacts" value + Then verify "Other_Artifacts_Counter_Number" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then verify "Workflows_Stats_Title" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then "Workflows_Stats_Title" element in "Workflows_Stats_Container" on "Project" should contains "Workflows" value + Then verify "Filtering_Time_Period" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then "Filtering_Time_Period" element in "Workflows_Stats_Container" on "Project" should contains "24 hrs" value + Then verify "Workflows_Stats_Counter" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then verify "In_Process_Counter_Subtitle" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then "In_Process_Counter_Subtitle" element in "Workflows_Stats_Container" on "Project" should contains "In Process" value + Then verify "In_Process_Counter_Status_Icon" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then verify "In_Process_Counter_Status_Icon" element in "Workflows_Stats_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" + Then verify "In_Process_Counter_Number" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then verify "Failed_Counter_Subtitle" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then "Failed_Counter_Subtitle" element in "Workflows_Stats_Container" on "Project" should contains "Failed" value + Then verify "Failed_Counter_Status_Icon" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then verify "Failed_Counter_Status_Icon" element in "Workflows_Stats_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."Failed_Worflows" + Then verify "Failed_Counter_Number" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then verify "Succeeded_Counter_Subtitle" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then "Succeeded_Counter_Subtitle" element in "Workflows_Stats_Container" on "Project" should contains "Succeeded" value + Then verify "Succeeded_Counter_Status_Icon" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then verify "In_Process_Counter_Status_Icon" element in "Workflows_Stats_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" + Then verify "Succeeded_Counter_Status_Icon" element in "Workflows_Stats_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."Succeeded" + Then verify "Succeeded_Counter_Number" element visibility in "Workflows_Stats_Container" on "Project" wizard + Then verify "Scheduled_Stats_Title" element visibility in "Scheduled_Stats_Container" on "Project" wizard + Then "Scheduled_Stats_Title" element in "Scheduled_Stats_Container" on "Project" should contains "Scheduled" value + Then verify "Filtering_Time_Period" element visibility in "Scheduled_Stats_Container" on "Project" wizard + Then "Filtering_Time_Period" element in "Scheduled_Stats_Container" on "Project" should contains "24 hrs" value + Then verify "Scheduled_Stats_Counter" element visibility in "Scheduled_Stats_Container" on "Project" wizard + Then verify "Jobs_Counter_Subtitle" element visibility in "Scheduled_Stats_Container" on "Project" wizard + Then "Jobs_Counter_Subtitle" element in "Scheduled_Stats_Container" on "Project" should contains "Jobs" value + Then verify "Jobs_Counter_Number" element visibility in "Scheduled_Stats_Container" on "Project" wizard + Then verify "Workflows_Counter_Subtitle" element visibility in "Scheduled_Stats_Container" on "Project" wizard + Then "Workflows_Counter_Subtitle" element in "Scheduled_Stats_Container" on "Project" should contains "Workflows" value + Then verify "Workflows_Counter_Number" element visibility in "Scheduled_Stats_Container" on "Project" wizard + Then verify "Models_Stats_Title" element visibility in "Models_Stats_Container" on "Project" wizard + Then "Models_Stats_Title" element in "Models_Stats_Container" on "Project" should contains "Models" value + Then verify "Model_Stats_Counter" element visibility in "Models_Stats_Container" on "Project" wizard + Then verify "Monitoring_App_Stats_Title" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then "Monitoring_App_Stats_Title" element in "Monitoring_App_Stats_Container" on "Project" should contains "Monitoring App" value + Then verify "Monitoring_App_Succeeded_Stats_Counter" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then verify "Monitoring_App_Succeeded_Counter_Subtitle" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then "Monitoring_App_Succeeded_Counter_Subtitle" element in "Monitoring_App_Stats_Container" on "Project" should contains "Succeeded" value + Then verify "Monitoring_App_Succeeded_Counter_Status_Icon" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then verify "Monitoring_App_Failed_Stats_Counter" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then verify "Monitoring_App_Failed_Counter_Subtitle" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then "Monitoring_App_Failed_Counter_Subtitle" element in "Monitoring_App_Stats_Container" on "Project" should contains "Failed" value + Then verify "Monitoring_App_Failed_Counter_Status_Icon" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then verify "Alerts_Stats_Title" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then "Alerts_Stats_Title" element in "Alerts_Stats_Container" on "Project" should contains "Alerts" value + Then verify "Alerts_Stats_Title_Icon" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then verify "Filtering_Time_Period" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then "Filtering_Time_Period" element in "Alerts_Stats_Container" on "Project" should contains "24 hrs" value + Then verify "Alerts_Stats_Counter" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then verify "Alerts_Stats_Endpoint_Subtitle" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then "Alerts_Stats_Endpoint_Subtitle" element in "Alerts_Stats_Container" on "Project" should contains "Endpoint" value + Then verify "Alerts_Stats_Endpoint_Counter" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then verify "Alerts_Stats_Jobs_Subtitle" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then "Alerts_Stats_Jobs_Subtitle" element in "Alerts_Stats_Container" on "Project" should contains "Jobs" value + Then verify "Alerts_Stats_Jobs_Counter" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then verify "Alerts_Stats_Application_Subtitle" element visibility in "Alerts_Stats_Container" on "Project" wizard + Then "Alerts_Stats_Application_Subtitle" element in "Alerts_Stats_Container" on "Project" should contains "Application" value + Then verify "Alerts_Stats_Application_Counter" element visibility in "Alerts_Stats_Container" on "Project" wizard + + @MLPM + @passive + @smoke + Scenario: MLPM023 - Check components on on the header details and the statistics section + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "project" label should be equal "default" value + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify "Project_Name" element visibility on "Project" wizard + Then "Project_Name" element on "Project" should contains "default" value + Then verify "Created_Details" element visibility on "Project" wizard + Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 15:21:14 PM" value + Then verify "Owner_Details" element visibility on "Project" wizard + Then "Owner_Details" element on "Project" should contains "Owner: igz_nobody" value + Then verify "Info_Baner" element visibility on "Project" wizard + Then "Info_Baner" element on "Project" should contains "Counters use a caching mechanism, and are not auto-refreshed." value + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options" + Then verify "Refresh_Button" element visibility on "Project" wizard + Then verify "Refresh_Button" element on "Project" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + Then verify "Runs_Statistic_Table" element visibility on "Project" wizard + Then verify visibility of header column "title" in "Runs_Statistic_Table" table on "Project" wizard + Then check "Runs" header value in "title" column in "Runs_Statistic_Table" table on "Project" wizard + Then verify "Runs_Statistic_Section_Title_Tip" element visibility in "Runs_Statistic_Section_Container" on "Project" wizard + Then verify "Runs_Statistic_Section_Title_Tip" element in "Runs_Statistic_Section_Container" on "Project" wizard should display hover hint "Label_Hint"."Runs_Statistic_Section_Title_Tip" + Then verify visibility of header column "time_period" in "Runs_Statistic_Table" table on "Project" wizard + Then check "Last 24 hrs" header value in "time_period" column in "Runs_Statistic_Table" table on "Project" wizard + Then verify visibility of header column "in_process_counter_number" in "Runs_Statistic_Table" table on "Project" wizard + Then verify visibility of header column "in_process_counter_subtitle" in "Runs_Statistic_Table" table on "Project" wizard + Then check "In Progress" header value in "in_process_counter_subtitle" column in "Runs_Statistic_Table" table on "Project" wizard + Then verify visibility of header column "in_process_counter_icon" in "Runs_Statistic_Table" table on "Project" wizard + Then verify "In_Process_Counter_Subtitle" element in "Runs_Statistic_Section_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" + Then verify visibility of header column "failed_counter_number" in "Runs_Statistic_Table" table on "Project" wizard + Then verify visibility of header column "failed_counter_subtitle" in "Runs_Statistic_Table" table on "Project" wizard + Then check "Failed" header value in "failed_counter_subtitle" column in "Runs_Statistic_Table" table on "Project" wizard + Then verify visibility of header column "failed_counter_icon" in "Runs_Statistic_Table" table on "Project" wizard + Then verify "Failed_Counter_Subtitle" element in "Runs_Statistic_Section_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."Failed_Jobs" + Then verify visibility of header column "succeeded_counter_number" in "Runs_Statistic_Table" table on "Project" wizard + Then verify visibility of header column "succeeded_counter_subtitle" in "Runs_Statistic_Table" table on "Project" wizard + Then check "Succeeded" header value in "succeeded_counter_subtitle" column in "Runs_Statistic_Table" table on "Project" wizard + Then verify visibility of header column "succeeded_counter_icon" in "Runs_Statistic_Table" table on "Project" wizard + Then verify "Succeeded_Counter_Subtitle" element in "Runs_Statistic_Section_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."Succeeded" + Then verify "Recent_Text" element visibility in "Runs_Statistic_Section_Container" on "Project" wizard + Then "Recent_Text" element in "Runs_Statistic_Section_Container" on "Project" should contains "Recent jobs" value + Then "Recent_Text_Sm" element in "Runs_Statistic_Section_Container" on "Project" should contains "(last 7 days)" value + Then check "erann-test" value in "name" column in "Runs_Statistic_Table" table on "Project" wizard + When scroll to the element with "erann-test" value in "name" column in "Runs_Statistic_Table" table on "Project" wizard + And wait load page + Then verify "All_Jobs_Link" element visibility in "Runs_Statistic_Section_Container" on "Project" wizard + Then "All_Jobs_Link" element in "Runs_Statistic_Section_Container" on "Project" should contains "All jobs" value + Then verify "Realtime_Functions_Nuclio_Table" element visibility on "Project" wizard + Then verify visibility of header column "title" in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then check "Real-time functions (Nuclio)" header value in "title" column in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then verify visibility of header column "running_counter_number" in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then check "Running" header value in "running_counter_subtitle" column in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then verify visibility of header column "running_counter_icon" in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then verify visibility of header column "failed_counter_number" in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then check "Failed" header value in "failed_counter_subtitle" column in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then verify visibility of header column "failed_counter_icon" in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then verify visibility of header column "api_gateways_counter_number" in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then check "API gateways" header value in "api_gateways_counter_subtitle" column in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then verify visibility of header column "consumer_groups_counter_number" in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then check "Consumer groups" header value in "consumer_groups_counter_subtitle" column in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then "Recent_Text" element in "Realtime_Functions_Nuclio_Statistic_Section" on "Project" should contains "Recent real-time functions" value + Then check "cat-vs-dog-classification-tf2-serving" value in "name" column in "Realtime_Functions_Nuclio_Table" table on "Project" wizard + Then verify "All_Realtime_Functions_Link" element visibility in "Realtime_Functions_Nuclio_Statistic_Section" on "Project" wizard + Then "All_Realtime_Functions_Link" element in "Realtime_Functions_Nuclio_Statistic_Section" on "Project" should contains "All real-time functions" value When hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard Then verify "General_Info_Quick_Links" element visibility on "commonPagesHeader" wizard @@ -69,7 +191,6 @@ Feature: Project Monitoring Page Then verify "Pin_Quick_Link_Button" element visibility on "commonPagesHeader" wizard Then verify "General_Info_Quick_Panel" element visibility on "commonPagesHeader" wizard Then verify "Project_Monitoring_Button" element visibility on "commonPagesHeader" wizard - Then verify "Quick_actions_Button" element visibility on "commonPagesHeader" wizard Then verify "Feature_Store_Button" element visibility on "commonPagesHeader" wizard Then verify "Datasets_Button" element visibility on "commonPagesHeader" wizard Then verify "Documents_Button" element visibility on "commonPagesHeader" wizard @@ -88,8 +209,6 @@ Feature: Project Monitoring Page Then verify "General_Info_Quick_Panel" element visibility on "commonPagesHeader" wizard Then verify "Project_Monitoring_Button" element invisibility on "commonPagesHeader" wizard Then verify "Project_Monitoring_Icon" element visibility on "commonPagesHeader" wizard - Then verify "Quick_actions_Button" element invisibility on "commonPagesHeader" wizard - Then verify "Quick_actions_Icon" element visibility on "commonPagesHeader" wizard Then verify "Feature_Store_Button" element invisibility on "commonPagesHeader" wizard Then verify "Feature_Store_Icon" element visibility on "commonPagesHeader" wizard Then verify "Datasets_Button" element invisibility on "commonPagesHeader" wizard @@ -144,16 +263,6 @@ Feature: Project Monitoring Page And select "Secrets" tab in "Project_Settings_Tab_Selector" on "Project_Settings_General_Tab" wizard And wait load page Then "Navigation_Bar" on "commonPagesHeader" wizard should be "pinned" - #check navigation between pages Project monitoring and Quick-actions due to instance links - Then click on "Project_Monitoring_Button" element on "commonPagesHeader" wizard - Then click on "Project_Quick_Actions_Instance" element on "commonPagesHeader" wizard - Then verify "Quick_actions_Active" not input element on "commonPagesHeader" wizard is active - Then click on "Project_Monitoring_First_Instance" element on "commonPagesHeader" wizard - Then verify "Project_Monitoring_Active" not input element on "commonPagesHeader" wizard is active - Then click on "Project_Quick_Actions_Instance" element on "commonPagesHeader" wizard - Then verify "Quick_actions_Active" not input element on "commonPagesHeader" wizard is active - Then click on "Project_Monitoring_Second_Instance" element on "commonPagesHeader" wizard - Then verify "Project_Monitoring_Active" not input element on "commonPagesHeader" wizard is active #check visibility of menu buttons in demo mode When turn on demo mode with query params "false" And wait load page @@ -184,9 +293,9 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify "Create_New" element visibility on "Project" wizard - Then verify "Create_New" dropdown element on "Project" wizard should contains "Project"."Create_New_Options" - Then select "Register artifact" option in "Create_New" dropdown on "Project" wizard + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options" + Then select "Register artifact" option in "Quick_Actions" dropdown on "Project" wizard Then "Title" element on "Register_File_Popup" should contains "Register Artifact" value Then "Form_Text" component on "Register_File_Popup" should contains "Register_Artifact"."Form_Text" Then "Form_Subtext" component on "Register_File_Popup" should contains "Register_Artifact"."Form_Subtext" @@ -237,9 +346,9 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify "Create_New" element visibility on "Project" wizard - Then verify "Create_New" dropdown element on "Project" wizard should contains "Project"."Create_New_Options_Demo" - Then select "Register model" option in "Create_New" dropdown on "Project" wizard + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options_Demo" + Then select "Register model" option in "Quick_Actions" dropdown on "Project" wizard Then "Title" element on "Register_Model_Popup" should contains "Register Model" value Then verify "Cross_Cancel_Button" element visibility on "Register_Model_Popup" wizard Then verify "New_File_Name_Input" element visibility on "Register_Model_Popup" wizard @@ -281,9 +390,9 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify "Create_New" element visibility on "Project" wizard - Then verify "Create_New" dropdown element on "Project" wizard should contains "Project"."Create_New_Options" - Then select "Register dataset" option in "Create_New" dropdown on "Project" wizard + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options" + Then select "Register dataset" option in "Quick_Actions" dropdown on "Project" wizard Then "Title" element on "Register_Dataset" should contains "Register Dataset" value Then "Form_Text" component on "Register_Dataset" should contains "Register_Dataset"."Form_Text" Then "Form_Subtext" component on "Register_Dataset" should contains "Register_Dataset"."Form_Subtext" @@ -326,9 +435,9 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify "Create_New" element visibility on "Project" wizard - Then verify "Create_New" dropdown element on "Project" wizard should contains "Project"."Create_New_Options" - Then select "Batch run" option in "Create_New" dropdown on "Project" wizard + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options" + Then select "Batch run" option in "Quick_Actions" dropdown on "Project" wizard And wait load page Then verify "Title" element visibility on "Modal_Wizard_Form" wizard Then "Title" element on "Modal_Wizard_Form" should contains "Batch Run" value @@ -419,13 +528,15 @@ Feature: Project Monitoring Page Scenario: MLPM008 - Check all mandatory components on Create ML Function - Job runtime Given open url And wait load page + When turn on demo mode with query params "false" + And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify "Create_New" element visibility on "Project" wizard - Then verify "Create_New" dropdown element on "Project" wizard should contains "Project"."Create_New_Options" + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options_Demo" When turn on demo mode with query params "false" And wait load page - Then select "ML function" option in "Create_New" dropdown on "Project" wizard + Then select "ML function" option in "Quick_Actions" dropdown on "Project" wizard Then "Title" element on "Create_ML_Function_Popup" should contains "Create New Function" value And verify "Cross_Cancel_Button" element visibility on "Create_ML_Function_Popup" wizard Then verify "New_Function_Name_Input" element visibility on "Create_ML_Function_Popup" wizard @@ -480,13 +591,15 @@ Feature: Project Monitoring Page Scenario: MLPM009 - Check all mandatory components on Create ML Function - Serving runtime Given open url And wait load page + When turn on demo mode with query params "false" + And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify "Create_New" element visibility on "Project" wizard - Then verify "Create_New" dropdown element on "Project" wizard should contains "Project"."Create_New_Options" + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options_Demo" When turn on demo mode with query params "false" And wait load page - Then select "ML function" option in "Create_New" dropdown on "Project" wizard + Then select "ML function" option in "Quick_Actions" dropdown on "Project" wizard Then "Title" element on "Create_ML_Function_Popup" should contains "Create New Function" value And verify "Cross_Cancel_Button" element visibility on "Create_ML_Function_Popup" wizard Then verify "New_Function_Name_Input" element visibility on "Create_ML_Function_Popup" wizard @@ -550,11 +663,13 @@ Feature: Project Monitoring Page Scenario: MLPM010 - Check all mandatory components on Create New Feature Set Given open url And wait load page + When turn on demo mode with query params "false" + And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then verify "Create_New" element visibility on "Project" wizard - Then verify "Create_New" dropdown element on "Project" wizard should contains "Project"."Create_New_Options" - Then select "Feature set" option in "Create_New" dropdown on "Project" wizard + Then verify "Quick_Actions" element visibility on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options_Demo" + Then select "Feature set" option in "Quick_Actions" dropdown on "Project" wizard Then verify "Cross_Close_Button" element visibility on "New_Feature_Set" wizard Then verify "Feature_Set_Name_Input" element visibility on "New_Feature_Set" wizard Then verify "Version_Input" element visibility on "New_Feature_Set" wizard @@ -593,12 +708,12 @@ Feature: Project Monitoring Page @MLPM @passive @smoke - Scenario: MLPM011 - Check Project Counter redirection to Models page + Scenario: MLPM011 - Check the redirection from Models counter to Models page Given open url And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on "Model_Stats_Counter" element on "Project" wizard + When click on "Model_Stats_Counter" element in "Models_Stats_Container" on "Project" wizard And wait load page Then verify "Table_Name_Filter_Input" element visibility on "Models" wizard Then click on "Table_FilterBy_Button" element on "Models" wizard @@ -615,13 +730,17 @@ Feature: Project Monitoring Page @MLPM @passive @smoke - Scenario: MLPM012 - Check Project Counter redirection to Feature Sets page + #TODO: Create Feature set from the Quick Actions dropdown menu + Scenario: MLPM012 - Check the redirection to Feature sets page during creating the Feature set Given open url And wait load page + When turn on demo mode with query params "false" + And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on "FeatureSets_Stats_Counter" element on "Project" wizard + Then select "Feature set" option in "Quick_Actions" dropdown on "Project" wizard And wait load page + Then verify "Cross_Close_Button" element visibility on "New_Feature_Set" wizard Then verify "Feature_Store_Tab_Selector" on "Feature_Store_Feature_Sets_Tab" wizard should contains "Feature_Store"."Tab_List" Then verify "Feature Sets" tab is active in "Feature_Store_Tab_Selector" on "Feature_Store_Feature_Sets_Tab" wizard Then verify "Table_Refresh_Button" element visibility on "Feature_Store_Feature_Sets_Tab" wizard @@ -649,12 +768,12 @@ Feature: Project Monitoring Page @MLPM @passive @smoke - Scenario: MLPM013 - Check Project Counter redirection to Artifacts page + Scenario: MLPM013 - Check the redirection from Other artifacts counter to Artifacts page Given open url And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on "Artifacts_Stats_Counter" element on "Project" wizard + When click on "Other_Artifacts_Counter_Number" element in "Artifacts_Stats_Container" on "Project" wizard And wait load page Then verify "Table_Name_Filter_Input" element visibility on "Files" wizard Then click on "Table_FilterBy_Button" element on "Files" wizard @@ -665,6 +784,74 @@ Feature: Project Monitoring Page Then verify "Files_Table" element visibility on "Files" wizard Then verify "Register_File_Button" element visibility on "Files" wizard Then "Register_File_Button" element on "Files" should contains "Register artifact" value + + @MLPM + @passive + @smoke + Scenario: MLPM024 - Check the redirection from Datasets counter to Datasets page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When click on "Datasets_Counter_Number" element in "Artifacts_Stats_Container" on "Project" wizard + And wait load page + Then verify "Table_Name_Filter_Input" element visibility on "Datasets" wizard + Then verify "Table_FilterBy_Button" element visibility on "Datasets" wizard + Then click on "Table_FilterBy_Button" element on "Datasets" wizard + Then "Title" element on "FilterBy_Popup" should contains "Filter by" value + Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Table_Tree_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Table_Tree_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Tag_Filer_Options_Main_Table" + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Show_Iterations_Checkbox" element visibility on "FilterBy_Popup" wizard + Then "Checkbox_Label" element on "FilterBy_Popup" should contains "Show best iteration only" value + Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Table_Refresh_Button" element visibility on "Datasets" wizard + Then verify "Datasets_Table" element visibility on "Datasets" wizard + + @MLPM + @passive + @smoke + Scenario: MLPM025 - Check the redirection from Documents counter to Documents page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When click on "Documents_Counter_Number" element in "Artifacts_Stats_Container" on "Project" wizard + And wait load page + Then verify "Table_Name_Filter_Input" element visibility on "Documents" wizard + Then verify "Table_FilterBy_Button" element visibility on "Documents" wizard + Then verify "Table_FilterBy_Button" element on "Documents" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" + Then click on "Table_FilterBy_Button" element on "Documents" wizard + Then "Title" element on "FilterBy_Popup" should contains "Filter by" value + Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Table_Tree_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Table_Tree_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Tag_Filer_Options_Main_Table" + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Show_Iterations_Checkbox" element visibility on "FilterBy_Popup" wizard + Then "Checkbox_Label" element on "FilterBy_Popup" should contains "Show best iteration only" value + Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Clear_Button" element on "FilterBy_Popup" wizard is disabled + Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Apply_Button" element on "FilterBy_Popup" wizard is disabled + Then verify "Table_Refresh_Button" element visibility on "Documents" wizard + Then verify "Table_Refresh_Button" element on "Documents" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + Then verify "Documents_Table" element visibility on "Documents" wizard + + @MLPM + @passive + @smoke + #TODO: Add components check on LLM prompts page + Scenario: MLPM026 - Check the redirection from LLM prompts counter to LLM prompts page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When click on "LLM_Prompts_Counter_Number" element in "Artifacts_Stats_Container" on "Project" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/default/llm-prompts?bePage=1&fePage=1" @MLPM @passive @@ -674,7 +861,7 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on cell with value "Running" in "name" column in "Jobs_Info_Card_Statistics" table on "Project" wizard + When click on "In_Process_Counter_Subtitle" element in "Runs_Statistic_Section_Container" on "Project" wizard And wait load page Then verify "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard should contains "Jobs_And_Workflows"."Tab_List" Then verify "Monitor Jobs" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard @@ -704,27 +891,184 @@ Feature: Project Monitoring Page Then verify "Jobs_Monitor_Table" element visibility on "Jobs_Monitor_Tab" wizard Then navigate back And wait load page - Then click on cell with value "Failed" in "name" column in "Jobs_Info_Card_Statistics" table on "Project" wizard + When click on "Failed_Counter_Subtitle" element in "Runs_Statistic_Section_Container" on "Project" wizard + And wait load page + Then verify "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard should contains "Jobs_And_Workflows"."Tab_List" + Then verify "Monitor Jobs" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Jobs_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitor_Tab" wizard selected option value "Past 24 hours" + Then verify "Table_FilterBy_Button" element visibility on "Jobs_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Jobs_Monitor_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Aborted, Error" + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Batch_Run_Button" element visibility on "Jobs_Monitor_Tab" wizard + Then "Batch_Run_Button" element on "Jobs_Monitor_Tab" should contains "Batch run" value + Then verify "Resource_Monitoring_Button" element visibility on "Jobs_Monitor_Tab" wizard + Then verify "Auto_Refresh_Checkbox" element visibility on "Jobs_Monitor_Tab" wizard + Then "Auto_Refresh_Checkbox" element should be unchecked on "Jobs_Monitor_Tab" wizard + Then verify "Table_Refresh_Button" element visibility on "Jobs_Monitor_Tab" wizard + Then navigate back + And wait load page + When click on "Succeeded_Counter_Subtitle" element in "Runs_Statistic_Section_Container" on "Project" wizard And wait load page + Then verify "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard should contains "Jobs_And_Workflows"."Tab_List" + Then verify "Monitor Jobs" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Jobs_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitor_Tab" wizard selected option value "Past 24 hours" + Then verify "Table_FilterBy_Button" element visibility on "Jobs_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Jobs_Monitor_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Completed" + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Batch_Run_Button" element visibility on "Jobs_Monitor_Tab" wizard + Then "Batch_Run_Button" element on "Jobs_Monitor_Tab" should contains "Batch run" value + Then verify "Resource_Monitoring_Button" element visibility on "Jobs_Monitor_Tab" wizard + Then verify "Auto_Refresh_Checkbox" element visibility on "Jobs_Monitor_Tab" wizard + Then "Auto_Refresh_Checkbox" element should be unchecked on "Jobs_Monitor_Tab" wizard + Then verify "Table_Refresh_Button" element visibility on "Jobs_Monitor_Tab" wizard @MLPM @passive @smoke - Scenario: MLPM015 - Check Project Counter redirection to Schedules tab + Scenario: MLPM015 - Check the redirection from Scheduled counter to Schedule tab Given open url And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on cell with value "Scheduled" in "name" column in "Jobs_Info_Card_Statistics" table on "Project" wizard + When click on "Scheduled_Stats_Counter" element in "Scheduled_Stats_Container" on "Project" wizard + And wait load page + Then verify "Schedule" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Any time" + Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Batch_Run_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then "Batch_Run_Button" element on "Schedule_Monitor_Tab" should contains "Batch run" value + Then verify "Table_Refresh_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Schedule_Monitor_Table" element visibility on "Schedule_Monitor_Tab" wizard + Then navigate back + And wait load page + When click on "Jobs_Counter_Number" element in "Scheduled_Stats_Container" on "Project" wizard And wait load page Then verify "Schedule" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "Table_Name_Filter_Input" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Any time" Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Job" Then verify "Batch_Run_Button" element visibility on "Schedule_Monitor_Tab" wizard Then "Batch_Run_Button" element on "Schedule_Monitor_Tab" should contains "Batch run" value Then verify "Table_Refresh_Button" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Schedule_Monitor_Table" element visibility on "Schedule_Monitor_Tab" wizard + Then click on breadcrumbs "project" label on "commonPagesHeader" wizard + And wait load page + When click on "Workflows_Counter_Number" element in "Scheduled_Stats_Container" on "Project" wizard + And wait load page + Then verify "Schedule" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Any time" + Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" + Then verify "Batch_Run_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then "Batch_Run_Button" element on "Schedule_Monitor_Tab" should contains "Batch run" value + Then verify "Table_Refresh_Button" element visibility on "Schedule_Monitor_Tab" wizard + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Scheduled_Type" + + @MLPM + @passive + @smoke + Scenario: MLPM027 - Check the redirection from Workflows counter to Monitor Workflows tab + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When click on "Workflows_Stats_Counter" element in "Workflows_Stats_Container" on "Project" wizard + And wait load page + Then verify "Monitor Workflows" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past week" + Then verify "Table_FilterBy_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Workflows_Monitor_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Table_Refresh_Button" element visibility on "Workflows_Monitor_Tab" wizard + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Monitoring_Workflow" + Then navigate back + And wait load page + When click on "In_Process_Counter_Number" element in "Workflows_Stats_Container" on "Project" wizard + And wait load page + Then verify "Monitor Workflows" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Any time" + Then verify "Table_FilterBy_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Workflows_Monitor_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Running, Terminating" + Then verify "Table_Refresh_Button" element visibility on "Workflows_Monitor_Tab" wizard + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Monitoring_Workflow_Status" + Then click on breadcrumbs "project" label on "commonPagesHeader" wizard + And wait load page + When click on "Failed_Counter_Number" element in "Workflows_Stats_Container" on "Project" wizard + And wait load page + Then verify "Monitor Workflows" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past week" + Then verify "Table_FilterBy_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Workflows_Monitor_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Error, Failed" + Then verify "Table_Refresh_Button" element visibility on "Workflows_Monitor_Tab" wizard + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Jobs_Monitoring_Status" + Then navigate back + And wait load page + When click on "Succeeded_Counter_Number" element in "Workflows_Stats_Container" on "Project" wizard + And wait load page + Then verify "Monitor Workflows" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past week" + Then verify "Table_FilterBy_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Workflows_Monitor_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Completed" + Then verify "Table_Refresh_Button" element visibility on "Workflows_Monitor_Tab" wizard + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Jobs_Monitoring_Status" + + @MLPM + @passive + @smoke + #TODO: Add components check on LLM prompts page + Scenario: MLPM028 - Check the redirection from Monitoring App counter to Monitoring app page + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When click on "Monitoring_App_Succeeded_Stats_Counter" element in "Monitoring_App_Stats_Container" on "Project" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + Then verify redirection to "projects/default/monitoring-app" + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Monitoring_App" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Monitoring_App" wizard selected option value "Past 24 hours" + Then verify "Refresh_Button" element visibility on "Monitoring_App" wizard + Then navigate back + And wait load page + When click on "Monitoring_App_Failed_Stats_Counter" element in "Monitoring_App_Stats_Container" on "Project" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + Then verify redirection to "projects/default/monitoring-app" + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Monitoring_App" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Monitoring_App" wizard selected option value "Past 24 hours" + Then verify "Refresh_Button" element visibility on "Monitoring_App" wizard @MLPM @passive @@ -753,13 +1097,13 @@ Feature: Project Monitoring Page @MLPM @passive @smoke - Scenario: MLPM016 - Check redirect to Jobs and workflows page using See All link + Scenario: MLPM016 - Check redirect to Jobs and workflows page using All jobs link Given open url And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page Then verify breadcrumbs "project" label should be equal "default" value - Then select "Batch run" option in "Create_New" dropdown on "Project" wizard + Then select "Batch run" option in "Quick_Actions" dropdown on "Project" wizard And wait load page And click on row root with value "test" in "name" column in "Functions_Table" table on "Modal_Wizard_Form" wizard And wait load page @@ -777,9 +1121,10 @@ Feature: Project Monitoring Page Then click on "Project_Monitoring_Button" element on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard And wait load page - Then verify "Recent_text" element visibility on "Project" wizard - Then verify "Create_New" dropdown element on "Project" wizard should contains "Project"."Create_New_Options" - Then click on "See_All_Jobs_Link" element on "Project" wizard + Then verify "Recent_Text" element visibility in "Runs_Statistic_Section_Container" on "Project" wizard + Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options" + Then verify "All_Jobs_Link" element visibility in "Runs_Statistic_Section_Container" on "Project" wizard + When click on "All_Jobs_Link" element in "Runs_Statistic_Section_Container" on "Project" wizard And wait load page Then verify breadcrumbs "tab" label should be equal "Jobs and workflows" value Then verify "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard should contains "Jobs_And_Workflows"."Tab_List" @@ -801,8 +1146,8 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - And save to context "name" column and "href" attribute on 1 row from "Jobs_And_Workflows" table on "Project" wizard - When click on cell with row index 1 in "name" column in "Jobs_And_Workflows" table on "Project" wizard + And save to context "name" column and "href" attribute on 1 row from "Runs_Statistic_Table" table on "Project" wizard + When click on cell with row index 1 in "name" column in "Runs_Statistic_Table" table on "Project" wizard And wait load page Then verify "Arrow_Back" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard @@ -823,8 +1168,7 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on "ConsumerGroups_Stats_Counter" element on "Project" wizard - And wait load page + When click on "ConsumerGroups_Stats_Counter" element in "Realtime_Functions_Nuclio_Statistic_Section" on "Project" wizard And wait load page Then "Title" element on "Consumer_Groups" should contains "Consumer groups (v3io stream)" value Then "Description" element on "Consumer_Groups" should contains "This report displays the project's consumer groups for Iguazio v3io streams" value @@ -833,15 +1177,12 @@ Feature: Project Monitoring Page Then verify "Consumer_Groups_Table" element visibility on "Consumer_Groups" wizard Then click on "Arrow_Back" element on "Consumer_Groups" wizard And wait load page - And wait load page Then verify breadcrumbs "project" label should be equal "default" value - Then verify "Create_New" element visibility on "Project" wizard + Then verify "Quick_Actions" element visibility on "Project" wizard Then verify "Refresh_Button" element visibility on "Project" wizard - Then verify "Dashboard_Realtime_Functions_Table" element visibility on "Project" wizard - Then verify "Jobs_And_Workflows" element visibility on "Project" wizard + Then verify "Realtime_Functions_Nuclio_Table" element visibility on "Project" wizard + Then verify "Runs_Statistic_Table" element visibility on "Project" wizard Then verify "Mono_Values_Cards" element visibility on "Project" wizard - Then verify "Jobs_Info_Card_Statistics" element visibility on "Project" wizard - Then verify "Real_Time_Functions_Card_Statistics" element visibility on "Project" wizard @MLPM @passive @@ -851,8 +1192,7 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on "ConsumerGroups_Stats_Counter" element on "Project" wizard - And wait load page + When click on "ConsumerGroups_Stats_Counter" element in "Realtime_Functions_Nuclio_Statistic_Section" on "Project" wizard And wait load page Then verify "Search_Input" element visibility on "Consumer_Groups" wizard Then verify "Consumer_Groups_Table" element visibility on "Consumer_Groups" wizard @@ -871,13 +1211,13 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "churn-project-admin" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on "ConsumerGroups_Stats_Counter" element on "Project" wizard + When click on "ConsumerGroups_Stats_Counter" element in "Realtime_Functions_Nuclio_Statistic_Section" on "Project" wizard And wait load page And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Consumer_Group_Yet" Then select "project" with "default" value in breadcrumbs menu And wait load page - Then click on "ConsumerGroups_Stats_Counter" element on "Project" wizard + When click on "ConsumerGroups_Stats_Counter" element in "Realtime_Functions_Nuclio_Statistic_Section" on "Project" wizard And wait load page And wait load page And save to context "consumer_group_name" column and "href" attribute on 1 row from "Consumer_Groups_Table" table on "Consumer_Groups" wizard @@ -902,7 +1242,7 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on "ConsumerGroups_Stats_Counter" element on "Project" wizard + When click on "ConsumerGroups_Stats_Counter" element in "Realtime_Functions_Nuclio_Statistic_Section" on "Project" wizard And wait load page And click on cell with row index 1 in "consumer_group_name" column in "Consumer_Groups_Table" table on "Consumer_Groups" wizard And wait load page @@ -923,7 +1263,7 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "auto-generated-data" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - Then click on "Alerts_Stats_Total_Number" element on "Project" wizard + When click on "Alerts_Stats_Counter" element in "Alerts_Stats_Container" on "Project" wizard And wait load page Then verify "Search_By_Name_Filter_Input" element visibility on "Alerts" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Alerts" wizard @@ -946,7 +1286,7 @@ Feature: Project Monitoring Page Then verify "Event_Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on breadcrumbs "project" label on "commonPagesHeader" wizard And wait load page - Then click on "Alerts_Stats_Endpoint_Number" element on "Project" wizard + When click on "Alerts_Stats_Endpoint_Counter" element in "Alerts_Stats_Container" on "Project" wizard And wait load page Then verify "Search_By_Name_Filter_Input" element visibility on "Alerts" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Alerts" wizard @@ -968,7 +1308,7 @@ Feature: Project Monitoring Page Then verify "Event_Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on breadcrumbs "project" label on "commonPagesHeader" wizard And wait load page - Then click on "Alerts_Stats_Jobs_Number" element on "Project" wizard + When click on "Alerts_Stats_Jobs_Counter" element in "Alerts_Stats_Container" on "Project" wizard And wait load page Then verify "Search_By_Name_Filter_Input" element visibility on "Alerts" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Alerts" wizard @@ -989,7 +1329,7 @@ Feature: Project Monitoring Page Then verify "Event_Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on breadcrumbs "project" label on "commonPagesHeader" wizard And wait load page - Then click on "Alerts_Stats_Application_Number" element on "Project" wizard + When click on "Alerts_Stats_Application_Counter" element in "Alerts_Stats_Container" on "Project" wizard And wait load page Then verify "Search_By_Name_Filter_Input" element visibility on "Alerts" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Alerts" wizard diff --git a/tests/features/step-definitions/steps.js b/tests/features/step-definitions/steps.js index 8cc0b91a39..432592296a 100644 --- a/tests/features/step-definitions/steps.js +++ b/tests/features/step-definitions/steps.js @@ -828,7 +828,7 @@ When( fromDatetime, toDatetime ) - await this.driver.sleep(1000) + await this.driver.sleep(2500) await applyDatetimePickerRange( this.driver, pageObjects[wizardName][datetimePicker] @@ -891,6 +891,14 @@ Then( } ) +Then( + 'verify visibility of header column {string} in {string} table on {string} wizard', + async function (columnName, tableName, wizardName) { + const locator = pageObjects[wizardName][tableName].headerSorters[columnName] + await componentIsVisible(this.driver, locator) + } +) + Then('verify {string} element visibility on {string} wizard', async function( component, wizard diff --git a/tests/features/step-definitions/table.steps.js b/tests/features/step-definitions/table.steps.js index d1ab1d3ab8..f5b8c384d2 100644 --- a/tests/features/step-definitions/table.steps.js +++ b/tests/features/step-definitions/table.steps.js @@ -52,6 +52,7 @@ import { isContainsSubstringInColumnDropdownCellsOverlay, isContainsSubstringInColumnTooltipCells, isContainsValueInColumn, + isContainsValueInHeaderColumn, isDatetimeCelsValueInRange, isNotContainsValueInColumn, putToTestContextCellParameters @@ -82,6 +83,15 @@ Then( } ) +Then( + 'check {string} header value in {string} column in {string} table on {string} wizard', + async function (value, column, table, wizard) { + await waitPageLoad(this.driver, pageObjects['commonPagesHeader']['loader']) + + await isContainsValueInHeaderColumn(this.driver, pageObjects[wizard][table], column, value) + } +) + Then( 'check {string} value not in {string} column in {string} table on {string} wizard', async function (value, column, table, wizard) { From 63ba90d34b51c62c1081c48a73e8301948937fba Mon Sep 17 00:00:00 2001 From: adi-gini Date: Mon, 4 Aug 2025 09:35:52 +0300 Subject: [PATCH 083/228] Fix [Projects Monitoring] LLM Prompts summary counter mismatch on Project Monitoring page (#3364) --- src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx index bbefbeba0e..d616c19ed4 100644 --- a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx @@ -47,7 +47,7 @@ const ArtifactsCounters = () => { const dataStats = useMemo(() => { if (projectName) { - const llm_prompts = projectStore?.projectSummary?.data?.llm_prompts || 0 + const llm_prompts = projectStore?.projectSummary?.data?.llm_prompts_count || 0 const files = projectStore?.projectSummary?.data?.files_count || 0 const documents = projectStore?.projectSummary?.data?.documents_count || 0 const datasets = projectStore?.projectSummary?.data?.datasets_count || 0 From 4825ef0223b868ba5e5d5d3dea103e62701b037f Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Mon, 4 Aug 2025 09:36:02 +0300 Subject: [PATCH 084/228] Fix [Jobs monitoring] Project name filter not applied in runs list (#3363) --- src/hooks/useFiltersFromSearchParams.hook.js | 13 +++++---- src/utils/createJobsContent.js | 2 +- src/utils/jobs.util.jsx | 27 ++++++++++++++---- tests/mockServer/mock.js | 29 ++++++++++++++++++-- 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/hooks/useFiltersFromSearchParams.hook.js b/src/hooks/useFiltersFromSearchParams.hook.js index 6df956c89d..c67611142a 100644 --- a/src/hooks/useFiltersFromSearchParams.hook.js +++ b/src/hooks/useFiltersFromSearchParams.hook.js @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import { useMemo } from 'react' -import { mapValues, isNil } from 'lodash' +import { mapValues, isNil, pickBy } from 'lodash' import { DATES_FILTER, ITERATIONS_FILTER, @@ -37,12 +37,15 @@ const defaultParamsParsingCallback = (_, value) => value const getFiltersFromSearchParams = (filtersConfig, searchParams, paramsParsingCallback) => { if (!filtersConfig) return {} - // todo add in 1.10.0 pickBy(filtersConfig, (configValue) => !configValue.) and fix all error where we use hidden configs - return mapValues(filtersConfig, (filterConfig, filterName) => { + const filtersConfigToApply = pickBy( + filtersConfig, + config => !config.hidden || config.applyHidden + ) + + return mapValues(filtersConfigToApply, (filterConfig, filterName) => { const searchParamValue = searchParams.get(filterName)?.trim?.() - // todo remove '|| filterConfig.hidden' after fix above - if (isNil(searchParamValue) || filterConfig.hidden) return filterConfig.initialValue + if (isNil(searchParamValue)) return filterConfig.initialValue let parsedValue = paramsParsingCallback(filterName, searchParamValue) diff --git a/src/utils/createJobsContent.js b/src/utils/createJobsContent.js index 29beb8626c..7c498841eb 100644 --- a/src/utils/createJobsContent.js +++ b/src/utils/createJobsContent.js @@ -464,7 +464,7 @@ export const createJobsMonitoringContent = (jobs, jobName, isStagingMode) => { const savedAndTransformedSearchParams = saveAndTransformSearchParams( window.location.search, true, - [BE_PAGE, FE_PAGE, NAME_FILTER] + [BE_PAGE, FE_PAGE, NAME_FILTER, PROJECT_FILTER] ) return `/projects/*/${JOBS_MONITORING_PAGE}/${JOBS_MONITORING_JOBS_TAB}/${job.name}${savedAndTransformedSearchParams}${savedAndTransformedSearchParams ? '&' : '?'}${`${PROJECT_FILTER}=${job.project}`}` diff --git a/src/utils/jobs.util.jsx b/src/utils/jobs.util.jsx index 32efdf2309..b3b089fed5 100644 --- a/src/utils/jobs.util.jsx +++ b/src/utils/jobs.util.jsx @@ -132,7 +132,13 @@ export const checkForSelectedJob = debounce( .then(job => { const parsedJob = parseJob(job) if (!parsedJob) { - navigate(getCloseDetailsLink(jobName || (projectName ? MONITOR_JOBS_TAB : JOBS_MONITORING_JOBS_TAB), true), { replace: true }) + navigate( + getCloseDetailsLink( + jobName || (projectName ? MONITOR_JOBS_TAB : JOBS_MONITORING_JOBS_TAB), + true + ), + { replace: true } + ) } else if (parsedJob) { const findJobIndex = jobsList => jobsList.findIndex(job => { @@ -153,7 +159,7 @@ export const checkForSelectedJob = debounce( return prevSearchParams }) } else { - parsedJob.ui.infoMessage = generateObjectNotInTheListMessage('job\'s run') + parsedJob.ui.infoMessage = generateObjectNotInTheListMessage("job's run") } } @@ -161,7 +167,13 @@ export const checkForSelectedJob = debounce( } }) .catch(error => { - navigate(getCloseDetailsLink(jobName || (projectName ? MONITOR_JOBS_TAB : JOBS_MONITORING_JOBS_TAB), true), { replace: true }) + navigate( + getCloseDetailsLink( + jobName || (projectName ? MONITOR_JOBS_TAB : JOBS_MONITORING_JOBS_TAB), + true + ), + { replace: true } + ) showErrorNotification( dispatch, error, @@ -183,7 +195,11 @@ export const getJobKindFromLabels = (labels = []) => { export const getJobsFiltersConfig = (jobName, crossProjects) => { const filters = { - [NAME_FILTER]: { label: 'Name:', hidden: Boolean(jobName), initialValue: '' }, + [NAME_FILTER]: { + label: 'Name:', + initialValue: '', + hidden: Boolean(jobName) + }, [DATES_FILTER]: { label: 'Start time:', initialValue: getDatePickerFilterValue( @@ -195,7 +211,8 @@ export const getJobsFiltersConfig = (jobName, crossProjects) => { label: 'Project:', initialValue: PROJECTS_FILTER_ALL_ITEMS, isModal: true, - hidden: Boolean(jobName) + hidden: Boolean(jobName), + applyHidden: true }, [STATUS_FILTER]: { label: 'Status:', initialValue: [FILTER_ALL_ITEMS], isModal: true }, [TYPE_FILTER]: { label: 'Type:', initialValue: FILTER_ALL_ITEMS, isModal: true }, diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 55f1b60a43..2b701be60a 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -390,7 +390,14 @@ function filterByLabels(elementLabels, requestLabels) { function getPartitionedData(listOfItems, pathToPartition, pathToUpdated, defaultPathToPartition) { return chain(listOfItems) - .groupBy(arrayItem => get(arrayItem, pathToPartition, defaultPathToPartition)) + .groupBy(item => { + if (Array.isArray(pathToPartition)) { + return pathToPartition + .map(path => get(item, path, get(item, defaultPathToPartition))) + .join('||') + } + return get(item, pathToPartition, defaultPathToPartition) + }) .map(group => maxBy(group, groupItem => new Date(get(groupItem, pathToUpdated)))) .value() } @@ -952,7 +959,17 @@ function getRuns(req, res) { } if (req.query['partition-by'] && req.query['partition-sort-by']) { - collectedRuns = getPartitionedData(collectedRuns, 'metadata.name', 'status.last_update') + const pathToPartition = ['metadata.name'] + + if (req.query['partition-by'] === 'project_and_name') { + pathToPartition.push('metadata.project') + } + + collectedRuns = getPartitionedData( + collectedRuns, + pathToPartition, + 'status.last_update' + ) } if (req.query['name']) { @@ -1515,9 +1532,15 @@ function getArtifacts(req, res) { } if (req.query['partition-by']) { + const pathToPartition = ['spec.db_key'] + + if (req.query['partition-by'] === 'project_and_name') { + pathToPartition.push('metadata.project') + } + collectedArtifacts = getPartitionedData( collectedArtifacts, - 'spec.db_key', + pathToPartition, 'metadata.updated', 'db_key' ) From e2806a16d75cfa637a648b79258f2cd5a424f4af Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Mon, 4 Aug 2025 09:36:20 +0300 Subject: [PATCH 085/228] Fix [Monitor Applications] Time range title is not fixed during scrolling (#3361) --- .../MEPsWithDetections.jsx | 22 ++-- .../monitoringApplicationCounters.scss | 7 +- .../MonitoringApplicationsPage.jsx | 114 +++++++++--------- .../monitoringApplicationsPage.scss | 9 ++ src/reducers/monitoringApplicationsReducer.js | 25 ++-- src/utils/getChartConfig.jsx | 3 +- 6 files changed, 101 insertions(+), 79 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx index acac31c85d..1115990c5f 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx @@ -25,23 +25,17 @@ import NoData from '../../../common/NoData/NoData' import { Loader, Tip } from 'igz-controls/components' import { - getFiltersConfig, MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicationsPage.util' import { getMEPsWithDetectionChartConfig } from '../../../utils/getChartConfig' import { groupDataToBins } from './monitoringApplications.util' -import { useFiltersFromSearchParams } from '../../../hooks/useFiltersFromSearchParams.hook' -import { DATES_FILTER } from '../../../constants' import { useSelector } from 'react-redux' const MEPsWithDetections = () => { const [isLoading, setIsLoading] = useState(true) + const chartRef = useRef() const chartYAxisRef = useRef() const chartWrapperRef = useRef() - const filtersConfig = useMemo(() => getFiltersConfig(), []) - const filters = useFiltersFromSearchParams(filtersConfig) - const startTime = useMemo(() => filters[DATES_FILTER].value[0].getTime(), [filters]) - const endTime = useMemo(() => (filters[DATES_FILTER].value[1] || new Date()).getTime(), [filters]) const barConfig = useMemo(() => getMEPsWithDetectionChartConfig(), []) const { endpointsWithDetections: { data: endpointsWithDetectionsData, loading } @@ -94,9 +88,9 @@ const MEPsWithDetections = () => { const barChartConfig = useMemo(() => { const { labels, values, dates } = groupDataToBins( - endpointsWithDetectionsData, - startTime, - endTime + endpointsWithDetectionsData.values, + endpointsWithDetectionsData.start, + endpointsWithDetectionsData.end ) return { @@ -130,7 +124,7 @@ const MEPsWithDetections = () => { }, plugins: [renderPlugin] } - }, [barConfig, endTime, endpointsWithDetectionsData, renderPlugin, startTime]) + }, [barConfig, endpointsWithDetectionsData, renderPlugin]) return (
      @@ -149,8 +143,12 @@ const MEPsWithDetections = () => { >
      - +
      +
      Time range
      diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss index 09d14d7c03..b3bb9fed24 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss @@ -2,14 +2,15 @@ .monitoring-application__statistics-section { display: flex; - gap: 15px; flex-direction: row; - margin-bottom: 25px; + gap: 15px; width: 100%; + margin-bottom: 25px; .monitoring-stats { flex: 1; padding: 15px; + border: 1px solid colors.$frenchLilac; &__alert { background-color: colors.$carouselPink; @@ -25,8 +26,8 @@ } .stats__counter { - font-weight: 500; color: colors.$primary; + font-weight: 500; font-size: 28px; } diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index a8e01e5b22..d1d5d56c53 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -52,67 +52,71 @@ const MonitoringApplicationsPage = () => { const [, setSearchParams] = useSearchParams() const refreshMonitoringApplications = useCallback( - filters => { - dispatch(fetchMonitoringApplicationsSummary({ project: params.projectName })) - .unwrap() - .catch(error => { - showErrorNotification(dispatch, error, '', 'Failed to fetch applications summary') - }) - dispatch(fetchMonitoringApplications({ project: params.projectName, filters })) - .unwrap() - .catch(error => { - showErrorNotification(dispatch, error, '', 'Failed to fetch monitoring applications') - }) - dispatch( - fetchMEPWithDetections({ - project: params.projectName, - filters: filters - }) - ) - .unwrap() - .catch(error => { - showErrorNotification( - dispatch, - error, - '', - 'Failed to fetch Model Endpoints with suspected/detected issue' - ) - }) + (filters, isFilterApplyAction) => { + if (!isFilterApplyAction) { + dispatch(fetchMonitoringApplicationsSummary({ project: params.projectName })) + .unwrap() + .catch(error => { + showErrorNotification(dispatch, error, '', 'Failed to fetch applications summary') + }) + dispatch(fetchMonitoringApplications({ project: params.projectName, filters })) + .unwrap() + .catch(error => { + showErrorNotification(dispatch, error, '', 'Failed to fetch monitoring applications') + }) + dispatch( + fetchMEPWithDetections({ + project: params.projectName, + filters: filters + }) + ) + .unwrap() + .catch(error => { + showErrorNotification( + dispatch, + error, + '', + 'Failed to fetch Model Endpoints with suspected/detected issue' + ) + }) + } }, [dispatch, params.projectName] ) const refreshMonitoringApplication = useCallback( - filters => { - dispatch( - fetchArtifacts({ - project: params.projectName, - filters: { - ...filters, - labels: `mlrun/app-name=${params.name}` - } - }) - ) - .unwrap() - .catch(error => { - showErrorNotification(dispatch, error, '', 'Failed to fetch artifacts') - }) + (filters, isFilterApplyAction) => { + if (!isFilterApplyAction) { + dispatch( + fetchArtifacts({ + project: params.projectName, + filters: { + ...filters, + labels: `mlrun/app-name=${params.name}` + } + }) + ) + .unwrap() + .catch(error => { + showErrorNotification(dispatch, error, '', 'Failed to fetch artifacts') + }) - dispatch( - fetchMonitoringApplication({ - project: params.projectName, - functionName: params.name, - filters - }) - ) - .unwrap() - .catch(error => { - showErrorNotification(dispatch, error, '', 'Failed to fetch monitoring application') - navigate( - `/projects/${params.projectName}/${MONITORING_APP_PAGE}${window.location.search}`, - { replace: true } - ) - }) + dispatch( + fetchMonitoringApplication({ + project: params.projectName, + functionName: params.name, + filters + }) + ) + .unwrap() + .catch(error => { + showErrorNotification(dispatch, error, '', 'Failed to fetch monitoring application') + navigate( + `/projects/${params.projectName}/${MONITORING_APP_PAGE}${window.location.search}`, + { replace: true } + ) + }) + } }, [dispatch, navigate, params.name, params.projectName] ) diff --git a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss index c0f1504ef6..eaf562986d 100644 --- a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss +++ b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss @@ -86,8 +86,17 @@ $applicationRowHeightExtended: variables.$rowHeightExtended; .section-item_chart-area { height: 100%; + padding-bottom: 25px; overflow-x: auto; + &_x-axis-label { + position: absolute; + bottom: 10px; + left: 50%; + font-weight: 500; + font-size: 13px; + } + &.loading { visibility: hidden; } diff --git a/src/reducers/monitoringApplicationsReducer.js b/src/reducers/monitoringApplicationsReducer.js index ec6f42299b..aa3f41c43b 100644 --- a/src/reducers/monitoringApplicationsReducer.js +++ b/src/reducers/monitoringApplicationsReducer.js @@ -30,7 +30,11 @@ const initialState = { error: null }, endpointsWithDetections: { - data: [], + data: { + values: [], + start: null, + end: null + }, loading: false, error: null }, @@ -54,8 +58,15 @@ export const fetchMEPWithDetections = createAsyncThunk( params.end = filters[DATES_FILTER].value[1].getTime() } + const savedStartDate = filters[DATES_FILTER].value[0].getTime() + const savedEndDate = (filters[DATES_FILTER].value[1] || new Date()).getTime() + return monitoringApplicationsApi.getMEPWithDetections(project, params).then(response => { - return response.data.values.map(([date, suspected, detected]) => [date, suspected + detected]) + return { + values: response.data.values.map(([date, suspected, detected]) => [date, suspected + detected]), + start: savedStartDate, + end: savedEndDate + } }) } ) @@ -63,12 +74,12 @@ export const fetchMEPWithDetections = createAsyncThunk( export const fetchMonitoringApplication = createAsyncThunk( 'fetchMonitoringApplication', ({ project, functionName, filters }) => { - let params = {} + const params = { + start: filters[DATES_FILTER].value[0].getTime() + } - if (filters[DATES_FILTER]) { - params = { - start: filters[DATES_FILTER].value[0].getTime() - } + if (filters[DATES_FILTER].value[1]) { + params.end = filters[DATES_FILTER].value[1].getTime() } return monitoringApplicationsApi diff --git a/src/utils/getChartConfig.jsx b/src/utils/getChartConfig.jsx index 32f141abc2..f352fc96b2 100644 --- a/src/utils/getChartConfig.jsx +++ b/src/utils/getChartConfig.jsx @@ -341,8 +341,7 @@ export const getMEPsWithDetectionChartConfig = () => { x: { ...barConfig.options.scales.x, title: { - ...barConfig.options.scales.x.title, - text: 'Time range' + display: false } }, y: { From 295b8d4ff5509c48e73ea21ceac37cc521436e5e Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 4 Aug 2025 09:36:39 +0300 Subject: [PATCH 086/228] Fix [LLM Prompt Artifact] Content becomes expanded only when the search contains more than 1 letter (#3360) --- src/common/ExpandableText/ExpandableText.jsx | 17 ++++++++++++----- src/common/ExpandableText/expandableText.scss | 2 +- src/common/SearchNavigator/SearchNavigator.jsx | 5 +++-- .../Details/DetailsPromptTemplate/PromptTab.jsx | 13 ++++++++----- .../ModelsPage/Models/models.util.jsx | 7 +++++++ 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/common/ExpandableText/ExpandableText.jsx b/src/common/ExpandableText/ExpandableText.jsx index 493d2442cb..fe38a4260f 100644 --- a/src/common/ExpandableText/ExpandableText.jsx +++ b/src/common/ExpandableText/ExpandableText.jsx @@ -17,21 +17,27 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { useState, useRef, useEffect } from 'react' +import { useState, useRef, useEffect, useContext } from 'react' import PropTypes from 'prop-types' import './expandableText.scss' -const ExpandableText = ({ children, collapsedHeight = 95, forceExpand = false }) => { +const ExpandableText = ({ + children, + context = null, + collapsedHeight = 95, + forceExpand = false +}) => { const [expanded, setExpanded] = useState(false) const [isOverflowing, setIsOverflowing] = useState(false) const contentRef = useRef(null) + const { contextForceExpand } = useContext(context) useEffect(() => { - if (forceExpand) { - setExpanded(forceExpand) + if (forceExpand || contextForceExpand) { + setExpanded(forceExpand || contextForceExpand) } - }, [forceExpand]) + }, [contextForceExpand, forceExpand]) useEffect(() => { const element = contentRef.current @@ -76,6 +82,7 @@ const ExpandableText = ({ children, collapsedHeight = 95, forceExpand = false }) ExpandableText.propTypes = { children: PropTypes.node.isRequired, + context: PropTypes.object, collapsedHeight: PropTypes.number, forceExpand: PropTypes.bool } diff --git a/src/common/ExpandableText/expandableText.scss b/src/common/ExpandableText/expandableText.scss index efb3b2e6f1..8616849e1c 100644 --- a/src/common/ExpandableText/expandableText.scss +++ b/src/common/ExpandableText/expandableText.scss @@ -5,7 +5,7 @@ } .expandable-text { - display: flex; + display: block; transition: max-height 0.3s ease; position: relative; overflow: hidden; diff --git a/src/common/SearchNavigator/SearchNavigator.jsx b/src/common/SearchNavigator/SearchNavigator.jsx index 70cef108dd..b2cde57004 100644 --- a/src/common/SearchNavigator/SearchNavigator.jsx +++ b/src/common/SearchNavigator/SearchNavigator.jsx @@ -47,7 +47,8 @@ const SearchNavigator = ({ promptTemplate, setSearchResult, searchOnChange = nul setActiveMatchIndex(0) setSearchValue('') setMatchCount(0) - }, [promptTemplate, setSearchResult]) + searchOnChange?.('') + }, [promptTemplate, searchOnChange, setSearchResult]) const searchOnChangeHandler = useCallback( value => { @@ -64,7 +65,7 @@ const SearchNavigator = ({ promptTemplate, setSearchResult, searchOnChange = nul setMatches(new Array(jsxMatchCount).fill(null)) setActiveMatchIndex(0) setSearchValue(value) - searchOnChange?.() + searchOnChange?.(value) }, [promptTemplate, setSearchResult, searchOnChange, clearResults] ) diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx index 91384cc591..d815f8958a 100644 --- a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { useEffect, useState } from 'react' +import { useEffect, useState, createContext } from 'react' import PropTypes from 'prop-types' import { capitalize, isEmpty } from 'lodash' @@ -29,6 +29,8 @@ import { ARGUMENTS_TAB } from '../../../constants' import ExpandableText from '../../../common/ExpandableText/ExpandableText' +export const ExpandContext = createContext({}) + const PromptTab = ({ handleTabChange, selectedItem, @@ -77,7 +79,7 @@ const PromptTab = ({
      {capitalize(item.role)}
      - {parts} + {parts}
      ) @@ -89,7 +91,6 @@ const PromptTab = ({ selectedItem.prompt_legend, setSelectedArgument, setSelectedTab, - forceExpandAll, selectedItem.prompt_template ]) @@ -100,7 +101,7 @@ const PromptTab = ({ setForceExpandAll(true)} + searchOnChange={value => setForceExpandAll(Boolean(value))} />
      @@ -108,7 +109,9 @@ const PromptTab = ({
      Role
      Content
      - {searchResult || promptTemplate} + + {searchResult || promptTemplate} +
      ) diff --git a/src/components/ModelsPage/Models/models.util.jsx b/src/components/ModelsPage/Models/models.util.jsx index a6298c0671..ce505b6d62 100644 --- a/src/components/ModelsPage/Models/models.util.jsx +++ b/src/components/ModelsPage/Models/models.util.jsx @@ -241,6 +241,7 @@ export const generateActionsMenu = ( disabled: !isTargetPathValid || modelMin.size > + modelMin.size > (frontendSpec?.artifact_limits?.max_download_size ?? ARTIFACT_MAX_DOWNLOAD_SIZE), icon: , onClick: modelMin => { @@ -278,6 +279,9 @@ export const generateActionsMenu = ( className: 'danger', hidden: isDetailsPopUp, disabled: modelMin?.has_children, + tooltip: modelMin?.has_children + ? 'There are llm-prompt artifacts pointing to this model. The model cannot be deleted' + : null, onClick: () => openDeleteConfirmPopUp( 'Delete model?', @@ -302,6 +306,9 @@ export const generateActionsMenu = ( icon: , hidden: isAllVersions || isDetailsPopUp, disabled: modelMin?.has_children, + tooltip: modelMin?.has_children + ? 'There are llm-prompt artifacts pointing to this model. The model cannot be deleted' + : null, className: 'danger', onClick: () => openDeleteConfirmPopUp( From af7bed89bcf25d1a15c3b3e535d5fdc89792374e Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 4 Aug 2025 09:38:58 +0300 Subject: [PATCH 087/228] Fix [Artifacts] Missing colons in the message "No data matching the filter" (#3362) --- src/utils/getNoDataMessage.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils/getNoDataMessage.js b/src/utils/getNoDataMessage.js index d93131c4c1..14ec813c10 100644 --- a/src/utils/getNoDataMessage.js +++ b/src/utils/getNoDataMessage.js @@ -181,7 +181,9 @@ const generateNoEntriesFoundMessage = (visibleFilterTypes, filtersConfig, filter : filters[filterType] const isLastElement = index === visibleFilterTypes.length - 1 - return message + `${label} ${value}${isLastElement ? '"' : ', '}` + return ( + message + `${label.endsWith(':') ? label : `${label}:`} ${value}${isLastElement ? '"' : ', '}` + ) }, 'No data matches the filter: "') } From 54b55a388580fd99bdbd94864cd49a43b8bec84b Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Mon, 4 Aug 2025 12:47:41 +0300 Subject: [PATCH 088/228] Bump DRC version `3.1.5` (#3365) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a1f7959e7e..006e51f054 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.4", + "iguazio.dashboard-react-controls": "3.1.5", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", From b92285b8eabb3e54dc17cbf4f6ee3a1ff7cafac6 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Mon, 4 Aug 2025 12:49:43 +0300 Subject: [PATCH 089/228] Fix [Alerts] Selected row isn't highlighted (#3366) --- src/utils/parseAlert.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/utils/parseAlert.js b/src/utils/parseAlert.js index 458d186b8e..9e6063c064 100644 --- a/src/utils/parseAlert.js +++ b/src/utils/parseAlert.js @@ -17,14 +17,16 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import { getAlertIdentifier } from './getUniqueIdentifier' + export const parseAlerts = alerts => { return alerts.map(alert => { return { ...alert, ui: { ...alert, - identifier: alert.id, - identifierUnique: `${alert.name}.${alert.id}` + identifier: getAlertIdentifier(alert), + identifierUnique: getAlertIdentifier(alert, true) } } }) From 83fcb132f5139315a035af7ed0ff922dc175ace4 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Mon, 4 Aug 2025 16:32:50 +0300 Subject: [PATCH 090/228] Fix [Feature store] Feature set isn't displayed after creation (#3368) --- tests/mockServer/mock.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 2b701be60a..86cc3b1957 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -486,8 +486,6 @@ function createProjectsFeatureSet(req, res) { function updateProjectsFeatureSet(req, res) { let featureSet = req.body - featureSet.metadata.updated = new Date().toISOString() - const featureSetIndex = featureSets.feature_sets.findIndex( featureSetItem => req.params.project === featureSetItem.metadata.project && @@ -496,6 +494,11 @@ function updateProjectsFeatureSet(req, res) { featureSet.metadata.uid === featureSetItem.metadata.uid ) + if (featureSetIndex === -1) { + return createProjectsFeatureSet(req, res) + } + + featureSet.metadata.updated = new Date().toISOString() featureSets.feature_sets[featureSetIndex] = featureSet res.send(featureSet) From fe066569f5f61f19de8e8842e11e0de98293a505 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Mon, 4 Aug 2025 19:11:03 +0300 Subject: [PATCH 091/228] Fix [Counters] runs and workflows counters are missing stats__counter class (#3369) --- .../AlertsCounters.jsx | 8 ++--- .../ArtifactsCounters.jsx | 32 ++++++++++++------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index eec9293a9e..5d72313b2c 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -114,7 +114,7 @@ const AlertsCounters = () => { data-testid="alerts_total_counter" onClick={alertsStats?.total?.link} > -
      +
      {projectStore?.projectsSummary?.loading ? ( ) : ( @@ -132,7 +132,7 @@ const AlertsCounters = () => { data-testid="alerts_endpoints_counter" >
      Endpoint
      -
      +
      {projectStore?.projectsSummary?.loading ? ( ) : ( @@ -148,7 +148,7 @@ const AlertsCounters = () => { onClick={alertsStats?.job?.link} >
      Jobs
      -
      +
      {projectStore?.projectsSummary?.loading ? ( ) : ( @@ -164,7 +164,7 @@ const AlertsCounters = () => { data-testid="alerts_application_counter" >
      Application
      -
      +
      {projectStore.projectsSummary.loading ? ( ) : ( diff --git a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx index d616c19ed4..df0be2348a 100644 --- a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx @@ -100,11 +100,13 @@ const ArtifactsCounters = () => { onClick={data?.datasets?.link} >
      Datasets
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - data?.datasets.counter?.toLocaleString() - )} +
      + {projectStore.projectsSummary.loading ? ( + + ) : ( +
      {data?.datasets.counter?.toLocaleString()}
      + )} +
      @@ -114,11 +116,15 @@ const ArtifactsCounters = () => { onClick={data?.documents?.link} >
      Documents
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - data?.documents?.counter?.toLocaleString() - )} +
      + {projectStore.projectsSummary.loading ? ( + + ) : ( +
      + {data?.documents?.counter?.toLocaleString()} +
      + )} +
      @@ -131,7 +137,9 @@ const ArtifactsCounters = () => { {projectStore.projectsSummary.loading ? ( ) : ( - data?.llm_prompt?.counter?.toLocaleString() +
      + {data?.llm_prompt?.counter?.toLocaleString()} +
      )}
      @@ -145,7 +153,7 @@ const ArtifactsCounters = () => { {projectStore.projectsSummary.loading ? ( ) : ( - data?.files?.counter?.toLocaleString() +
      {data?.files?.counter?.toLocaleString()}
      )}
      From af9d049525050d9fcddf363713695d6602e8cce7 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 5 Aug 2025 11:17:56 +0300 Subject: [PATCH 092/228] Fix [Alerts] '!' icon is missing on the Alerts tab (#3367) --- package.json | 2 +- src/elements/AlertsTableRow/AlertsTableRow.scss | 7 +------ src/scss/main.scss | 13 +++++++++++++ src/utils/createAlertsContent.jsx | 2 +- src/utils/createArtifactsContent.jsx | 4 ++-- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 006e51f054..661b958bb5 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.5", + "iguazio.dashboard-react-controls": "3.1.6", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", diff --git a/src/elements/AlertsTableRow/AlertsTableRow.scss b/src/elements/AlertsTableRow/AlertsTableRow.scss index 471359966a..ae9ebd21c9 100644 --- a/src/elements/AlertsTableRow/AlertsTableRow.scss +++ b/src/elements/AlertsTableRow/AlertsTableRow.scss @@ -45,14 +45,9 @@ top: 9px; left: 14px; - path { - fill: colors.$burntSienna; - } - svg { width: 14px; height: 14px; - padding: 1px; background-color: colors.$white; border-radius: 50%; } @@ -127,8 +122,8 @@ &.modal { .modal__header { align-items: flex-start; - padding: 1rem 2rem; min-height: auto; + padding: 1rem 2rem; &-title { font-size: 18px; diff --git a/src/scss/main.scss b/src/scss/main.scss index a78acb7b6c..06592ebd60 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -557,3 +557,16 @@ div[id^='chartjs-tooltip'] { .override-artifact-dialog { z-index: 10; } + +/* =========== ICONS ============= */ + +.table-severity-warning-icon { + svg { + width: 32px; + height: 32px; + + path { + fill: colors.$supernova; + } + } +} diff --git a/src/utils/createAlertsContent.jsx b/src/utils/createAlertsContent.jsx index 9fefacf2a2..12631f785d 100644 --- a/src/utils/createAlertsContent.jsx +++ b/src/utils/createAlertsContent.jsx @@ -22,7 +22,7 @@ import { formatDatetime } from 'igz-controls/utils/datetime.util' import Application from 'igz-controls/images/entity-type-application.svg?react' import Endpoint from 'igz-controls/images/entity-type-endpoint.svg?react' -import Error from 'igz-controls/images/severity-warning.svg?react' +import Error from 'igz-controls/images/notification-badge.svg?react' import Critical from 'igz-controls/images/severity-critical.svg?react' import Email from 'igz-controls/images/email-icon.svg?react' import Git from 'igz-controls/images/git-icon.svg?react' diff --git a/src/utils/createArtifactsContent.jsx b/src/utils/createArtifactsContent.jsx index 128a05c205..46e5a010af 100644 --- a/src/utils/createArtifactsContent.jsx +++ b/src/utils/createArtifactsContent.jsx @@ -41,7 +41,7 @@ import { validateArguments } from './validateArguments' // import { roundFloats } from 'igz-controls/utils/common.util' import SeverityOk from 'igz-controls/images/severity-ok.svg?react' -import SeverityWarning from 'igz-controls/images/severity-warning.svg?react' +import SeverityWarning from 'igz-controls/images/severity-low.svg?react' import SeverityError from 'igz-controls/images/severity-error.svg?react' import TableModelCell from '../elements/TableModelCell/TableModelCell' @@ -415,7 +415,7 @@ export const getDriftStatusData = driftStatus => { case 'POSSIBLE_DRIFT': return { value: ( - + ), From e8ccd1ac9546960b7f7b54ec5951ecded90e0f49 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Wed, 6 Aug 2025 12:25:01 +0300 Subject: [PATCH 093/228] Fix [LLM prompts] Align the main table view (#3371) --- .../DetailsPromptTemplate/PromptTab.jsx | 8 +++++ .../TableModelCell/TableModelCell.jsx | 30 ++++++++++--------- src/utils/getNoDataMessage.js | 6 +++- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx index d815f8958a..99ff4142f5 100644 --- a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -94,6 +94,14 @@ const PromptTab = ({ selectedItem.prompt_template ]) + useEffect(() => { + return () => { + setPromptTemplate([]) + setSearchResult('') + setForceExpandAll(false) + } + }, []) + return (
      diff --git a/src/elements/TableModelCell/TableModelCell.jsx b/src/elements/TableModelCell/TableModelCell.jsx index fe5e30ef83..700ff758dd 100644 --- a/src/elements/TableModelCell/TableModelCell.jsx +++ b/src/elements/TableModelCell/TableModelCell.jsx @@ -40,22 +40,24 @@ const TableModelCell = ({ id, modelUri, bodyCellClassName = '' }) => { }, [parsedUri]) return ( - modelUri && ( -
      - ) + {parsedUri.tag} + + )} + ) } diff --git a/src/utils/getNoDataMessage.js b/src/utils/getNoDataMessage.js index 14ec813c10..01be4118cd 100644 --- a/src/utils/getNoDataMessage.js +++ b/src/utils/getNoDataMessage.js @@ -64,7 +64,9 @@ import { TAG_FILTER_ALL_ITEMS, TYPE_FILTER, PROJECTS_FILTER_ALL_ITEMS, - LLM_PROMPTS_PAGE + LLM_PROMPTS_PAGE, + MODEL_NAME_FILTER, + MODEL_TAG_FILTER } from '../constants' const messageNamesList = { @@ -203,6 +205,8 @@ const getVisibleFilterTypes = (filtersConfig, filters, filtersStore) => { type === ENDPOINT_RESULT || type === JOB_NAME || type === LABELS_FILTER || + type === MODEL_NAME_FILTER || + type === MODEL_TAG_FILTER || type === NAME_FILTER) && filters[type]?.length > 0 const isStatusVisible = From 1d81fbb33f5b96c21bfd429a5961825031cc0e7f Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Wed, 6 Aug 2025 12:25:22 +0300 Subject: [PATCH 094/228] Fix [LLM Prompts] Prompt template Tab has no info (#3372) --- src/components/Details/DetailsPromptTemplate/PromptTab.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx index 99ff4142f5..0ec4f2faed 100644 --- a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -44,7 +44,7 @@ const PromptTab = ({ const [forceExpandAll, setForceExpandAll] = useState(false) useEffect(() => { - if (Array.isArray(selectedItem.prompt_template) && !isEmpty(selectedItem.prompt_legend)) { + if (Array.isArray(selectedItem.prompt_template)) { const legendMap = { ...selectedItem.prompt_legend } const regex = new RegExp(`\\b(${Object.keys(legendMap).join('|')})\\b`, 'g') From 1745199840e6e2dc84a9ce49b648b8aebb85b091 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Thu, 7 Aug 2025 18:54:14 +0300 Subject: [PATCH 095/228] Fix [Monitor Applications] Y-axis label is truncated (#3370) --- .../MonitoringApplicationsPage/monitoringApplicationsPage.scss | 1 + src/utils/getChartConfig.jsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss index eaf562986d..51ab5ad6a8 100644 --- a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss +++ b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss @@ -95,6 +95,7 @@ $applicationRowHeightExtended: variables.$rowHeightExtended; left: 50%; font-weight: 500; font-size: 13px; + transform: translate(-50%, 0); } &.loading { diff --git a/src/utils/getChartConfig.jsx b/src/utils/getChartConfig.jsx index f352fc96b2..b0c5f10ac6 100644 --- a/src/utils/getChartConfig.jsx +++ b/src/utils/getChartConfig.jsx @@ -348,7 +348,7 @@ export const getMEPsWithDetectionChartConfig = () => { ...barConfig.options.scales.y, title: { ...barConfig.options.scales.y.title, - text: 'Model endpoint with detections' + text: 'Model endpoints' } } }, From be1f60b9b977de15ed68642399900edbe1686ac2 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Thu, 7 Aug 2025 18:54:33 +0300 Subject: [PATCH 096/228] Fix [Retry Job] Fix text in tooltips (#3373) --- src/components/Jobs/jobs.util.js | 4 ++-- src/utils/createJobsContent.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Jobs/jobs.util.js b/src/components/Jobs/jobs.util.js index 7f2fa458ef..ca49f9f85e 100644 --- a/src/components/Jobs/jobs.util.js +++ b/src/components/Jobs/jobs.util.js @@ -74,8 +74,8 @@ export const getInfoHeaders = (isSpark, selectedJob) => { { label: 'Log level', id: LOG_LEVEL_ID }, { label: 'Output path', id: 'outputPath' }, { label: 'Total iterations', id: 'iterations' }, - { label: 'Attempt count', id: 'retryCountWithInitialAttempt', tip: 'Number of attempts to run kubejobs' }, - { label: 'Maximum attempts', id: 'maxRetriesWithInitialAttempt', tip: 'Maximin number of attempts to run kubejobs' } + { label: 'Attempt count', id: 'retryCountWithInitialAttempt', tip: 'Number of attempts to run Kubernetes jobs' }, + { label: 'Maximum attempts', id: 'maxRetriesWithInitialAttempt', tip: 'Maximum number of attempts to run Kubernetes jobs' } ] if (isSpark) { diff --git a/src/utils/createJobsContent.js b/src/utils/createJobsContent.js index 7c498841eb..6045864965 100644 --- a/src/utils/createJobsContent.js +++ b/src/utils/createJobsContent.js @@ -169,7 +169,7 @@ export const createJobsMonitorTabContent = (jobs, jobName, isStagingMode) => { id: `attempts.${identifierUnique}`, value: `${job.retryCountWithInitialAttempt} out of ${job.maxRetriesWithInitialAttempt}`, className: 'table-cell-1', - tip: 'Number of attempts to run kubejobs' + tip: 'Number of attempts to run Kubernetes jobs' } ] } @@ -571,7 +571,7 @@ export const createJobsMonitoringContent = (jobs, jobName, isStagingMode) => { id: `attempts.${identifierUnique}`, value: `${job.retryCountWithInitialAttempt} out of ${job.maxRetriesWithInitialAttempt}`, className: 'table-cell-1', - tip: 'Number of attempts to run kubejobs' + tip: 'Number of attempts to run Kubernetes jobs' } ] } From bd256cc5772f098fddd6ff75ad9279dfe9ae8117 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Thu, 7 Aug 2025 18:55:01 +0300 Subject: [PATCH 097/228] Fix [Model endpoints] Error occurred during retrieving the artifact (#3374) --- .../ArtifactPopUp/ArtifactPopUp.jsx | 79 +++++++++++++------ 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx b/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx index 54531db6c5..0cf9f9421f 100644 --- a/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx +++ b/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx @@ -42,12 +42,18 @@ import { generateActionsMenu as generateDocumentActionsMenu, generatePageData as generateDocumentPageData } from '../../../components/Documents/documents.util' +import { + generateActionsMenu as generateLlmPromptActionsMenu, + generatePageData as generateLlmPromptPageData +} from '../../../components/LLMPrompts/llmPrompts.util' import { DATASET_TYPE, DATASETS_PAGE, DOCUMENT_TYPE, DOCUMENTS_PAGE, FILES_PAGE, + LLM_PROMPT_TYPE, + LLM_PROMPTS_PAGE, MODEL_TYPE, MODELS_TAB } from '../../../constants' @@ -65,33 +71,51 @@ const ArtifactPopUp = ({ artifactData, isOpen, onResolve }) => { const viewMode = getViewMode(window.location.search) const artifactContext = useMemo(() => { - return [DATASETS_PAGE, DATASET_TYPE].includes(artifactData.kind) - ? { + switch (artifactData.kind) { + case DATASETS_PAGE: + case DATASET_TYPE: + return { type: DATASETS_PAGE, generateActionsMenu: generateDatasetActionsMenu, pageData: generateDatasetPageData(viewMode, selectedArtifact, {}, true), fetchArtifact: artifactsApi.getDataSets } - : [MODELS_TAB, MODEL_TYPE].includes(artifactData.kind) - ? { - type: MODELS_TAB, - generateActionsMenu: generateModelActionsMenu, - pageData: generateModelPageData(viewMode, selectedArtifact), - fetchArtifact: artifactsApi.getModels - } - : [DOCUMENTS_PAGE, DOCUMENT_TYPE].includes(artifactData.kind) - ? { - type: DOCUMENTS_PAGE, - generateActionsMenu: generateDocumentActionsMenu, - pageData: generateDocumentPageData(viewMode), - fetchArtifact: artifactsApi.getDocuments - } - : { - type: FILES_PAGE, - generateActionsMenu: generateFileActionsMenu, - pageData: generateFilePageData(viewMode), - fetchArtifact: artifactsApi.getFiles - } + + case MODELS_TAB: + case MODEL_TYPE: + return { + type: MODELS_TAB, + generateActionsMenu: generateModelActionsMenu, + pageData: generateModelPageData(viewMode, selectedArtifact), + fetchArtifact: artifactsApi.getModels + } + + case DOCUMENTS_PAGE: + case DOCUMENT_TYPE: + return { + type: DOCUMENTS_PAGE, + generateActionsMenu: generateDocumentActionsMenu, + pageData: generateDocumentPageData(viewMode), + fetchArtifact: artifactsApi.getDocuments + } + + case LLM_PROMPTS_PAGE: + case LLM_PROMPT_TYPE: + return { + type: LLM_PROMPTS_PAGE, + generateActionsMenu: generateLlmPromptActionsMenu, + pageData: generateLlmPromptPageData(viewMode), + fetchArtifact: artifactsApi.getLLMPrompts + } + + default: + return { + type: FILES_PAGE, + generateActionsMenu: generateFileActionsMenu, + pageData: generateFilePageData(viewMode), + fetchArtifact: artifactsApi.getFiles + } + } }, [selectedArtifact, artifactData.kind, viewMode]) const toggleConvertedYaml = useCallback( @@ -141,7 +165,16 @@ const ArtifactPopUp = ({ artifactData, isOpen, onResolve }) => { onResolve() }) - }, [artifactData, artifactContext, dispatch, onResolve]) + }, [ + artifactData, + artifactContext, + dispatch, + onResolve, + artifactData.iteration, + artifactData.tree, + artifactData.uid, + artifactData.tag + ]) const actionsMenu = useMemo( () => fileMin => From 27b7b42138a0b103053e1a5f72b0632fe753376e Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Thu, 7 Aug 2025 18:55:15 +0300 Subject: [PATCH 098/228] Fix [LLM Prompt Artifact] Remove delete (#3375) --- src/components/LLMPrompts/llmPrompts.util.jsx | 130 +++++++++--------- 1 file changed, 63 insertions(+), 67 deletions(-) diff --git a/src/components/LLMPrompts/llmPrompts.util.jsx b/src/components/LLMPrompts/llmPrompts.util.jsx index 756126a505..c51ac6da9f 100644 --- a/src/components/LLMPrompts/llmPrompts.util.jsx +++ b/src/components/LLMPrompts/llmPrompts.util.jsx @@ -19,13 +19,10 @@ such restriction. */ import React from 'react' -import DeleteArtifactPopUp from '../../elements/DeleteArtifactPopUp/DeleteArtifactPopUp' - import { ARTIFACT_MAX_DOWNLOAD_SIZE, ITERATIONS_FILTER, LABELS_FILTER, - LLM_PROMPT_TYPE, LLM_PROMPTS_PAGE, MODEL_NAME_FILTER, MODEL_TAG_FILTER, @@ -39,8 +36,6 @@ import { applyTagChanges, chooseOrFetchArtifact } from '../../utils/artifacts.ut import { copyToClipboard } from '../../utils/copyToClipboard' import { generateUri } from '../../utils/resources' import { getIsTargetPathValid } from '../../utils/createArtifactsContent' -import { handleDeleteArtifact } from '../../utils/handleDeleteArtifact' -import { openDeleteConfirmPopUp, openPopUp } from 'igz-controls/utils/common.util' import { setDownloadItem, setShowDownloadsList } from '../../reducers/downloadReducer' import { showArtifactsPreview } from '../../reducers/artifactsReducer' import { FULL_VIEW_MODE } from 'igz-controls/constants' @@ -49,7 +44,6 @@ import TagIcon from 'igz-controls/images/tag-icon.svg?react' import YamlIcon from 'igz-controls/images/yaml.svg?react' import ArtifactView from 'igz-controls/images/eye-icon.svg?react' import Copy from 'igz-controls/images/copy-to-clipboard-icon.svg?react' -import Delete from 'igz-controls/images/delete.svg?react' import DownloadIcon from 'igz-controls/images/download.svg?react' import HistoryIcon from 'igz-controls/images/history.svg?react' @@ -125,8 +119,9 @@ export const generateActionsMenu = ( isDetailsPopUp = false ) => { const isTargetPathValid = getIsTargetPathValid(llmPromptMin ?? {}, frontendSpec) - const llmPromptDataCouldBeDeleted = - llmPromptMin?.target_path?.endsWith('.pq') || llmPromptMin?.target_path?.endsWith('.parquet') + //TODO: uncomment when MEP delete will be implemented + // const llmPromptDataCouldBeDeleted = + // llmPromptMin?.target_path?.endsWith('.pq') || llmPromptMin?.target_path?.endsWith('.parquet') const getFullLLMPrompt = llmPromptMin => { return chooseOrFetchArtifact(dispatch, LLM_PROMPTS_PAGE, null, selectedLLMPrompt, llmPromptMin) @@ -177,66 +172,67 @@ export const generateActionsMenu = ( label: 'View YAML', icon: , onClick: llmPromptMin => getFullLLMPrompt(llmPromptMin).then(toggleConvertedYaml) - }, - { - label: 'Delete', - icon: , - hidden: isDetailsPopUp, - className: 'danger', - onClick: () => - llmPromptDataCouldBeDeleted - ? openPopUp(DeleteArtifactPopUp, { - artifact: llmPromptMin, - artifactType: LLM_PROMPT_TYPE, - category: LLM_PROMPT_TYPE, - filters: llmPromptsFilters, - refreshArtifacts, - refreshAfterDeleteCallback - }) - : openDeleteConfirmPopUp( - 'Delete LLM Prompt?', - `Do you want to delete the LLM Prompt "${llmPromptMin.db_key}"? Deleted LLM Prompt can not be restored.`, - () => { - handleDeleteArtifact( - dispatch, - projectName, - llmPromptMin.db_key, - llmPromptMin.uid, - refreshArtifacts, - refreshAfterDeleteCallback, - llmPromptsFilters, - LLM_PROMPT_TYPE - ) - } - ), - allowLeaveWarning: true - }, - { - label: 'Delete all versions', - icon: , - hidden: isDetailsPopUp || isAllVersions, - className: 'danger', - onClick: () => - openDeleteConfirmPopUp( - 'Delete LLM Prompt?', - `Do you want to delete all versions of the LLM Prompt "${llmPromptMin.db_key}"? Deleted LLM prompt can not be restored.`, - () => { - handleDeleteArtifact( - dispatch, - projectName, - llmPromptMin.db_key, - llmPromptMin.uid, - refreshArtifacts, - refreshAfterDeleteCallback, - llmPromptsFilters, - LLM_PROMPT_TYPE, - LLM_PROMPT_TYPE, - true - ) - } - ), - allowLeaveWarning: true } + //TODO: uncomment when MEP delete will be implemented + // { + // label: 'Delete', + // icon: , + // hidden: isDetailsPopUp, + // className: 'danger', + // onClick: () => + // llmPromptDataCouldBeDeleted + // ? openPopUp(DeleteArtifactPopUp, { + // artifact: llmPromptMin, + // artifactType: LLM_PROMPT_TYPE, + // category: LLM_PROMPT_TYPE, + // filters: llmPromptsFilters, + // refreshArtifacts, + // refreshAfterDeleteCallback + // }) + // : openDeleteConfirmPopUp( + // 'Delete LLM Prompt?', + // `Do you want to delete the LLM Prompt "${llmPromptMin.db_key}"? Deleted LLM Prompt can not be restored.`, + // () => { + // handleDeleteArtifact( + // dispatch, + // projectName, + // llmPromptMin.db_key, + // llmPromptMin.uid, + // refreshArtifacts, + // refreshAfterDeleteCallback, + // llmPromptsFilters, + // LLM_PROMPT_TYPE + // ) + // } + // ), + // allowLeaveWarning: true + // }, + // { + // label: 'Delete all versions', + // icon: , + // hidden: isDetailsPopUp || isAllVersions, + // className: 'danger', + // onClick: () => + // openDeleteConfirmPopUp( + // 'Delete LLM Prompt?', + // `Do you want to delete all versions of the LLM Prompt "${llmPromptMin.db_key}"? Deleted LLM prompt can not be restored.`, + // () => { + // handleDeleteArtifact( + // dispatch, + // projectName, + // llmPromptMin.db_key, + // llmPromptMin.uid, + // refreshArtifacts, + // refreshAfterDeleteCallback, + // llmPromptsFilters, + // LLM_PROMPT_TYPE, + // LLM_PROMPT_TYPE, + // true + // ) + // } + // ), + // allowLeaveWarning: true + // } ], [ { From 818901e71dfdcb4ab4acfe7bd794237ed809ed90 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Thu, 7 Aug 2025 18:55:43 +0300 Subject: [PATCH 099/228] Fix [LLM prompts] filter artifact by model name not functional (#3376) --- src/components/LLMPrompts/llmPrompts.util.jsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/LLMPrompts/llmPrompts.util.jsx b/src/components/LLMPrompts/llmPrompts.util.jsx index c51ac6da9f..579e439cd8 100644 --- a/src/components/LLMPrompts/llmPrompts.util.jsx +++ b/src/components/LLMPrompts/llmPrompts.util.jsx @@ -280,13 +280,11 @@ export const getFiltersConfig = isAllVersions => ({ [MODEL_NAME_FILTER]: { label: 'Model name:', initialValue: '', - isModal: true, - hidden: isAllVersions + isModal: true }, [MODEL_TAG_FILTER]: { label: 'Model version tag:', initialValue: '', - isModal: true, - hidden: isAllVersions + isModal: true } }) From d64d28788b7ef6502fd12beff773afd7e3ee32b3 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Sat, 9 Aug 2025 17:12:04 +0300 Subject: [PATCH 100/228] Fix [Alerts] Counters aren't displayed if request fails (#3378) --- src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index 5d72313b2c..40ea3848db 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -21,6 +21,7 @@ import React, { useMemo, useRef, useState } from 'react' import classNames from 'classnames' import { useNavigate, useParams } from 'react-router-dom' import { useSelector } from 'react-redux' +import { defaults } from 'lodash' import { Loader, PopUpDialog } from 'igz-controls/components' import StatsCard from '../../common/StatsCard/StatsCard' @@ -77,7 +78,7 @@ const AlertsCounters = () => { return { projectName, - data: projectStore.jobsMonitoringData.alerts || defaultAlertData + data: defaults({}, projectStore.jobsMonitoringData.alerts, defaultAlertData) } }, [ paramProjectName, From 61a8c79acc03206ac281820cd40b6221917f06cc Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Mon, 11 Aug 2025 12:52:19 +0300 Subject: [PATCH 101/228] Fix [Counters] styling by Figma (#3377) --- src/common/StatsCard/statsCard.scss | 8 ++------ src/components/Project/project.scss | 13 ++++++------- src/elements/ProjectDataCard/ProjectDataCard.jsx | 4 ++-- .../ProjectStatistics/projectStatistics.scss | 6 +++--- .../projectsMonitoringCounters.scss | 15 +++++++++++---- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/common/StatsCard/statsCard.scss b/src/common/StatsCard/statsCard.scss index 0cf65f04bc..b1042245b6 100644 --- a/src/common/StatsCard/statsCard.scss +++ b/src/common/StatsCard/statsCard.scss @@ -46,14 +46,10 @@ align-items: center; margin: 0; color: colors.$primary; - font-weight: normal; - font-size: 1rem; + font-weight: 500; + font-size: 1.25em; transition: font-size 0.3s ease-in-out; - @media screen and (min-width: 1600px) { - font-size: 1.25rem; - } - &_with-icon { padding-left: 18px; diff --git a/src/components/Project/project.scss b/src/components/Project/project.scss index 42deab7d87..72f112f607 100644 --- a/src/components/Project/project.scss +++ b/src/components/Project/project.scss @@ -22,6 +22,7 @@ flex: 1; padding: 24px 40px; background-color: colors.$white; + font-size: 12px; .general-info { display: flex; @@ -168,12 +169,9 @@ justify-content: space-between; margin-bottom: 16px; color: colors.$primary; - font-size: 1.25rem; + font-size: 1.25em; + font-weight: 500; line-height: 23px; - - @media screen and (min-width: 1600px) { - font-size: 1.25rem; - } } &-info { @@ -200,7 +198,7 @@ } &.table-header { - min-height: 150px; + min-height: 110px; } } @@ -227,7 +225,8 @@ align-items: center; min-height: 40px; margin: 0 0 5px 0; - font-size: 18px; + font-size: 14px; + font-weight: 500; .text-sm { margin-left: 5px; diff --git a/src/elements/ProjectDataCard/ProjectDataCard.jsx b/src/elements/ProjectDataCard/ProjectDataCard.jsx index 68b807f222..dbf1af1256 100644 --- a/src/elements/ProjectDataCard/ProjectDataCard.jsx +++ b/src/elements/ProjectDataCard/ProjectDataCard.jsx @@ -46,7 +46,7 @@ const ProjectDataCard = ({
      - + {hasUpdateDate && ( diff --git a/src/elements/ProjectStatistics/projectStatistics.scss b/src/elements/ProjectStatistics/projectStatistics.scss index 40ebe80adf..f9ece16fc5 100644 --- a/src/elements/ProjectStatistics/projectStatistics.scss +++ b/src/elements/ProjectStatistics/projectStatistics.scss @@ -77,10 +77,10 @@ max-width: 100px; color: colors.$topaz; font-weight: 400; - font-size: 14px; + font-size: 12px; text-align: center; - i[class^="state-"] { + i[class^='state-'] { display: inline-block; width: 8px; height: 8px; @@ -90,7 +90,7 @@ &-value { width: 100%; - font-weight: 400; + font-weight: 500; font-size: 26px; line-height: 35px; text-align: center; diff --git a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss index c5eb913065..397ee580a7 100644 --- a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss +++ b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss @@ -32,7 +32,9 @@ border: 1px solid colors.$frenchLilac; &.alerts-card { - transition: background-color 0s, border-color 0s; + transition: + background-color 0s, + border-color 0s; } &.alerts-card_not-empty { @@ -50,14 +52,19 @@ margin: 0; color: colors.$topaz; font-weight: normal; - font-size: 14px; + font-size: 12px; + } + + &__counter { + font-size: 1.15em; + font-weight: 500; } &-card__row { flex: unset; margin-bottom: 0; font-weight: 400; - font-size: 14px; + font-size: 12px; & > * { position: relative; @@ -217,7 +224,7 @@ gap: 6px; align-items: center; color: colors.$topaz; - font-size: 14px; + font-size: 12px; } } } From d549bc6662160f52eb507d15220e40208baf5b09 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 11 Aug 2025 15:20:23 +0300 Subject: [PATCH 102/228] Fix [LLM Prompts] just the first place prompt template place holder highlight "in blue" and clickable (#3379) --- .../DetailsPromptTemplate/PromptTab.jsx | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx index 0ec4f2faed..5aec8173af 100644 --- a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -44,31 +44,41 @@ const PromptTab = ({ const [forceExpandAll, setForceExpandAll] = useState(false) useEffect(() => { - if (Array.isArray(selectedItem.prompt_template)) { + if (!isEmpty(selectedItem.prompt_template)) { const legendMap = { ...selectedItem.prompt_legend } - const regex = new RegExp(`\\b(${Object.keys(legendMap).join('|')})\\b`, 'g') const jsxContent = selectedItem.prompt_template.map((item, idx) => { - const parts = item.content.split(regex).map((part, i) => { - if (legendMap[part]) { - const currentArgument = legendMap[part] + const parts = item.content.split(/(\{[^}]+})/g).map((part, i) => { + const match = part.match(/^\{([^}]+)}$/) + + if (match) { + const argName = match[1] + const currentArgument = legendMap[argName] + + if (currentArgument) { + return ( + } + textShow + > + { + setSelectedArgument(currentArgument) + setSelectedTab(ARGUMENTS_TAB) + }} + > + {`{${argName}}`} + + + ) + } return ( - } - textShow - > - { - setSelectedArgument(currentArgument) - setSelectedTab(ARGUMENTS_TAB) - }} - > - {`{${part}}`} - - + + {`{${argName}}`} + ) } @@ -88,10 +98,10 @@ const PromptTab = ({ setPromptTemplate(jsxContent) } }, [ + selectedItem.prompt_template, selectedItem.prompt_legend, setSelectedArgument, - setSelectedTab, - selectedItem.prompt_template + setSelectedTab ]) useEffect(() => { From 15da13f40eee2d5dcec774bc5e61488aaaa2a6d6 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Tue, 12 Aug 2025 09:42:10 +0300 Subject: [PATCH 103/228] Fix [LLM prompts] Breadcrumb navigation does not include LLM prompts (#3380) --- src/common/Breadcrumbs/Breadcrumbs.jsx | 6 ++---- src/common/Breadcrumbs/breadcrumbs.util.js | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/common/Breadcrumbs/Breadcrumbs.jsx b/src/common/Breadcrumbs/Breadcrumbs.jsx index f0ba997e75..44e48643a8 100644 --- a/src/common/Breadcrumbs/Breadcrumbs.jsx +++ b/src/common/Breadcrumbs/Breadcrumbs.jsx @@ -24,7 +24,6 @@ import { useSelector } from 'react-redux' import BreadcrumbsStep from './BreadcrumbsStep/BreadcrumbsStep' -import { useMode } from '../../hooks/mode.hook' import { generateMlrunScreens, generateTabsList } from './breadcrumbs.util' import { MONITORING_APP_PAGE, PROJECTS_PAGE_PATH } from '../../constants' import { generateProjectsList } from '../../utils/projects' @@ -35,7 +34,6 @@ const Breadcrumbs = ({ onClick = () => {} }) => { const [searchValue, setSearchValue] = useState('') const [showScreensList, setShowScreensList] = useState(false) const [showProjectsList, setShowProjectsList] = useState(false) - const { isDemoMode } = useMode() const breadcrumbsRef = useRef() const params = useParams() const location = useLocation() @@ -47,8 +45,8 @@ const Breadcrumbs = ({ onClick = () => {} }) => { }, [projectStore.projectsNames.data]) const mlrunScreens = useMemo(() => { - return generateMlrunScreens(params, isDemoMode) - }, [isDemoMode, params]) + return generateMlrunScreens(params) + }, [params]) const projectTabs = useMemo(() => { return generateTabsList() }, []) diff --git a/src/common/Breadcrumbs/breadcrumbs.util.js b/src/common/Breadcrumbs/breadcrumbs.util.js index ae246f8151..2349ce1112 100644 --- a/src/common/Breadcrumbs/breadcrumbs.util.js +++ b/src/common/Breadcrumbs/breadcrumbs.util.js @@ -39,7 +39,7 @@ import { } from '../../constants' import { generateNuclioLink } from '../../utils' -export const generateMlrunScreens = (params, isDemo) => +export const generateMlrunScreens = params => params.projectName ? [ { @@ -54,7 +54,7 @@ export const generateMlrunScreens = (params, isDemo) => { label: 'Feature store', id: 'feature-store' }, { label: 'Datasets', id: 'datasets' }, { label: 'Documents', id: DOCUMENTS_PAGE }, - { label: 'LLM prompts', id: LLM_PROMPTS_PAGE, hidden: !isDemo }, + { label: 'LLM prompts', id: LLM_PROMPTS_PAGE }, { label: 'Artifacts', id: 'files' }, { label: 'Models', id: 'models' }, { label: 'Monitoring app', id: MONITORING_APP_PAGE }, From b822208cc841f73fe1c3e91ec04f1e6ef6680378 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Tue, 12 Aug 2025 10:12:54 +0300 Subject: [PATCH 104/228] Fix [Projects Monitoring] Titles formatting and filtering defaults (#3381) --- src/components/Project/ProjectMonitor.jsx | 17 ++++- src/components/Project/project.utils.jsx | 38 ++++++++++- .../ProjectDataCard/ProjectDataCard.jsx | 4 +- src/elements/ProjectJobs/ProjectJobs.jsx | 8 ++- .../AlertsCounters.jsx | 3 +- .../ApplicationCounters.jsx | 2 +- .../ArtifactsCounters.jsx | 4 +- .../ScheduledJobsCounters.jsx | 3 +- .../WorkflowsCounters.jsx | 3 +- src/utils/generateMonitoringData.js | 65 +++++++++++++++---- 10 files changed, 119 insertions(+), 28 deletions(-) diff --git a/src/components/Project/ProjectMonitor.jsx b/src/components/Project/ProjectMonitor.jsx index 245d2475e7..3fac52dd0f 100644 --- a/src/components/Project/ProjectMonitor.jsx +++ b/src/components/Project/ProjectMonitor.jsx @@ -52,6 +52,7 @@ import { removeNewFeatureSet } from '../../reducers/featureStoreReducer' import { setNotification } from 'igz-controls/reducers/notificationReducer' import { showErrorNotification } from 'igz-controls/utils/notification.util' import { useNuclioMode } from '../../hooks/nuclioMode.hook' +import { useMode } from '../../hooks/mode.hook' const ProjectMonitor = () => { const [createFeatureSetPanelIsOpen, setCreateFeatureSetPanelIsOpen] = useState(false) @@ -62,6 +63,7 @@ const ProjectMonitor = () => { const params = useParams() const dispatch = useDispatch() const { isNuclioModeDisabled } = useNuclioMode() + const { isDemoMode } = useMode() const projectAbortControllerRef = useRef(new AbortController()) const projectSummariesAbortControllerRef = useRef(new AbortController()) const v3ioStreamsAbortControllerRef = useRef(new AbortController()) @@ -86,6 +88,13 @@ const ProjectMonitor = () => { [frontendSpec] ) + const openRegisterModelModal = useCallback(() => { + openPopUp(RegisterModelModal, { + params: params, + refresh: () => navigate(registerArtifactLink(MODEL_TYPE)) + }) + }, [params, navigate, registerArtifactLink]) + const openRegisterArtifactModal = useCallback( artifactKind => { openPopUp(RegisterArtifactModal, { @@ -103,13 +112,17 @@ const ProjectMonitor = () => { params, openRegisterArtifactModal, generateNuclioLink, - openPopUp + openPopUp, + openRegisterModelModal, + setCreateFeatureSetPanelIsOpen, + setIsNewFunctionPopUpOpen, + isDemoMode ) return { createNewOptions } - }, [navigate, params, openRegisterArtifactModal]) + }, [navigate, params, openRegisterArtifactModal, openRegisterModelModal, isDemoMode]) const fetchProjectDataAndSummary = useCallback(() => { projectAbortControllerRef.current = new AbortController() diff --git a/src/components/Project/project.utils.jsx b/src/components/Project/project.utils.jsx index c8f2c8f42f..c9c891e438 100644 --- a/src/components/Project/project.utils.jsx +++ b/src/components/Project/project.utils.jsx @@ -52,7 +52,11 @@ export const generateCreateNewOptions = ( params, openRegisterArtifactModal, generateNuclioLink, - openPopUp + openPopUp, + openRegisterModelModal, + setCreateFeatureSetsPanelIsOpen, + setIsNewFunctionPopUpOpen, + isDemoMode ) => [ { label: 'Register dataset', @@ -111,6 +115,38 @@ export const generateCreateNewOptions = ( icon: , handler: () => window.open(generateNuclioLink(`/projects/${params.projectName}/create-function`), '_blank') + }, + { + label: 'Register model', + id: 'registerModel', + handler: () => { + openRegisterModelModal() + }, + hidden: !isDemoMode + }, + { + label: 'ML function', + id: 'mlFunction', + handler: () => { + setIsNewFunctionPopUpOpen(true) + }, + hidden: !isDemoMode + }, + { + label: 'Feature set', + id: 'featureSet', + handler: () => setCreateFeatureSetsPanelIsOpen(true), + hidden: !isDemoMode + }, + { + label: 'Create feature vector', + id: 'createFeatureVector', + handler: () => + navigate( + `/projects/${params.projectName}/feature-store/feature-vectors?openPanel=true`, + '_blank' + ), + hidden: !isDemoMode } ] diff --git a/src/elements/ProjectDataCard/ProjectDataCard.jsx b/src/elements/ProjectDataCard/ProjectDataCard.jsx index dbf1af1256..2cffa2c58a 100644 --- a/src/elements/ProjectDataCard/ProjectDataCard.jsx +++ b/src/elements/ProjectDataCard/ProjectDataCard.jsx @@ -32,6 +32,7 @@ import ClockIcon from 'igz-controls/images/clock.svg?react' const ProjectDataCard = ({ content, footerLinkText = 'See all', + headerLink = '', hasUpdateDate = false, href = '', link = '', @@ -52,7 +53,7 @@ const ProjectDataCard = ({ {title} ) : ( - {title} + {title} )} {tip && }
      @@ -100,6 +101,7 @@ const ProjectDataCard = ({ ProjectDataCard.propTypes = { content: PropTypes.object.isRequired, footerLinkText: PropTypes.string, + headerLink: PropTypes.string, hasUpdateDate: PropTypes.bool, href: PropTypes.string, link: PropTypes.string, diff --git a/src/elements/ProjectJobs/ProjectJobs.jsx b/src/elements/ProjectJobs/ProjectJobs.jsx index 33e8da8d7b..40ece40809 100644 --- a/src/elements/ProjectJobs/ProjectJobs.jsx +++ b/src/elements/ProjectJobs/ProjectJobs.jsx @@ -24,7 +24,9 @@ import moment from 'moment' import ProjectDataCard from '../ProjectDataCard/ProjectDataCard' -import { MONITOR_JOBS_TAB, REQUEST_CANCELED } from '../../constants' +import { DATES_FILTER, MONITOR_JOBS_TAB, REQUEST_CANCELED } from '../../constants' +import { PAST_24_HOUR_DATE_OPTION } from '../../utils/datePicker.util' + import { getJobsStatistics, getJobsTableData, groupByName, sortByDate } from './projectJobs.utils' import { fetchProjectJobs } from '../../reducers/projectReducer' @@ -71,7 +73,9 @@ const ProjectJobs = () => { { const { projectName: paramProjectName } = useParams() const navigate = useNavigate() const projectStore = useSelector(store => store.projectStore) - const timeLabel = paramProjectName ? '24 hrs' : 'Last 24 hrs' const handleOpenPopUp = () => { const isHidden = !detailsRef.current?.offsetParent @@ -105,7 +104,7 @@ const AlertsCounters = () => { } iconClass="stats-card__title-icon">
      - {timeLabel} + Last 24 hrs
      diff --git a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx index 679a13fb91..fe791a729f 100644 --- a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx @@ -76,7 +76,7 @@ const ApplicationCounter = () => { return (
      - +
      { className={data.llm_prompt.className} onClick={data.llm_prompt.link} > -
      LLM Prompts
      +
      LLM prompt artifacts
      {projectStore.projectsSummary.loading ? ( ) : ( @@ -149,7 +149,7 @@ const ArtifactsCounters = () => { className={data?.files?.className} onClick={data?.files?.link} > -
      Other Artifacts
      +
      Other artifacts
      {projectStore.projectsSummary.loading ? ( ) : ( diff --git a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx index afc24fd80f..e0b1c76166 100644 --- a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx @@ -38,7 +38,6 @@ const ScheduledJobsCounters = () => { const [showPopup, setShowPopup] = useState(false) const anchorRef = useRef(null) const detailsRef = useRef(null) - const timeLabel = projectName ? '24 hrs' : 'Next 24 hrs' const handleOpenPopUp = () => { const isHidden = !detailsRef.current?.offsetParent @@ -92,7 +91,7 @@ const ScheduledJobsCounters = () => {
      - {timeLabel} + Next 24 hrs
      diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index 75fe82f93e..367d617800 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -37,7 +37,6 @@ const WorkflowsCounters = () => { const { projectName } = useParams() const navigate = useNavigate() const projectStore = useSelector(store => store.projectStore) - const timeLabel = projectName ? '24 hrs' : 'Last 24 hrs' const handleOpenPopUp = () => { const isHidden = !detailsRef.current?.offsetParent @@ -95,7 +94,7 @@ const WorkflowsCounters = () => {
      - {timeLabel} + Next 24 hrs
      diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index c502b15fbc..b201eac5f2 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -35,10 +35,14 @@ import { STATUS_FILTER, TYPE_FILTER } from '../constants' -import { ANY_TIME_DATE_OPTION } from './datePicker.util' +import { + ANY_TIME_DATE_OPTION, + PAST_24_HOUR_DATE_OPTION, + NEXT_24_HOUR_DATE_OPTION +} from './datePicker.util' import classNames from 'classnames' -const IN_PROCESS = 'In Process' +const IN_PROCESS = 'In process' const FAILED = 'Failed' const SUCCEEDED = 'Succeeded' @@ -63,7 +67,11 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { ? { total: { counter: data.total || 0, - link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: [FILTER_ALL_ITEMS] }) + link: () => + navigateToJobsMonitoringPage({ + [STATUS_FILTER]: [FILTER_ALL_ITEMS], + [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION + }) }, counters: [ { @@ -82,7 +90,11 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { { counter: data.failed || 0, className: classNames('stats__link', 'stats__line'), - link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: [ERROR_STATE, 'aborted'] }), + link: () => + navigateToJobsMonitoringPage({ + [STATUS_FILTER]: [ERROR_STATE, 'aborted'], + [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION + }), statusClass: 'failed', tooltip: 'Aborted, Error', label: FAILED, @@ -93,7 +105,11 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { { counter: data.completed || 0, className: classNames('stats__link'), - link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['completed'] }), + link: () => + navigateToJobsMonitoringPage({ + [STATUS_FILTER]: ['completed'], + [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION + }), statusClass: 'completed', tooltip: 'Completed', label: SUCCEEDED, @@ -105,7 +121,11 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { ? { total: { counter: data.total || 0, - link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: [FILTER_ALL_ITEMS] }) + link: () => + navigateToJobsMonitoringPage({ + [STATUS_FILTER]: [FILTER_ALL_ITEMS], + [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION + }) }, counters: [ { @@ -125,7 +145,10 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { counter: data.failed || 0, className: classNames('stats__link', 'stats__line'), link: () => - navigateToJobsMonitoringPage({ [STATUS_FILTER]: [ERROR_STATE, FAILED_STATE] }), + navigateToJobsMonitoringPage({ + [STATUS_FILTER]: [ERROR_STATE, FAILED_STATE], + [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION + }), statusClass: 'failed', tooltip: 'Error, Failed', label: FAILED, @@ -136,7 +159,11 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { { counter: data.completed || 0, className: classNames('stats__link'), - link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['completed'] }), + link: () => + navigateToJobsMonitoringPage({ + [STATUS_FILTER]: ['completed'], + [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION + }), statusClass: 'completed', tooltip: 'Completed', label: SUCCEEDED, @@ -172,8 +199,8 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { list: [ { key: 'datasets', label: 'Datasets' }, { key: 'documents', label: 'Documents' }, - { key: 'llm_prompt', label: 'LLM Prompts' }, - { key: 'files', label: 'Other Artifacts' } + { key: 'llm_prompt', label: 'LLM prompt artifacts' }, + { key: 'files', label: 'Other artifacts' } ] } : tab === MODELS_PAGE @@ -215,15 +242,27 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { : { total: { counter: data.total || 0, - link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: FILTER_ALL_ITEMS }) + link: () => + navigateToJobsMonitoringPage({ + [TYPE_FILTER]: FILTER_ALL_ITEMS, + [DATES_FILTER]: NEXT_24_HOUR_DATE_OPTION + }) }, jobs: { counter: data.jobs || 0, - link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: JOB_KIND_JOB }) + link: () => + navigateToJobsMonitoringPage({ + [TYPE_FILTER]: JOB_KIND_JOB, + [DATES_FILTER]: NEXT_24_HOUR_DATE_OPTION + }) }, workflows: { counter: data.workflows || 0, - link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: JOB_KIND_WORKFLOW }) + link: () => + navigateToJobsMonitoringPage({ + [TYPE_FILTER]: JOB_KIND_WORKFLOW, + [DATES_FILTER]: NEXT_24_HOUR_DATE_OPTION + }) } } } From 907245336665a59e71309837487cbd1e492b3d74 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Wed, 13 Aug 2025 17:03:24 +0300 Subject: [PATCH 105/228] Fix [Workflows] "Terminate" workflow is missing on CE (#3382) --- src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx | 3 ++- src/components/Workflow/Workflow.jsx | 3 ++- src/elements/WorkflowsTable/WorkflowsTable.jsx | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx index 33b1c2881d..ba837dedfd 100644 --- a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx +++ b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx @@ -85,6 +85,7 @@ export const generateActionsMenu = ( jobs_dashboard_url, handleMonitoring, abortable_function_kinds, + ce, handleConfirmAbortJob, handleConfirmDeleteJob, handleConfirmTerminateWorkflow, @@ -168,7 +169,7 @@ export const generateActionsMenu = ( icon: , className: 'danger', onClick: handleConfirmTerminateWorkflow, - hidden: !accessibleProjectsMap[job?.project], + hidden: ce || !accessibleProjectsMap[job?.project], disabled: job?.state?.value !== FUNCTION_RUNNING_STATE } ] diff --git a/src/components/Workflow/Workflow.jsx b/src/components/Workflow/Workflow.jsx index f94a43b586..1cc16043ea 100644 --- a/src/components/Workflow/Workflow.jsx +++ b/src/components/Workflow/Workflow.jsx @@ -91,6 +91,7 @@ const Workflow = ({ const { isStagingMode } = useMode() const projectName = params.workflowProjectName || params.projectName const dispatch = useDispatch() + const ce = useSelector(store => store.appStore.frontendSpec?.ce?.version) const accessibleProjectsMap = useSelector(state => state.projectStore.accessibleProjectsMap) useEffect(() => { @@ -257,7 +258,7 @@ const Workflow = ({
      - {accessibleProjectsMap[projectName] && ( + {(ce || accessibleProjectsMap[projectName]) && (
      - }> - {header.value} - - {header.tip && } - + }> + {header.value} + + {header.tip && } +
      - {key === 'name' ? ( - body[key].href ? ( - - } - textShow={true} + return ( + !body[key].hidden && + (key === 'type' ? ( + + ) : ( + + {key === 'name' ? ( + body[key].href ? ( + - {extractedItemName} - - - ) : body[key].link ? ( - + } + textShow={true} + > + {extractedItemName} + + + ) : body[key].link ? ( + + }> + {body[key].value} + + + ) : ( }> {body[key].value} - + ) + ) : key === 'labels' ? ( + + ) : key === 'status' ? ( + <> + {Array.isArray(body.status.value) ? ( + body.status.value.map((status, index) => { + return ( + } + > + + + ) + }) + ) : ( + + } + > + {body[key].value} + + )} + ) : ( - }> - {body[key].value} - - ) - ) : key === 'labels' ? ( - - ) : key === 'status' ? ( - <> - {Array.isArray(body.status.value) ? ( - body.status.value.map((status, index) => { - return ( - } - > - - - ) - }) - ) : ( - }> - {body[key].value} - - )} - - ) : ( - <> - - } - > - {body[key].value} - - {body[key].status && ( + <> } + template={ + + } > - + {body[key].value} - )} - - )} - - {parsedUri?.key && (parsedUri?.uid || parsedUri.tree) && ( -
      -
      handleOpenArtifactPopUp()}> - } textShow> - {parsedUri.key} - -
      +
      + {parsedUri?.key && (parsedUri?.uid || parsedUri.tree) && ( +
      +
      handleOpenArtifactPopUp()}> + } textShow> + {parsedUri.key} + + {parsedUri.tag}
      - )} - {parsedUri?.key && !parsedUri?.uid && !parsedUri.tree && ( +
      + )} + {parsedUri?.key && !parsedUri?.uid && !parsedUri.tree && ( + <> }>{parsedUri.key} - )} -
      getCloseDetailsLink(params.jobName || (params.projectName ? MONITOR_JOBS_TAB : JOBS_MONITORING_JOBS_TAB))} + getCloseDetailsLink={() => + getCloseDetailsLink( + params.jobName || + (params.projectName ? MONITOR_JOBS_TAB : JOBS_MONITORING_JOBS_TAB) + ) + } handleCancel={() => setSelectedJob({})} pageData={pageData} selectedItem={selectedJob} diff --git a/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx b/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx index 9766799346..871639105c 100644 --- a/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx +++ b/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx @@ -250,7 +250,8 @@ const ScheduledJobsTable = ({ defaultData: jobWizardMode === PANEL_EDIT_MODE ? editableItem?.scheduled_object : {}, mode: jobWizardMode, wizardTitle: jobWizardMode === PANEL_EDIT_MODE ? 'Edit job' : undefined, - onSuccessRequest: refreshJobsWithFilters + onSuccessRequest: refreshJobsWithFilters, + isCrossProjects: !params.projectName }) setJobWizardIsOpened(true) From ae59b69014c61c500dfe8bb4d1a7f509e3d9c584 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Sun, 17 Aug 2025 09:18:30 +0300 Subject: [PATCH 109/228] Fix [Vite] Dev tools doesn't show css file names (#3387) --- vite.config.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vite.config.mjs b/vite.config.mjs index 184bd5f070..20b71de28d 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -84,8 +84,10 @@ export default defineConfig(({ mode }) => { chunkSizeWarningLimit: 3000 }, css: { + devSourcemap: true, preprocessorOptions: { scss: { + sourceMap: true, api: 'modern' } } From f9143fd4ff2c8e9d85d4ee6adfb98087370813dd Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:55:59 +0300 Subject: [PATCH 110/228] Fix [UI] Unexpected application error on Alerts tab in Model endpoint details (#3388) --- src/utils/getNoDataMessage.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/getNoDataMessage.js b/src/utils/getNoDataMessage.js index 01be4118cd..f6eb6af3b3 100644 --- a/src/utils/getNoDataMessage.js +++ b/src/utils/getNoDataMessage.js @@ -162,13 +162,13 @@ const getSelectedDateValue = (filterType, filters) => { true, true, '/', - filters[DATES_FILTER].value[0] ?? new Date(), - filters[DATES_FILTER].value[1] ?? new Date() + filters[DATES_FILTER]?.value?.[0] ?? new Date(), + filters[DATES_FILTER]?.value?.[1] ?? new Date() ) return (filterType === DATE_RANGE_TIME_FILTER && - !isEqual(filters[DATES_FILTER].value, DATE_FILTER_ANY_TIME)) || - (filterType === DATES_FILTER && !isEqual(filters[DATES_FILTER].value, DATE_FILTER_ANY_TIME)) + !isEqual(filters[DATES_FILTER]?.value, DATE_FILTER_ANY_TIME)) || + (filterType === DATES_FILTER && !isEqual(filters[DATES_FILTER]?.value, DATE_FILTER_ANY_TIME)) ? date : ANY_TIME } From c2756586467672ca4c6e02770e0873449f173247 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 19 Aug 2025 09:03:38 +0300 Subject: [PATCH 111/228] Fix [Monitoring app] Incorrect Chart date calculation and missing "No Data" message in Monitoring App (#3389) --- .../MEPsWithDetections.jsx | 2 +- .../monitoringApplications.util.js | 43 +++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx index 1115990c5f..9be57e4ecb 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx @@ -132,7 +132,7 @@ const MEPsWithDetections = () => { Model Endpoints with suspected/detected issue - {endpointsWithDetectionsData?.length === 0 && !(isLoading || loading) ? ( + {endpointsWithDetectionsData.values?.length === 0 && !(isLoading || loading) ? ( ) : (
      diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js index ced25135c2..68c25e7756 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js @@ -86,7 +86,7 @@ export function groupDataToBins(data, startTime, endTime) { const HOUR = 'hour' const MINUTES = 'minutes' // "minutes" represents 10 minutes const timeDiffInHours = (new Date(endTime) - new Date(startTime) - allowedDeviation) / (1000 * 60 * 60) - const basePeriod = timeDiffInHours > 72 ? DAY : timeDiffInHours > 6 ? HOUR : MINUTES + const basePeriod = timeDiffInHours > 72 ? DAY : timeDiffInHours > 6 ? HOUR : MINUTES const roundDate = date => { const dateToRound = new Date(date) @@ -112,7 +112,7 @@ export function groupDataToBins(data, startTime, endTime) { } else { period.setDate(period.getDate() + 1) } - + return period } // generate bins @@ -121,16 +121,22 @@ export function groupDataToBins(data, startTime, endTime) { } data.forEach(([timestamp, value]) => { - const date = roundDate(timestamp) - const dateKey = date.toISOString() + const timestampDate = new Date(timestamp) + + // ignore potential data beyond selected time range + if (timestampDate >= startTime && timestampDate <= endTime) { + const date = roundDate(timestamp) + const dateKey = date.toISOString() - grouped.set(dateKey, grouped.get(dateKey) + value) + grouped.set(dateKey, grouped.get(dateKey) + value) + } }) const getLabel = (from, to) => { const fromDate = moment(from) const toDate = moment(to || from) - const shortFormatString = basePeriod === MINUTES ? 'hh:mm A' : basePeriod === HOUR ? 'MM/DD, hh:mm A' : 'MM/DD/YY' + const shortFormatString = + basePeriod === MINUTES ? 'hh:mm A' : basePeriod === HOUR ? 'MM/DD, hh:mm A' : 'MM/DD/YY' const fullFormatString = 'MM/DD/YY, hh:mm A' if (!to) { @@ -144,20 +150,23 @@ export function groupDataToBins(data, startTime, endTime) { } const groupedData = Array.from(grouped.entries()) - const dataset = groupedData.reduce((dataset, [date, value], index) => { - if (index === 0) { - // cut the first bin if it is not full - if (startTime > new Date(date)) return dataset - } + const dataset = groupedData.reduce( + (dataset, [date, value], index) => { + if (index === 0) { + // cut the first bin if it is not full + if (startTime > new Date(date)) return dataset + } - const labelData = getLabel(date) + const labelData = getLabel(date) - dataset.values.push(value) - dataset.labels.push(labelData.label) - dataset.dates.push(labelData.fullDate) + dataset.values.push(value) + dataset.labels.push(labelData.label) + dataset.dates.push(labelData.fullDate) - return dataset - }, {values: [], labels: [], dates: []}) + return dataset + }, + { values: [], labels: [], dates: [] } + ) // cut the last bin if it is not full if (dataset.values.length && endTime > new Date(groupedData[groupedData.length - 1][0])) { From da321a181647aebc2a2d9007918a145d220228f1 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 19 Aug 2025 09:42:59 +0300 Subject: [PATCH 112/228] Fix [Monitoring app] Function name should not be in the lowercase (#3390) --- src/reducers/monitoringApplicationsReducer.js | 2 +- src/utils/createApplicationContent.jsx | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/reducers/monitoringApplicationsReducer.js b/src/reducers/monitoringApplicationsReducer.js index aa3f41c43b..b2a0fd8554 100644 --- a/src/reducers/monitoringApplicationsReducer.js +++ b/src/reducers/monitoringApplicationsReducer.js @@ -83,7 +83,7 @@ export const fetchMonitoringApplication = createAsyncThunk( } return monitoringApplicationsApi - .getMonitoringApplication(project, functionName.toLowerCase(), params) + .getMonitoringApplication(project, functionName, params) .then(response => response.data) } ) diff --git a/src/utils/createApplicationContent.jsx b/src/utils/createApplicationContent.jsx index 3f255bad6b..26cfe6c7e6 100644 --- a/src/utils/createApplicationContent.jsx +++ b/src/utils/createApplicationContent.jsx @@ -25,6 +25,10 @@ import { generateNuclioLink } from './parseUri' export const createApplicationContent = (application, projectName) => { const identifierUnique = 'identifierUnique.' + application.name + application.application_class + // If the Nuclio function name is generated by Mlrun, it follows the structure bellow + // and is limited to 63 characters + const nuclioFunctionName = `${projectName}-${application.name.toLowerCase()}`.slice(0, 63) + return { data: { ...application, @@ -39,7 +43,7 @@ export const createApplicationContent = (application, projectName) => { id: `key.${identifierUnique}`, headerId: 'name', headerLabel: 'Name', - value: capitalize(application.name), + value: application.name, className: 'table-cell-name', getLink: () => application.name }, @@ -94,7 +98,8 @@ export const createApplicationContent = (application, projectName) => { headerLabel: 'Nuclio function', value: application.name, className: 'table-cell-2', - getLink: () => generateNuclioLink(`/projects/${projectName}/functions/${application.name}`), + getLink: () => + generateNuclioLink(`/projects/${projectName}/functions/${nuclioFunctionName}`), showStatus: true } ] From a9d2c12c4f214937698c43a8e1da930558309c8e Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Thu, 21 Aug 2025 08:41:18 +0300 Subject: [PATCH 113/228] Bump DRC version `3.1.7` (#3397) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 661b958bb5..6f0f6ab4df 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.6", + "iguazio.dashboard-react-controls": "3.1.7", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", From 69266f5cd74d636e893307485e5c808a1df0ccb6 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Thu, 21 Aug 2025 08:42:25 +0300 Subject: [PATCH 114/228] Fix [UI] Project created time in UTC time instead of local time zone (#3392) --- src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx index af33eb8266..c905c893a1 100644 --- a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx +++ b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx @@ -35,7 +35,7 @@ const ProjectDetailsHeader = ({ projectData, projectName }) => {
      Created: - {getDateAndTimeByFormat(projectData.metadata.created, ' MM/DD/YYYY, HH:mm:ss A')} + {getDateAndTimeByFormat(projectData.metadata.created + 'Z', ' MM/DD/YYYY, HH:mm:ss A')} {projectData.spec.owner && !frontendSpec.ce?.version && ( Owner: {projectData.spec.owner} From 1f2384fff467bee0c4abf5ec26480597637cb729 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Thu, 21 Aug 2025 08:42:51 +0300 Subject: [PATCH 115/228] Fix [Projects Monitoring] Titles formatting and filtering defaults (#3393) --- src/components/ProjectsPage/projects.util.jsx | 6 +++--- .../ProjectsMonitoringCounters/ApplicationCounters.jsx | 8 ++++---- .../ProjectsMonitoringCounters/WorkflowsCounters.jsx | 2 +- src/utils/generateMonitoringData.js | 5 +++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/components/ProjectsPage/projects.util.jsx b/src/components/ProjectsPage/projects.util.jsx index dc26e1abfd..a25d7a4c24 100644 --- a/src/components/ProjectsPage/projects.util.jsx +++ b/src/components/ProjectsPage/projects.util.jsx @@ -298,7 +298,7 @@ export const generateMonitoringCounters = (data, dispatch) => { }, monitoring_app: { total: 0, - succeeded: 0, + running: 0, failed: 0 }, artifacts: { @@ -343,10 +343,10 @@ export const generateMonitoringCounters = (data, dispatch) => { monitoringCounters.models.total += project.models_count || 0 - monitoringCounters.monitoring_app.succeeded += project.running_model_monitoring_functions || 0 + monitoringCounters.monitoring_app.running += project.running_model_monitoring_functions || 0 monitoringCounters.monitoring_app.failed += project.failed_model_monitoring_functions || 0 monitoringCounters.monitoring_app.total = - monitoringCounters.monitoring_app.failed + monitoringCounters.monitoring_app.succeeded + monitoringCounters.monitoring_app.failed + monitoringCounters.monitoring_app.running monitoringCounters.artifacts.llm_prompts += project.llm_prompts_count || 0 monitoringCounters.artifacts.datasets += project.datasets_count || 0 diff --git a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx index fe791a729f..bceaad251b 100644 --- a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx @@ -45,18 +45,18 @@ const ApplicationCounter = () => { const applicationData = useMemo(() => { if (projectName) { - const succeeded = projectStore.projectSummary.data?.running_model_monitoring_functions || 0 + const running = projectStore.projectSummary.data?.running_model_monitoring_functions || 0 const failed = projectStore.projectSummary.data?.failed_model_monitoring_functions || 0 return { - succeeded, + running, failed, - total: succeeded + failed + total: running + failed } } return ( projectStore.jobsMonitoringData?.monitoring_app || { - succeeded: 0, + running: 0, failed: 0, total: 0 } diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index 367d617800..d11aa45ad6 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -94,7 +94,7 @@ const WorkflowsCounters = () => {
      - Next 24 hrs + Last 24 hrs
      diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index b201eac5f2..6e61ef7527 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -45,6 +45,7 @@ import classNames from 'classnames' const IN_PROCESS = 'In process' const FAILED = 'Failed' const SUCCEEDED = 'Succeeded' +const RUNNING = 'Running' export const generateMonitoringStats = (data, navigate, tab, projectName) => { const linkClassNameDetails = (projectName, noLine) => @@ -220,11 +221,11 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }, counters: [ { - counter: data.succeeded || 0, + counter: data.running || 0, className: classNames('stats__counter', projectName && 'stats__link'), link: () => navigateToTab(projectName, MONITORING_APP_PAGE), statusClass: 'completed', - label: SUCCEEDED, + label: RUNNING, popUpClassName: classNames({ 'card-popup_text_link': projectName }) }, { From 97ebc2d81144707f6128fb1242d9ca6a3506dbbe Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Thu, 21 Aug 2025 11:03:10 +0300 Subject: [PATCH 116/228] Fix [General] Breadcrumbs are scrolled with the content (#3394) --- .../MonitoringApplicationsPage.jsx | 2 +- .../monitoringApplicationsPage.scss | 170 ++++---- src/components/Project/ProjectMonitorView.jsx | 6 +- src/components/Project/project.scss | 390 +++++++++--------- .../ProjectSettings/ProjectSettings.jsx | 6 +- .../ProjectSettings/projectSettings.scss | 58 +-- src/scss/main.scss | 4 +- 7 files changed, 299 insertions(+), 337 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index d1d5d56c53..168c4a917c 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -134,7 +134,7 @@ const MonitoringApplicationsPage = () => {
      -
      +
      {params.name && ( diff --git a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss index 51ab5ad6a8..db6aeb07b6 100644 --- a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss +++ b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss @@ -7,113 +7,111 @@ $applicationRowHeight: variables.$rowHeight; $applicationHeaderRowHeight: variables.$headerRowHeight; $applicationRowHeightExtended: variables.$rowHeightExtended; -.monitoring-apps-title { - color: colors.$primary; - font-weight: 400; - font-size: 2.1em; -} - -.content__action-bar-wrapper { - margin-bottom: 15px; -} - -.monitoring-apps { - flex: 1; -} - -.monitoring-app__section { - display: grid; - gap: 15px; - margin-bottom: 25px; - - &.section_small { - grid-template-columns: repeat(2, 1fr); - min-height: 200px; +.monitoring-app-content { + .monitoring-apps-title { + color: colors.$primary; + font-weight: 400; + font-size: 2.1em; } - &.section_big { - min-height: 300px; + .monitoring-apps { + flex: 1; } - .monitoring-app__section-item { - display: flex; - flex-direction: column; - padding: 20px; - color: colors.$topaz; - background-color: colors.$white; - border: 1px solid colors.$frenchLilac; - border-radius: 8px; - box-shadow: shadows.$previewBoxShadowInit; - transition: all 0.3s ease-in-out; - - .section-item_title { - display: flex; - align-items: center; - margin-bottom: 20px; - color: colors.$primary; - font-size: 1rem; - line-height: 23px; - } + .monitoring-app__section { + display: grid; + gap: 15px; + margin-bottom: 25px; - .section-table { - width: 100%; - height: auto; + &.section_small { + grid-template-columns: repeat(2, 1fr); + min-height: 200px; } - .applications-table { - @include mixins.rowsHeight( - $applicationHeaderRowHeight, - $applicationRowHeight, - $applicationRowHeightExtended - ); + &.section_big { + min-height: 300px; } - .section-item_chart-wrapper { - position: relative; - width: 100%; - height: 268px; + .monitoring-app__section-item { + display: flex; + flex-direction: column; + padding: 20px; + color: colors.$topaz; + background-color: colors.$white; + border: 1px solid colors.$frenchLilac; + border-radius: 8px; + box-shadow: shadows.$previewBoxShadowInit; + transition: all 0.3s ease-in-out; + + .section-item_title { + display: flex; + align-items: center; + margin-bottom: 20px; + color: colors.$primary; + font-size: 1rem; + line-height: 23px; + } - .section-item_chart { - position: absolute; - top: 0; - left: 0; + .section-table { width: 100%; - height: 100%; + height: auto; + } - .loader-wrapper { - position: absolute; - } + .applications-table { + @include mixins.rowsHeight( + $applicationHeaderRowHeight, + $applicationRowHeight, + $applicationRowHeightExtended + ); + } - .section-item_chart-area { + .section-item_chart-wrapper { + position: relative; + width: 100%; + height: 268px; + + .section-item_chart { + position: absolute; + top: 0; + left: 0; + width: 100%; height: 100%; - padding-bottom: 25px; - overflow-x: auto; - &_x-axis-label { + .loader-wrapper { position: absolute; - bottom: 10px; - left: 50%; - font-weight: 500; - font-size: 13px; - transform: translate(-50%, 0); - } - - &.loading { - visibility: hidden; } - .section-item_ml-chart-wrapper { - width: 100%; - min-width: 100%; + .section-item_chart-area { height: 100%; + padding-bottom: 25px; + overflow-x: auto; + + &_x-axis-label { + position: absolute; + bottom: 10px; + left: 50%; + font-weight: 500; + font-size: 13px; + transform: translate(-50%, 0); } - & > canvas#chart-y-axis { - position: absolute; - top: 0; - left: 0; - background-color: colors.$white; - pointer-events: none; + &.loading { + visibility: hidden; + } + + .section-item_ml-chart-wrapper { + width: 100%; + min-width: 100%; + height: 100%; + } + + & > canvas#chart-y-axis { + position: absolute; + top: 0; + left: 0; + background-color: colors.$white; + pointer-events: none; + } } } } diff --git a/src/components/Project/ProjectMonitorView.jsx b/src/components/Project/ProjectMonitorView.jsx index 1e818ed406..8b6752c047 100644 --- a/src/components/Project/ProjectMonitorView.jsx +++ b/src/components/Project/ProjectMonitorView.jsx @@ -62,8 +62,8 @@ const ProjectMonitorView = ({ showFunctionsPanel }) => { return ( -
      -
      +
      +
      {project.loading ? ( @@ -89,7 +89,7 @@ const ProjectMonitorView = ({ ) : isEmpty(project.data) ? ( ) : ( -
      +
      diff --git a/src/components/Project/project.scss b/src/components/Project/project.scss index 72f112f607..0e6c66ee56 100644 --- a/src/components/Project/project.scss +++ b/src/components/Project/project.scss @@ -2,289 +2,269 @@ @use 'igz-controls/scss/borders'; @use 'igz-controls/scss/shadows'; -.project { - &-wrapper { - display: flex; - flex: 1 1; - flex-direction: column; - min-width: 100%; - } - - &__header { - min-height: 70px; - padding: 20px 24px; - background-color: colors.$white; - box-shadow: shadows.$headerShadow; - } +.project-content { + padding: 24px 40px; - &__content { + .general-info { display: flex; flex: 1; - padding: 24px 40px; - background-color: colors.$white; - font-size: 12px; + flex-direction: column; + width: 250px; + padding-right: 64px; - .general-info { + &__row { display: flex; - flex: 1; - flex-direction: column; - width: 250px; - padding-right: 64px; - - &__row { - display: flex; - justify-content: space-between; - margin-top: 5px; - color: colors.$primary; + justify-content: space-between; + margin-top: 5px; + color: colors.$primary; - .row-label { - display: inline-block; - width: 80px; - } + .row-label { + display: inline-block; + width: 80px; + } - .row-action { - cursor: pointer; - } + .row-action { + cursor: pointer; + } - &.status-row { - .row-name { - text-transform: capitalize; - } + &.status-row { + .row-name { + text-transform: capitalize; } } + } - &__links { - display: flex; - flex-direction: column; - align-items: flex-start; + &__links { + display: flex; + flex-direction: column; + align-items: flex-start; - &-label { - margin-bottom: 16px; - color: colors.$primary; - } + &-label { + margin-bottom: 16px; + color: colors.$primary; + } - &-link { - margin-bottom: 15px; - } + &-link { + margin-bottom: 15px; } } + } - .project-details { - margin-bottom: 15px; - } + .project-details { + margin-bottom: 15px; + } - .main-info { + .main-info { + display: flex; + flex: 4; + flex-direction: column; + + &__toolbar { display: flex; - flex: 4; - flex-direction: column; + align-items: center; + justify-content: space-between; + margin-bottom: 15px; - &__toolbar { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 15px; + &-banner { + align-self: flex-end; + } - &-banner { - align-self: flex-end; + &-menu { + width: 155px; + + .select { + &__header { + cursor: pointer; + } } - &-menu { - width: 155px; + &.launch-menu { + display: none; + background-color: colors.$white; .select { - &__header { - cursor: pointer; + &__label { + color: colors.$primary; } } + } - &.launch-menu { - display: none; - background-color: colors.$white; + &.create-new-menu { + background-color: colors.$malibu; + border: none; - .select { - &__label { - color: colors.$primary; - } + .select { + &__label { + color: colors.$white; + text-transform: none; } } - &.create-new-menu { - background-color: colors.$malibu; - border: none; - - .select { - &__label { - color: colors.$white; - text-transform: none; - } - } - - svg { - path { - fill: colors.$white; - } + svg { + path { + fill: colors.$white; } } } + } - &-actions { - display: flex; - flex: 1; - align-items: center; - justify-content: flex-end; - } - - .refresh { - display: flex; - margin-left: 10px; - } + &-actions { + display: flex; + flex: 1; + align-items: center; + justify-content: flex-end; } - .project-data-card { - position: relative; + .refresh { display: flex; - flex: 1 0 0; - flex-direction: column; - min-width: 0; - min-height: 460px; - margin-right: 20px; - padding: 15px; - overflow-x: auto; - background-color: colors.$white; - border: borders.$dividerBorder; - border-radius: 8px; - box-shadow: shadows.$projectStatisticsShadow; + margin-left: 10px; + } + } - @media screen and (min-width: 1300px) { - padding: 20px; - } + .project-data-card { + position: relative; + display: flex; + flex: 1 0 0; + flex-direction: column; + min-width: 0; + min-height: 460px; + margin-right: 20px; + padding: 15px; + overflow-x: auto; + background-color: colors.$white; + border: borders.$dividerBorder; + border-radius: 8px; + box-shadow: shadows.$projectStatisticsShadow; + + @media screen and (min-width: 1300px) { + padding: 20px; + } - &__header { - z-index: 1; - min-width: fit-content; + &__header { + z-index: 1; + min-width: fit-content; - &-text { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 16px; - color: colors.$primary; - font-size: 1.25em; + &-text { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16px; + color: colors.$primary; + font-size: 1.25em; font-weight: 500; - line-height: 23px; - } + line-height: 23px; + } - &-info { - display: flex; - align-items: center; - color: colors.$topaz; - font-size: 12px; + &-info { + display: flex; + align-items: center; + color: colors.$topaz; + font-size: 12px; - &-icon { - flex: 0 1 12px; + &-icon { + flex: 0 1 12px; - & * { - fill: colors.$spunPearl; - } - } - - & *:not(:last-child) { - margin-right: 5px; + & * { + fill: colors.$spunPearl; } } - &-tip { - margin-left: 5px; + & *:not(:last-child) { + margin-right: 5px; } + } - &.table-header { - min-height: 110px; - } + &-tip { + margin-left: 5px; } - .no-data-block { - background-color: colors.$white; + &.table-header { + min-height: 110px; } + } - &_small { - .project-data-card__header { - height: 100%; + .no-data-block { + background-color: colors.$white; + } - &-text { - margin-bottom: 25px; - } + &_small { + .project-data-card__header { + height: 100%; + + &-text { + margin-bottom: 25px; } } + } - &__see-all-link { - margin: 25px 20px 0 auto; - } + &__see-all-link { + margin: 25px 20px 0 auto; + } - &__recent-text { - display: flex; - align-items: center; - min-height: 40px; - margin: 0 0 5px 0; - font-size: 14px; + &__recent-text { + display: flex; + align-items: center; + min-height: 40px; + margin: 0 0 5px 0; + font-size: 14px; font-weight: 500; - .text-sm { - margin-left: 5px; - font-size: 0.75em; - } - } - - &:last-child { - margin-right: 0; + .text-sm { + margin-left: 5px; + font-size: 0.75em; } } - .wrapper { - position: relative; - z-index: 1; - background-color: colors.$white; + &:last-child { + margin-right: 0; } + } - &__statistics-section { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 15px; - margin-bottom: 25px; + .wrapper { + position: relative; + z-index: 1; + background-color: colors.$white; + } - &_left { - display: flex; - gap: 15px; - } + &__statistics-section { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px; + margin-bottom: 25px; - &_right { - display: flex; - gap: 15px; - } + &_left { + display: flex; + gap: 15px; + } - .monitoring-stats { - flex: 1; - padding: 15px; + &_right { + display: flex; + gap: 15px; + } - @media screen and (min-width: 1300px) { - padding: 20px; - } + .monitoring-stats { + flex: 1; + padding: 15px; - &.alerts-card { - flex: 2; - } + @media screen and (min-width: 1300px) { + padding: 20px; } - @media (max-width: 1250px) { - grid-template-columns: repeat(1, 2fr); + &.alerts-card { + flex: 2; } } + + @media (max-width: 1250px) { + grid-template-columns: repeat(1, 2fr); + } } } +} - &__error-container { - margin: auto; - color: colors.$primary; - } +.project__error-container { + margin: auto; + color: colors.$primary; } main.unpinned { diff --git a/src/components/ProjectSettings/ProjectSettings.jsx b/src/components/ProjectSettings/ProjectSettings.jsx index 8d101c0574..a728678c98 100644 --- a/src/components/ProjectSettings/ProjectSettings.jsx +++ b/src/components/ProjectSettings/ProjectSettings.jsx @@ -285,11 +285,11 @@ const ProjectSettings = () => { {projectStore.projectsToDelete.includes(params.projectName) && } -
      -
      +
      +
      -
      +
      Date: Thu, 21 Aug 2025 11:13:37 +0300 Subject: [PATCH 117/228] Fix [Projects Setting] Redundant request for empty label data and invalid empty-key in Node Selector params (#3391) --- .../ProjectSettingsGeneral/ProjectSettingsGeneral.jsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.jsx b/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.jsx index adebb5e51b..19c21c1e6e 100644 --- a/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.jsx +++ b/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.jsx @@ -55,7 +55,8 @@ import { areFormValuesChanged, generateObjectFromKeyValue, parseObjectToKeyValue, - setFieldState + setFieldState, + clearArrayFromEmptyObjectElements } from 'igz-controls/utils/form.util' import { FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' import { getChipOptions } from 'igz-controls/utils/chips.util' @@ -214,7 +215,9 @@ const ProjectSettingsGeneral = ({ [DEFAULT_IMAGE]: formStateLocal.values[DEFAULT_IMAGE] ?? '', [DESCRIPTION]: formStateLocal.values[DESCRIPTION] ?? '', [GOALS]: formStateLocal.values[GOALS] ?? '', - [PARAMS]: generateObjectFromKeyValue(formStateLocal.values[PARAMS]) + [PARAMS]: generateObjectFromKeyValue( + clearArrayFromEmptyObjectElements(formStateLocal.values[PARAMS]) + ) }, metadata: { ...newProjectData.metadata, @@ -224,7 +227,7 @@ const ProjectSettingsGeneral = ({ if (areNodeSelectorsSupported) { newProjectData.spec[NODE_SELECTORS] = generateObjectFromKeyValue( - formStateLocal.values[NODE_SELECTORS] + clearArrayFromEmptyObjectElements(formStateLocal.values[NODE_SELECTORS]) ) } From 3812d3b0f9958c391d6abffc81c359c78884d91b Mon Sep 17 00:00:00 2001 From: adi-gini Date: Thu, 21 Aug 2025 14:20:44 +0300 Subject: [PATCH 118/228] Fix [Workflows] "Terminate" workflow is missing on CE (#3398) --- src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx index ba837dedfd..080020f8eb 100644 --- a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx +++ b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx @@ -169,7 +169,7 @@ export const generateActionsMenu = ( icon: , className: 'danger', onClick: handleConfirmTerminateWorkflow, - hidden: ce || !accessibleProjectsMap[job?.project], + hidden: !ce && !accessibleProjectsMap[job?.project], disabled: job?.state?.value !== FUNCTION_RUNNING_STATE } ] From ce4291771800ad25b1b116fe8a78550c5a60832a Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Wed, 27 Aug 2025 05:12:20 +0300 Subject: [PATCH 119/228] Fix [Counters] styling (#3386) --- src/common/StatsCard/StatsCard.jsx | 42 +++++++- src/common/StatsCard/statsCard.scss | 18 +++- .../MonitoringApplicationCard.jsx | 22 ++-- .../monitoringApplicationCounters.util.jsx | 26 ++--- src/components/Project/project.scss | 7 +- .../AlertsCounters.jsx | 34 +++--- .../ApplicationCounters.jsx | 30 +++--- .../ArtifactsCounters.jsx | 57 +++++----- .../ModelsCounters.jsx | 18 ++-- .../RunsCounters.jsx | 30 +++--- .../ScheduledJobsCounters.jsx | 32 +++--- .../WorkflowsCounters.jsx | 24 ++--- .../projectsMonitoringCounters.scss | 102 ++++++++---------- src/utils/generateMonitoringData.js | 14 +-- 14 files changed, 242 insertions(+), 214 deletions(-) diff --git a/src/common/StatsCard/StatsCard.jsx b/src/common/StatsCard/StatsCard.jsx index 73e7bbeca6..efb8bfcab2 100644 --- a/src/common/StatsCard/StatsCard.jsx +++ b/src/common/StatsCard/StatsCard.jsx @@ -25,9 +25,11 @@ import { TextTooltipTemplate, Tip, Tooltip } from 'igz-controls/components' import './statsCard.scss' -const StatsCard = ({ children, className = '', onClick = () => {} }) => { +const StatsCard = ({ children, className = '', onClick = () => { } }) => { + const cardClass = classNames('stats-card', className) + return ( -
      +
      {children}
      ) @@ -64,6 +66,31 @@ StatsCard.Col = ({ children }) => { } StatsCard.Col.displayName = 'StatsCard.Col' +StatsCard.MainCounter = ({ children, className = '', id = '', onClick = () => { } }) => { + const mainCounterClass = classNames('stats__counter_main', className) + + return ( +
      +
      + {children} +
      +
      + ) +} +StatsCard.MainCounter.displayName = 'StatsCard.MainCounter' + +StatsCard.SecondaryCounter = ({ children }) => { + return ( +
      +
      + {children} +
      +
      + ) +} +StatsCard.SecondaryCounter.displayName = 'StatsCard.SecondaryCounter' + + StatsCard.propTypes = { children: PropTypes.node.isRequired, className: PropTypes.string, @@ -86,4 +113,15 @@ StatsCard.Col.propTypes = { children: PropTypes.node } +StatsCard.MainCounter.propTypes = { + children: PropTypes.node.isRequired, + className: PropTypes.string, + id: PropTypes.string.isRequired, + onClick: PropTypes.func +} + +StatsCard.SecondaryCounter.propTypes = { + children: PropTypes.node.isRequired +} + export default StatsCard diff --git a/src/common/StatsCard/statsCard.scss b/src/common/StatsCard/statsCard.scss index b1042245b6..63158190fe 100644 --- a/src/common/StatsCard/statsCard.scss +++ b/src/common/StatsCard/statsCard.scss @@ -23,6 +23,7 @@ flex-flow: row nowrap; align-items: baseline; justify-content: space-between; + font-size: 12px; &:not(:last-child) { margin-bottom: 1em; @@ -45,6 +46,7 @@ gap: 6px; align-items: center; margin: 0; + padding-bottom: 1em; color: colors.$primary; font-weight: 500; font-size: 1.25em; @@ -60,7 +62,7 @@ &-icon { position: absolute; - top: 1px; + top: 0; left: 0; width: 16px; height: 16px; @@ -69,6 +71,7 @@ @media screen and (min-width: 1600px) { width: 20px; height: 20px; + top: -2px; } svg { @@ -90,5 +93,18 @@ display: flex; align-items: normal; } + + .stats__counter { + color: colors.$primary; + font-weight: 500; + + &_main { + font-size: 26px; + } + + &_secondary { + font-size: 15px; + } + } } } diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx index 807c18e6da..681e9c1087 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx @@ -47,18 +47,16 @@ const MonitoringApplicationCard = ({ hidden={!counter.tooltipText} template={} > -
      -
      - {loading ? ( - - ) : error || isNil(counter.title) ? ( - 'N/A' - ) : ( - counter.title - )} - {counter.status && } -
      -
      + + {loading ? ( + + ) : error || isNil(counter.title) ? ( + 'N/A' + ) : ( + counter.title + )} + {counter.status && } + {counter.subtitle && (
      const applicationsCountersContent = [ { - id: 'applications', + id: 'applicationsStatus', title: 'Applications', counterData: [ { + id: 'applications', title: monitoringApplicationError ? null : monitoringApplications.operatingFunctions.length + - monitoringApplications.applications.length + monitoringApplications.applications.length } ] }, @@ -62,7 +63,7 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => ] }, { - id: 'endpoints', + id: 'endpointsStatus', title: 'Endpoints', counterData: [ { @@ -78,10 +79,11 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => ] }, { - id: 'runningFrequency', + id: 'runningFrequencyStatus', title: 'Running interval', counterData: [ { + id: 'interval', title: monitoringApplicationError ? null : `Every ${formatMinutesToString(monitoringApplications.applications?.[0]?.base_period)}` @@ -149,13 +151,13 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => return params.name ? { - content: applicationCountersContent, - loading: monitoringApplicationIsLoading, - error: monitoringApplicationError - } + content: applicationCountersContent, + loading: monitoringApplicationIsLoading, + error: monitoringApplicationError + } : { - content: applicationsCountersContent, - loading: applicationsSummary.loading, - error: applicationsSummary.error - } + content: applicationsCountersContent, + loading: applicationsSummary.loading, + error: applicationsSummary.error + } } diff --git a/src/components/Project/project.scss b/src/components/Project/project.scss index 0e6c66ee56..205a878eb5 100644 --- a/src/components/Project/project.scss +++ b/src/components/Project/project.scss @@ -150,8 +150,8 @@ justify-content: space-between; margin-bottom: 16px; color: colors.$primary; - font-size: 1.25em; - font-weight: 500; + font-size: 1em; + font-weight: 500; line-height: 23px; } @@ -160,6 +160,7 @@ align-items: center; color: colors.$topaz; font-size: 12px; + font-weight: 400; &-icon { flex: 0 1 12px; @@ -207,7 +208,7 @@ min-height: 40px; margin: 0 0 5px 0; font-size: 14px; - font-weight: 500; + font-weight: 500; .text-sm { margin-left: 5px; diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index dd91b60864..e7e2233c1d 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -109,19 +109,17 @@ const AlertsCounters = () => {
      -
      -
      - {projectStore?.projectsSummary?.loading ? ( - - ) : ( - alertsData?.data?.total?.toLocaleString() - )} -
      -
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + alertsData?.data?.total?.toLocaleString() + )} +
      @@ -132,13 +130,13 @@ const AlertsCounters = () => { data-testid="alerts_endpoints_counter" >
      Endpoint
      -
      + {projectStore?.projectsSummary?.loading ? ( ) : ( alertsData?.data?.endpoint?.toLocaleString() )} -
      +
      @@ -148,29 +146,29 @@ const AlertsCounters = () => { onClick={alertsStats?.job?.link} >
      Jobs
      -
      + {projectStore?.projectsSummary?.loading ? ( ) : ( alertsData?.data?.jobs?.toLocaleString() )} -
      +
      Application
      -
      + {projectStore.projectsSummary.loading ? ( ) : ( alertsData?.data?.application?.toLocaleString() )} -
      +
      diff --git a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx index bceaad251b..fd3a48fbda 100644 --- a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx @@ -79,26 +79,24 @@ const ApplicationCounter = () => {
      -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - applicationStats?.total?.counter?.toLocaleString() - )} -
      -
      + {projectStore.projectsSummary.loading ? ( + + ) : ( + applicationStats?.total?.counter?.toLocaleString() + )} +
      {applicationStats.counters.map(({ counter, className, label, statusClass, link }) => ( -
      -
      + @@ -107,9 +105,9 @@ const ApplicationCounter = () => { ) : ( counter.toLocaleString() )} -
      -
      - {label} + +
      +
      {label}
      diff --git a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx index 983424f7c1..2207868ec6 100644 --- a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx @@ -82,15 +82,13 @@ const ArtifactsCounters = () => {
      -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - data?.total?.counter?.toLocaleString() - )} -
      -
      + + {projectStore.projectsSummary.loading ? ( + + ) : ( + data?.total?.counter?.toLocaleString() + )} +
      @@ -100,13 +98,13 @@ const ArtifactsCounters = () => { onClick={data?.datasets?.link} >
      Datasets
      -
      + {projectStore.projectsSummary.loading ? ( ) : ( -
      {data?.datasets.counter?.toLocaleString()}
      + data?.datasets.counter?.toLocaleString() )} -
      +
      @@ -116,15 +114,13 @@ const ArtifactsCounters = () => { onClick={data?.documents?.link} >
      Documents
      -
      + {projectStore.projectsSummary.loading ? ( ) : ( -
      - {data?.documents?.counter?.toLocaleString()} -
      + data?.documents?.counter?.toLocaleString() )} -
      +
      @@ -134,13 +130,13 @@ const ArtifactsCounters = () => { onClick={data.llm_prompt.link} >
      LLM prompt artifacts
      - {projectStore.projectsSummary.loading ? ( - - ) : ( -
      - {data?.llm_prompt?.counter?.toLocaleString()} -
      - )} + + {projectStore.projectsSummary.loading ? ( + + ) : ( + data?.llm_prompt?.counter?.toLocaleString() + )} +
      @@ -150,11 +146,14 @@ const ArtifactsCounters = () => { onClick={data?.files?.link} >
      Other artifacts
      - {projectStore.projectsSummary.loading ? ( - - ) : ( -
      {data?.files?.counter?.toLocaleString()}
      - )} + + {projectStore.projectsSummary.loading ? ( + + ) : ( + data?.files?.counter?.toLocaleString() + )} + +
      diff --git a/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx index 255c8be0e4..a5c8d143b7 100644 --- a/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx @@ -44,19 +44,17 @@ const ModelsAndApplication = () => { -
      -
      - {projectStore?.projectsSummary?.loading ? ( - - ) : ( - data?.models?.counter?.toLocaleString() - )} -
      -
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + data?.models?.counter?.toLocaleString() + )} +
      ) diff --git a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx index 4be9f0f323..fd158b6480 100644 --- a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx @@ -58,7 +58,7 @@ const RunCounter = () => {
      @@ -67,24 +67,20 @@ const RunCounter = () => {
      -
      -
      - {projectStore.projectsSummary.loading ? ( - - ) : ( - jobStats.total.counter.toLocaleString() - )} -
      -
      + + {projectStore.projectsSummary.loading ? ( + + ) : ( + jobStats.total.counter.toLocaleString() + )} +
      {jobStats?.counters?.map( - ({ counter, className, counterClassName, label, link, statusClass, tooltip }) => { + ({ counter, className, label, link, statusClass, tooltip }) => { return (
      {
      -
      + {projectStore?.projectsSummary?.loading ? ( ) : ( counter.toLocaleString() )} -
      +
      ) diff --git a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx index e0b1c76166..f376b6acc5 100644 --- a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx @@ -96,19 +96,13 @@ const ScheduledJobsCounters = () => {
      -
      -
      - {projectStore?.projectsSummary?.loading ? ( - - ) : ( - scheduledStats.total.counter - )} -
      -
      + + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + scheduledStats.total.counter + )} +
      @@ -118,29 +112,29 @@ const ScheduledJobsCounters = () => { data-testid="scheduled_jobs_counter" >
      Jobs
      -
      + {projectStore.projectsSummary.loading ? ( ) : ( scheduledStats.jobs.counter.toLocaleString() )} -
      +
      Workflows
      -
      + {projectStore.projectsSummary.loading ? ( ) : ( scheduledStats.workflows.counter.toLocaleString() )} -
      +
      @@ -165,7 +159,7 @@ const ScheduledJobsCounters = () => { )}
      - + ) } diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index d11aa45ad6..ff008cbc36 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -99,19 +99,17 @@ const WorkflowsCounters = () => {
      -
      -
      - {projectStore?.projectsSummary?.loading ? ( - - ) : ( - workflowsStats?.total?.counter?.toLocaleString() - )} -
      -
      + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + workflowsStats?.total?.counter?.toLocaleString() + )} +
      @@ -130,13 +128,13 @@ const WorkflowsCounters = () => {
      -
      + {projectStore?.projectsSummary?.loading ? ( ) : ( counter?.toLocaleString() )} -
      +
      ) diff --git a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss index 397ee580a7..d17333a1c3 100644 --- a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss +++ b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss @@ -55,41 +55,47 @@ font-size: 12px; } - &__counter { - font-size: 1.15em; - font-weight: 500; - } - &-card__row { flex: unset; margin-bottom: 0; font-weight: 400; - font-size: 12px; - - & > * { - position: relative; - display: flex; - justify-content: space-between; - width: 100%; - padding-bottom: 0.5rem; - color: colors.$primary; - } } &-large { min-height: 34px; } - &__counter_header { - font-weight: 600; - font-size: 26px; - } - &__details { - margin-top: 0.5em; + margin-top: 1rem; + + .stats-card__row { + margin-bottom: 0.5rem; + + .stats__line { + position: relative; + display: flex; + justify-content: space-between; + width: 100%; + padding-bottom: 0.5rem; + } + + &:not(:last-child) { + .stats__line { + &::after { + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 1px; + background-color: colors.$mulledWineThree; + content: ''; + } + } + } + } - & > * { - margin-bottom: 0.5em; + .stats__counter_main { + padding-bottom: 0; } @media (max-width: 1250px) { @@ -126,18 +132,6 @@ } } - &__line { - &::after { - position: absolute; - right: 0; - bottom: 0; - left: 0; - height: 1px; - background-color: colors.$mulledWineThree; - content: ''; - } - } - &__status { i[class^='state-'] { margin-left: 5px; @@ -171,10 +165,6 @@ } } - @media (max-width: 1250px) { - display: none; - } - .stats__subtitle { font-size: inherit; } @@ -192,7 +182,7 @@ .monitoring-stats.application-card { .stats { - &__counter_header { + &__counter_total { display: none; @media (max-width: 1250px) { @@ -200,6 +190,15 @@ } } + &__details { + margin: 0; + display: none; + + @media (min-width: 1250px) { + display: block; + } + } + &__container { display: flex; flex: 1; @@ -208,11 +207,6 @@ align-items: center; } - &__counter { - font-weight: 600; - font-size: 26px; - } - &__link { &:hover { @include counterLinkHover; @@ -286,6 +280,14 @@ main.unpinned { } } + .stats__counter_total { + display: none; + + @media (max-width: 1100px) { + display: flex; + } + } + .project-card__info { @media (max-width: 1250px) { display: flex; @@ -295,16 +297,6 @@ main.unpinned { display: none; } } - - &.application-card { - .stats__counter_header { - display: none; - - @media (max-width: 1100px) { - display: flex; - } - } - } } } } diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index 6e61ef7527..77e902f270 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -52,7 +52,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { classNames(!noLine && 'stats__line', projectName && 'stats__link') const linkClassNameHeader = projectName => - classNames('stats__counter_header', projectName && 'stats__link') + classNames(projectName && 'stats__link') const navigateToTab = (projectName, tab) => { projectName && navigate(`/projects/${projectName}/${tab}`) @@ -105,7 +105,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }, { counter: data.completed || 0, - className: classNames('stats__link'), + className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['completed'], @@ -159,7 +159,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }, { counter: data.completed || 0, - className: classNames('stats__link'), + className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: ['completed'], @@ -195,7 +195,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { files: { counter: data.files || 0, link: () => navigateToTab(projectName, 'files'), - className: linkClassNameDetails(projectName, true) + className: linkClassNameDetails(projectName) }, list: [ { key: 'datasets', label: 'Datasets' }, @@ -217,12 +217,12 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { total: { counter: data.total || 0, link: () => navigateToTab(projectName, MONITORING_APP_PAGE), - className: linkClassNameHeader(projectName) + className: `stats__counter_total ${linkClassNameHeader(projectName)}` }, counters: [ { counter: data.running || 0, - className: classNames('stats__counter', projectName && 'stats__link'), + className: classNames(projectName && 'stats__link'), link: () => navigateToTab(projectName, MONITORING_APP_PAGE), statusClass: 'completed', label: RUNNING, @@ -230,7 +230,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }, { counter: data.failed || 0, - className: classNames('stats__counter', projectName && 'stats__link', { + className: classNames(projectName && 'stats__link', { stats__failed: data.failed > 0 }), link: () => navigateToTab(projectName, MONITORING_APP_PAGE), From b990435e5ce69087eea4877b6649eef9b4400b37 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Wed, 27 Aug 2025 05:16:18 +0300 Subject: [PATCH 120/228] Fix [UI] Unexpected application error on Alerts tab in Model endpoint details (#3399) --- .../DetailsDrillDownAlert/DetailsAlertsMetrics.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.jsx b/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.jsx index 81e6c18606..7eea478bf7 100644 --- a/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.jsx +++ b/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.jsx @@ -112,10 +112,10 @@ const DetailsAlertsMetrics = ({ selectedItem, filters, isAlertsPage = true }) => if (!isAlertsPage) { if (filters?.dates?.initialSelectedOptionId === CUSTOM_RANGE_DATE_OPTION) { - params.start = filters?.dates.value[0].getTime() - params.end = filters?.dates.value[1].getTime() + params.start = filters?.dates?.value[0]?.getTime?.() + params.end = filters?.dates?.value[1]?.getTime?.() } else { - params.start = filters?.dates.value[0].getTime() + params.start = filters?.dates?.value[0]?.getTime?.() params.end = Date.now() } } From 9453cee757a96d204dc590bfcb0fcfeb27cb20c5 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:28:43 +0300 Subject: [PATCH 121/228] Fix [Counters] Add info icon to cross-project and project-screen (#3396) --- .../ProjectDetailsHeader.jsx | 6 +++++- src/components/Project/ProjectMonitorView.jsx | 3 --- src/components/Project/project.scss | 4 ---- .../ProjectsMonitoring/ProjectsMonitoring.jsx | 5 ++++- src/constants.js | 4 ++++ src/elements/PageHeader/PageHeader.jsx | 12 ++++++++---- src/elements/PageHeader/pageHeader.scss | 16 ++++++++++++++++ 7 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx index c905c893a1..72101a01fc 100644 --- a/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx +++ b/src/common/ProjectDetailsHeader/ProjectDetailsHeader.jsx @@ -21,8 +21,12 @@ import React from 'react' import PropTypes from 'prop-types' import { useSelector } from 'react-redux' +import PageHeader from '../../elements/PageHeader/PageHeader' + import { getDateAndTimeByFormat } from 'igz-controls/utils/datetime.util' +import { COUNTERS_GENERAL_MESSAGE } from '../../constants' + import './ProjectDetailsHeader.scss' const ProjectDetailsHeader = ({ projectData, projectName }) => { @@ -30,7 +34,7 @@ const ProjectDetailsHeader = ({ projectData, projectName }) => { return (
      -
      {projectName}
      + {projectData && (
      diff --git a/src/components/Project/ProjectMonitorView.jsx b/src/components/Project/ProjectMonitorView.jsx index 8b6752c047..308e8321f4 100644 --- a/src/components/Project/ProjectMonitorView.jsx +++ b/src/components/Project/ProjectMonitorView.jsx @@ -93,9 +93,6 @@ const ProjectMonitorView = ({
      -
      - Counters use a caching mechanism, and are not auto-refreshed. -
      diff --git a/src/elements/TableModelCell/tableModelCell.scss b/src/elements/TableModelCell/tableModelCell.scss new file mode 100644 index 0000000000..c004307b21 --- /dev/null +++ b/src/elements/TableModelCell/tableModelCell.scss @@ -0,0 +1,9 @@ +.model-name-wrapper { + display: flex; + flex-direction: column; + + .item-tag, + .model-name{ + align-self: baseline; + } +} \ No newline at end of file From accc470ad16722ab0aa925f2830d566ecd1c9b76 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Sun, 31 Aug 2025 09:59:38 +0300 Subject: [PATCH 129/228] Fix [LLM prompts] Make search and tabs row static (#3405) --- .../detailsPromptTemplate.scss | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss index 01904636c9..0c36e7a8e7 100644 --- a/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss +++ b/src/components/Details/DetailsPromptTemplate/detailsPromptTemplate.scss @@ -5,14 +5,18 @@ .prompt-tab { display: flex; flex-direction: column; - justify-content: center; align-items: center; + justify-content: center; &__header { + position: sticky; + top: 0; + left: 0; + z-index: 6; display: flex; align-items: center; width: 100%; - margin-top: 20px; + padding-top: 20px; padding-bottom: 10px; background-color: white; } @@ -21,8 +25,8 @@ display: flex; flex-direction: column; width: 100%; - margin-top: 8px; min-height: 300px; + margin-top: 8px; &-header { font-weight: bold; @@ -59,9 +63,9 @@ justify-content: space-between; width: 135px; padding: 11px 18px; + font-size: 14px; border: borders.$primaryBorder; border-radius: 4px; - font-size: 14px; cursor: pointer; &-wrapper { @@ -96,8 +100,8 @@ &-key { width: 150px; - font-weight: bold; padding-right: 10px; + font-weight: bold; } &-value { @@ -105,4 +109,4 @@ } } } -} \ No newline at end of file +} From 49fead5562de9d6bf4f881d27abbe10f194662d3 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 1 Sep 2025 16:00:58 +0300 Subject: [PATCH 130/228] Fix [LLM prompts] Redesign llm prompt detail view elements (#3411) --- src/common/ExpandableText/expandableText.scss | 3 +- .../DetailsGenerationConfiguration.jsx | 28 +++++++++++++------ .../detailsGenerationConfiguration.scss | 16 +++++++---- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/common/ExpandableText/expandableText.scss b/src/common/ExpandableText/expandableText.scss index 8616849e1c..5f5a1672ad 100644 --- a/src/common/ExpandableText/expandableText.scss +++ b/src/common/ExpandableText/expandableText.scss @@ -42,8 +42,7 @@ .see-less-button { background: none; border: none; - color: colors.$cornflowerBlueTwo; - font-weight: 500; + color: colors.$cornflowerBlue; font-size: 14px; cursor: pointer; padding: 0; diff --git a/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx b/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx index 919a4966ae..51335215cc 100644 --- a/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx +++ b/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx @@ -21,21 +21,31 @@ import React from 'react' import PropTypes from 'prop-types' import { isEmpty } from 'lodash' -import NoData from '../../../common/NoData/NoData' - import './detailsGenerationConfiguration.scss' const DetailsGenerationConfiguration = ({ selectedItem }) => { return (
      - {Object.entries(selectedItem.model_configuration || {}).map(([key, value]) => { - return ( -
      -
      {key}
      -
      {value}
      + {!isEmpty(selectedItem.model_configuration) && ( + <> +
      + {Object.entries(selectedItem.model_configuration || {}).length} modifications made to + the default configuration: +
      +
      +
      Key
      +
      Value
      - ) - })} + {Object.entries(selectedItem.model_configuration || {}).map(([key, value]) => { + return ( +
      +
      {key}
      +
      {value}
      +
      + ) + })} + + )} {isEmpty(selectedItem.model_configuration) && Default configuration is used.}
      ) diff --git a/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss b/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss index 4a7fbf0039..7794ba4e90 100644 --- a/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss +++ b/src/components/Details/DetailsGenerationConfiguration/detailsGenerationConfiguration.scss @@ -4,6 +4,14 @@ .generation-configuration-tab { margin-top: 15px; + &__counter { + margin-bottom: 20px; + } + + &__table-header { + font-weight: 500; + } + &__row { display: flex; padding: 10px 0; @@ -11,13 +19,9 @@ line-height: 20px; border-bottom: borders.$secondaryBorder; - &-key { - min-width: 150px; - font-weight: 500; - } - + &-key, &-value { - color: colors.$topaz; + width: 50%; } } } \ No newline at end of file From e4494e263cbf43371b96075520d120a2c8099e28 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Mon, 1 Sep 2025 16:01:48 +0300 Subject: [PATCH 131/228] Fix [Projects, Project monitoring] Incorrect data in tooltip for collapsed scheduled counters (#3410) --- .../ScheduledJobsCounters.jsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx index f376b6acc5..0bb0d3e39c 100644 --- a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx @@ -96,7 +96,11 @@ const ScheduledJobsCounters = () => {
      - + {projectStore?.projectsSummary?.loading ? ( ) : ( @@ -149,7 +153,7 @@ const ScheduledJobsCounters = () => { >
      - Runs: {scheduledStats.workflows.counter} + Jobs: {scheduledStats.jobs.counter}
      Workflows: {scheduledStats.workflows.counter} @@ -159,7 +163,7 @@ const ScheduledJobsCounters = () => { )}
      - + ) } From 4b207cee31258ee0d7d24686c621169e179c78a5 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Mon, 1 Sep 2025 16:58:15 +0300 Subject: [PATCH 132/228] Fix [Artifacts] Selected artifact shifts out of view after opening detail pane (#3400) --- package.json | 2 +- src/components/Alerts/Alerts.jsx | 7 +++++++ src/components/Artifacts/Artifacts.jsx | 7 +++++++ src/components/FunctionsPage/Functions.jsx | 7 +++++++ src/elements/JobsTable/JobsTable.jsx | 7 +++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f0f6ab4df..e418388322 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.7", + "iguazio.dashboard-react-controls": "3.1.8", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", diff --git a/src/components/Alerts/Alerts.jsx b/src/components/Alerts/Alerts.jsx index eb61454064..6324c2a856 100644 --- a/src/components/Alerts/Alerts.jsx +++ b/src/components/Alerts/Alerts.jsx @@ -41,6 +41,7 @@ import { getJobLogs } from '../../utils/getJobLogs.util' import { useAlertsPageData } from '../../hooks/useAlertsPageData' import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' import { removeProjects } from '../../reducers/projectReducer' +import { useTableScroll } from 'igz-controls/hooks/useTable.hook' const Alerts = () => { const [selectedAlert, setSelectedAlert] = useState({}) @@ -70,6 +71,12 @@ const Alerts = () => { setSearchParams } = useAlertsPageData(alertsFilters, true) + useTableScroll({ + content: paginatedAlerts, + selectedItem: selectedAlert, + isAllVersions: true + }) + const tableContent = useMemo(() => { return paginatedAlerts.map(alert => createAlertRowData(alert, isCrossProjects)) }, [isCrossProjects, paginatedAlerts]) diff --git a/src/components/Artifacts/Artifacts.jsx b/src/components/Artifacts/Artifacts.jsx index 25f91d6120..cc3a938a39 100644 --- a/src/components/Artifacts/Artifacts.jsx +++ b/src/components/Artifacts/Artifacts.jsx @@ -55,6 +55,7 @@ import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchPara import { useMode } from '../../hooks/mode.hook' import { usePagination } from '../../hooks/usePagination.hook' import { useRefreshAfterDelete } from '../../hooks/useRefreshAfterDelete.hook' +import { useTableScroll } from 'igz-controls/hooks/useTable.hook' const Artifacts = ({ actionButtons = [], @@ -391,6 +392,12 @@ const Artifacts = ({ resetPaginationTrigger: `${params.projectName}_${isAllVersions}` }) + useTableScroll({ + content: isAllVersions ? paginatedArtifactVersions : paginatedArtifacts, + selectedItem: selectedArtifact, + isAllVersions + }) + const tableContent = useMemo(() => { return (isAllVersions ? paginatedArtifactVersions : paginatedArtifacts).map(contentItem => createArtifactsRowData(contentItem, params.projectName, isAllVersions) diff --git a/src/components/FunctionsPage/Functions.jsx b/src/components/FunctionsPage/Functions.jsx index 932491593f..7afb6a6742 100644 --- a/src/components/FunctionsPage/Functions.jsx +++ b/src/components/FunctionsPage/Functions.jsx @@ -75,6 +75,7 @@ import { toggleYaml } from '../../reducers/appReducer' import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' import { useMode } from '../../hooks/mode.hook' import { usePagination } from '../../hooks/usePagination.hook' +import { useTableScroll } from 'igz-controls/hooks/useTable.hook' const Functions = ({ isAllVersions = false }) => { const [confirmData, setConfirmData] = useState(null) @@ -649,6 +650,12 @@ const Functions = ({ isAllVersions = false }) => { resetPaginationTrigger: `${params.projectName}_${isAllVersions}` }) + useTableScroll({ + content: isAllVersions ? paginatedFunctionVersions : paginatedFunctions, + selectedItem: selectedFunction, + isAllVersions + }) + const tableContent = useMemo( () => (isAllVersions ? paginatedFunctionVersions : paginatedFunctions).map(contentItem => diff --git a/src/elements/JobsTable/JobsTable.jsx b/src/elements/JobsTable/JobsTable.jsx index 96d6e716df..b370fec0ca 100644 --- a/src/elements/JobsTable/JobsTable.jsx +++ b/src/elements/JobsTable/JobsTable.jsx @@ -57,6 +57,7 @@ import { setNotification } from 'igz-controls/reducers/notificationReducer' import { toggleYaml } from '../../reducers/appReducer' import { usePods } from '../../hooks/usePods.hook' import { getInitialFiltersByConfig } from '../../hooks/useFiltersFromSearchParams.hook' +import { useTableScroll } from 'igz-controls/hooks/useTable.hook' import './jobsTable.scss' @@ -384,6 +385,12 @@ const JobsTable = React.forwardRef( } }, [lastCheckedJobIdRef, selectedJob]) + useTableScroll({ + content: paginatedJobs, + selectedItem: selectedJob, + isAllVersions: true + }) + return ( <> {jobsStore.loading && } From ddb4f79093959c8fe693405483488ce075c6d0df Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 2 Sep 2025 13:34:31 +0300 Subject: [PATCH 133/228] Fix [Monitoring app] Preselected metrics issues (#3412) --- .../ApplicationMetrics/ApplicationMetrics.jsx | 11 +- .../DetailsMetrics/DetailsMetrics.scss | 1 + .../ModelEndpoints/ModelEndpoints.jsx | 7 + src/reducers/detailsReducer.js | 11 +- tests/mockServer/data/metrics.json | 248 ++++++++- tests/mockServer/data/modelEndpoints.json | 520 ++++++++++++++++++ tests/mockServer/mock.js | 2 +- 7 files changed, 787 insertions(+), 13 deletions(-) diff --git a/src/components/ApplicationMetrics/ApplicationMetrics.jsx b/src/components/ApplicationMetrics/ApplicationMetrics.jsx index c989746b43..58472dd585 100644 --- a/src/components/ApplicationMetrics/ApplicationMetrics.jsx +++ b/src/components/ApplicationMetrics/ApplicationMetrics.jsx @@ -56,13 +56,14 @@ import { PRIMARY_BUTTON } from 'igz-controls/constants' import RefreshIcon from 'igz-controls/images/refresh.svg?react' import SearchIcon from 'igz-controls/images/search.svg?react' import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' - -import './ApplicationMetrics.scss' import { datePickerPastOptions, getDatePickerFilterValue, PAST_24_HOUR_DATE_OPTION } from '../../utils/datePicker.util' +import { clearMetricsOptions } from '../../reducers/detailsReducer' + +import './ApplicationMetrics.scss' export const LIST_ID = 'LIST_ID' export const LIST_ITEMS_ID = 'LIST_ITEMS_ID' @@ -230,6 +231,12 @@ const ApplicationMetrics = () => { } }, [dispatch, modelEndpoints, navigate, params.id, params.appName, params.projectName]) + useEffect(()=> { + return () => { + dispatch(clearMetricsOptions()) + } + }, [dispatch]) + return (
      diff --git a/src/components/DetailsMetrics/DetailsMetrics.scss b/src/components/DetailsMetrics/DetailsMetrics.scss index 8bf7e95a2a..a36bdcd10d 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.scss +++ b/src/components/DetailsMetrics/DetailsMetrics.scss @@ -10,6 +10,7 @@ $stickyHeaderHeight: 55px; z-index: 2; display: flex; justify-content: space-between; + background-color: colors.$white; &__custom-filters { display: flex; diff --git a/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx b/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx index 2ffa16ef07..15b39c1d91 100644 --- a/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx +++ b/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx @@ -44,6 +44,7 @@ import { getScssVariableValue } from 'igz-controls/utils/common.util' import { isDetailsTabExists } from '../../../utils/link-helper.util' import { isRowRendered, useVirtualization } from '../../../hooks/useVirtualization.hook' import { setFilters } from '../../../reducers/filtersReducer' +import { clearMetricsOptions } from '../../../reducers/detailsReducer' import { useFiltersFromSearchParams } from '../../../hooks/useFiltersFromSearchParams.hook' import { useInitialTableFetch } from '../../../hooks/useInitialTableFetch.hook' import { useModelsPage } from '../ModelsPage.context' @@ -191,6 +192,12 @@ const ModelEndpoints = () => { } }, [dispatch, params.projectName]) + useEffect(()=> { + return () => { + dispatch(clearMetricsOptions()) + } + }, [dispatch]) + useEffect(() => { if (params.name && modelEndpoints.length > 0) { const searchItem = modelEndpoints.find(item => item.metadata?.uid === params.tag) diff --git a/src/reducers/detailsReducer.js b/src/reducers/detailsReducer.js index 8cb57b79ba..1770702edd 100644 --- a/src/reducers/detailsReducer.js +++ b/src/reducers/detailsReducer.js @@ -104,7 +104,7 @@ export const fetchModelEndpointMetrics = createAsyncThunk( .then(({ data = [] }) => { const metrics = generateMetricsItems(data, applicationName) - return { endpointUid: uid, metrics } + return { endpointUid: uid, metrics, applicationName } }) .catch(error => thunkAPI.rejectWithValue(error)) } @@ -189,6 +189,14 @@ const detailsStoreSlice = createSlice({ decreaseDetailsLoadingCounter(state) { state.loadingCounter = state.loadingCounter - 1 }, + clearMetricsOptions(state) { + state.metricsOptions = { + all: [], + lastSelected: [], + preselected: [], + selectedByEndpoint: {} + } + } }, extraReducers: builder => { builder.addCase(fetchModelFeatureVector.pending, state => { @@ -289,6 +297,7 @@ export const { setSelectedMetricsOptions, increaseDetailsLoadingCounter, decreaseDetailsLoadingCounter, + clearMetricsOptions } = detailsStoreSlice.actions export default detailsStoreSlice.reducer diff --git a/tests/mockServer/data/metrics.json b/tests/mockServer/data/metrics.json index 6dc5f883fb..d10def30b8 100644 --- a/tests/mockServer/data/metrics.json +++ b/tests/mockServer/data/metrics.json @@ -12,23 +12,224 @@ "project": "default" }, { - "full_name": "default.histogram-data-drift-1.metric.tvdar_mean_1", + "full_name": "default.monitorAppV1.metric.tvdar_mean_1", "type": "metric", - "app": "histogram-data-drift-1", + "app": "monitorAppV1", "name": "tvdar_mean_1", "project": "default" }, { - "full_name": "default.histogram-data-drift-1.metric.tvdop_mean_1", + "full_name": "default.monitorAppV1.metric.tvdop_mean_1", "type": "metric", - "app": "histogram-data-drift-1", + "app": "monitorAppV1", "name": "tvdop_mean_1", "project": "default" }, { - "full_name": "default.histogram-data-drift-1.metric.tvds_mean_1", + "full_name": "default.monitorAppV1.metric.tvds_mean_1", "type": "metric", - "app": "histogram-data-drift-1", + "app": "monitorAppV1", + "name": "tvds_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV1.result.hellinger_mean_1", + "type": "result", + "app": "monitorAppV1", + "name": "hellinger_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV1.metric.data_drift_test_1", + "type": "metric", + "app": "monitorAppV1", + "name": "data_drift_test_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV1.metric.general_drift_1", + "type": "metric", + "app": "monitorAppV1", + "name": "general_drift_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV1.result.model_perf_1", + "type": "result", + "app": "monitorAppV1", + "name": "model_perf_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV2.metric.kld_mean_1", + "type": "metric", + "app": "monitorAppV2", + "name": "kld_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV2.metric.kld_mean_1", + "type": "metric", + "app": "monitorAppV2", + "name": "kld_mean_1", + "project": "default" + } + ], + "metricsValues": [ + { + "full_name": "default.rujmfi.result.data_drift_test", + "type": "result", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.hskoyl.result.data_drift_test", + "type": "result", + "data": "true", + "values": [ + 5 + ] + }, + { + "full_name": "default.mlrun-infra.metric.invocations-rate", + "type": "metric", + "data": "true", + "values": [ + 10, true + ] + }, + { + "full_name": "default.monitorAppV1.metric.tvdar_mean_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV1.metric.tvdop_mean_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV1.metric.tvds_mean_1", + "type": "metric", + "data": false + }, + { + "full_name": "default.monitorAppV1.result.hellinger_mean_1", + "type": "result", + "result_kind": 0, + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV1.metric.data_drift_test_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV1.metric.general_drift_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV1.result.model_perf_1", + "type": "result", + "result_kind": 1, + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV2.metric.kld_mean_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV2.metric.kld_mean_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + } + ] + }, + { + "modelEndpointUID": "a7c95783e6a726a1a233e581ea898ba44fa7e342", + "project": "default", + "metricsOptions": [ + { + "full_name": "default.mlrun-infra.metric.invocations-rate", + "type": "metric", + "app": "mlrun-infra", + "name": "invocations-rate", + "project": "default" + }, + { + "full_name": "default.monitorAppV1.metric.tvdar_mean_1", + "type": "metric", + "app": "monitorAppV1", + "name": "tvdar_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV2.metric.tvdar_mean_1", + "type": "metric", + "app": "monitorAppV2", + "name": "tvdar_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV3.metric.tvdar_mean_1", + "type": "metric", + "app": "monitorAppV3", + "name": "tvdar_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV1.metric.tvdop_mean_1", + "type": "metric", + "app": "monitorAppV1", + "name": "tvdop_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV2.metric.tvdop_mean_1", + "type": "metric", + "app": "monitorAppV2", + "name": "tvdop_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV1.metric.tvds_mean_1", + "type": "metric", + "app": "monitorAppV1", + "name": "tvds_mean_1", + "project": "default" + }, + { + "full_name": "default.monitorAppV3.metric.tvds_mean_1", + "type": "metric", + "app": "monitorAppV3", "name": "tvds_mean_1", "project": "default" }, @@ -101,7 +302,7 @@ ] }, { - "full_name": "default.histogram-data-drift-1.metric.tvdar_mean_1", + "full_name": "default.monitorAppV1.metric.tvdar_mean_1", "type": "metric", "data": "true", "values": [ @@ -109,7 +310,7 @@ ] }, { - "full_name": "default.histogram-data-drift-1.metric.tvdop_mean_1", + "full_name": "default.monitorAppV2.metric.tvdar_mean_1", "type": "metric", "data": "true", "values": [ @@ -117,7 +318,36 @@ ] }, { - "full_name": "default.histogram-data-drift-1.metric.tvds_mean_1", + "full_name": "default.monitorAppV3.metric.tvdar_mean_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV2.metric.tvdop_mean_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV1.metric.tvdop_mean_1", + "type": "metric", + "data": "true", + "values": [ + 10 + ] + }, + { + "full_name": "default.monitorAppV1.metric.tvds_mean_1", + "type": "metric", + "data": false + }, + { + "full_name": "default.monitorAppV3.metric.tvds_mean_1", "type": "metric", "data": false }, diff --git a/tests/mockServer/data/modelEndpoints.json b/tests/mockServer/data/modelEndpoints.json index 96ac7a9b0c..100968951d 100644 --- a/tests/mockServer/data/modelEndpoints.json +++ b/tests/mockServer/data/modelEndpoints.json @@ -262,6 +262,268 @@ "sampling_percentage": 20 } }, + { + "kind": "model-endpoint", + "metadata": { + "project": "default", + "labels": { + "my-key": "my-value", + "owner": "admin", + "v3io_user": "admin" + }, + "endpoint_type": 3, + "name": "RandomForestClassifier2", + "created": "2024-11-03T09:18:59.079000", + "updated": "2024-11-03T09:40:58.317000", + "uid": "a7c95783e6a726a1a233e581ea898ba44fa7e342" + }, + "spec": { + "function_name": "transaction-fraud", + "function_tag": "latest", + "function_uid": "unversioned-latest", + "function_uri": "default/aggregate@79fd83704a8514dc2415bded0e9d0ffd94262e92", + "model_name": "RandomForestClassifier", + "model_class": "ClassifierModel", + "model_uid": "898baa010eb35b914558182ad487bc582defde34", + "model_tag": null, + "model_uri": "store://models/default/model_default:latest", + "feature_names": [ + "amount_max_2h", + "amount_sum_2h", + "amount_count_2h", + "amount_avg_2h", + "amount_max_12h", + "label" + ], + "label_names": ["label", "__index_level_0__"], + "children": null, + "children_uids": null, + "feature_stats": { + "amount_max_2h": { + "count": 7446, + "mean": 41.994970453935, + "std": 104.4010819361322, + "min": 0, + "max": 4759.79, + "hist": [ + [7352, 57, 19, 6, 2, 2, 0, 1, 3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1], + [ + 0, 237.9895, 475.979, 713.9685, 951.958, 1189.9475, 1427.937, 1665.9265, 1903.916, + 2141.9055, 2379.895, 2617.8845, 2855.874, 3093.8635, 3331.853, 3569.8424999999997, + 3807.832, 4045.8215, 4283.811, 4521.8005, 4759.79 + ] + ] + }, + "amount_sum_2h": { + "count": 7446, + "mean": 46.912805533172175, + "std": 107.48110128941029, + "min": -147.49, + "max": 4770.01, + "hist": [ + [6920, 467, 32, 13, 2, 3, 1, 0, 4, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 1], + [ + -147.49, 98.38499999999999, 344.26, 590.135, 836.01, 1081.885, 1327.76, 1573.635, + 1819.51, 2065.385, 2311.26, 2557.135, 2803.01, 3048.885, 3294.76, 3540.635, 3786.51, + 4032.385, 4278.26, 4524.135, 4770.01 + ] + ] + }, + "amount_count_2h": { + "count": 7446, + "mean": 1.2539618587160892, + "std": 0.5436930806122989, + "min": -1, + "max": 6, + "hist": [ + [6, 0, 0, 0, 0, 5860, 0, 0, 1306, 0, 0, 229, 0, 0, 42, 0, 0, 2, 0, 1], + [ + -1, -0.65, -0.30000000000000004, 0.04999999999999982, 0.3999999999999999, 0.75, + 1.0999999999999996, 1.4499999999999997, 1.7999999999999998, 2.15, 2.5, + 2.8499999999999996, 3.1999999999999993, 3.55, 3.8999999999999995, 4.25, 4.6, + 4.949999999999999, 5.3, 5.6499999999999995, 6 + ] + ] + }, + "amount_avg_2h": { + "count": 7446, + "mean": 38.96664405945027, + "std": 140.24284088047725, + "min": -107.44000000000001, + "max": 6405.95, + "hist": [ + [7366, 49, 19, 4, 0, 0, 3, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2], + [ + -107.44000000000001, 218.22949999999997, 543.8989999999999, 869.5684999999999, + 1195.2379999999998, 1520.9074999999998, 1846.5769999999998, 2172.2464999999997, + 2497.9159999999997, 2823.5854999999997, 3149.2549999999997, 3474.9244999999996, + 3800.5939999999996, 4126.2635, 4451.933, 4777.6025, 5103.272, 5428.9415, 5754.611, + 6080.2805, 6405.95 + ] + ] + }, + "amount_max_12h": { + "count": 7446, + "mean": 53.890123556271824, + "std": 122.18467228149133, + "min": 0, + "max": 4759.79, + "hist": [ + [7300, 92, 24, 13, 3, 4, 0, 2, 3, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1], + [ + 0, 237.9895, 475.979, 713.9685, 951.958, 1189.9475, 1427.937, 1665.9265, 1903.916, + 2141.9055, 2379.895, 2617.8845, 2855.874, 3093.8635, 3331.853, 3569.8424999999997, + 3807.832, 4045.8215, 4283.811, 4521.8005, 4759.79 + ] + ] + }, + "label": { + "count": 7446, + "mean": 0.014907332796132152, + "std": 0.12119025003595912, + "min": 0, + "max": 1, + "hist": [ + [7335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111], + [ + 0, 0.05, 0.1, 0.15000000000000002, 0.2, 0.25, 0.30000000000000004, + 0.35000000000000003, 0.4, 0.45, 0.5, 0.55, 0.6000000000000001, 0.65, + 0.7000000000000001, 0.75, 0.8, 0.8500000000000001, 0.9, 0.9500000000000001, 1 + ] + ] + } + }, + "monitoring_feature_set_uri": "store://feature-sets/default/stocks:latest" + }, + "status": { + "state": null, + "monitoring_mode": "enabled", + "current_stats": { + "amount_avg_2h": { + "count": 11, + "mean": 28.0887273020327, + "std": 11.304901433309531, + "min": 12.19, + "max": 38.615200064471935, + "hist": [ + [1, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 5], + [ + 12.19, 13.511260003223596, 14.832520006447194, 16.15378000967079, + 17.475040012894386, 18.796300016117982, 20.117560019341582, 21.438820022565178, + 22.760080025788774, 24.08134002901237, 25.402600032235966, 26.723860035459566, + 28.04512003868316, 29.36638004190676, 30.687640045130358, 32.00890004835395, + 33.33016005157755, 34.65142005480114, 35.97268005802474, 37.29394006124834, + 38.615200064471935 + ] + ] + }, + "amount_count_2h": { + "count": 11, + "mean": 0.5454545454545454, + "std": 0.5222329678670935, + "min": 0, + "max": 1, + "hist": [ + [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6], + [ + 0, 0.05, 0.1, 0.15000000000000002, 0.2, 0.25, 0.30000000000000004, + 0.35000000000000003, 0.4, 0.45, 0.5, 0.55, 0.6000000000000001, 0.65, + 0.7000000000000001, 0.75, 0.8, 0.8500000000000001, 0.9, 0.9500000000000001, 1 + ] + ] + }, + "amount_max_12h": { + "count": 11, + "mean": 55.03636363636363, + "std": 57.971923596293976, + "min": 20.92, + "max": 224.11, + "hist": [ + [3, 4, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [ + 20.92, 31.079500000000003, 41.239000000000004, 51.3985, 61.558, 71.7175, 81.877, + 92.0365, 102.196, 112.35549999999999, 122.515, 132.6745, 142.834, + 152.99349999999998, 163.15300000000002, 173.3125, 183.47199999999998, + 193.63150000000002, 203.791, 213.95049999999998, 224.11 + ] + ] + }, + "amount_max_2h": { + "count": 11, + "mean": 29.96273243391514, + "std": 13.260285022445734, + "min": 12.19, + "max": 42.738011354613306, + "hist": [ + [1, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5], + [ + 12.19, 13.717400567730666, 15.24480113546133, 16.772201703191996, + 18.299602270922662, 19.82700283865333, 21.354403406383994, 22.881803974114657, + 24.409204541845323, 25.93660510957599, 27.464005677306652, 28.991406245037318, + 30.518806812767984, 32.04620738049865, 33.573607948229316, 35.10100851595998, + 36.62840908369065, 38.155809651421315, 39.68321021915198, 41.21061078688264, + 42.738011354613306 + ] + ] + }, + "amount_sum_2h": { + "count": 11, + "mean": 10.536363636363637, + "std": 11.31334457419845, + "min": 0, + "max": 30.42, + "hist": [ + [5, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], + [ + 0, 1.5210000000000001, 3.0420000000000003, 4.563000000000001, 6.0840000000000005, + 7.605, 9.126000000000001, 10.647, 12.168000000000001, 13.689000000000002, 15.21, + 16.731, 18.252000000000002, 19.773000000000003, 21.294, 22.815, 24.336000000000002, + 25.857000000000003, 27.378000000000004, 28.899, 30.42 + ] + ] + } + }, + "first_request": "2022-05-02 11:14:21.082236+00:00", + "last_request": "2022-05-19 09:43:49.502045+00:00", + "error_count": null, + "drift_status": "DRIFT_DETECTED", + "avg_latency": null, + "drift_measures": { + "amount_max_2h": { + "tvd": 0.9006299904768882, + "hellinger": 0.8026729143746129, + "kld": 8.03097275516625 + }, + "tvd_sum": 4.0574683173393895, + "tvd_mean": 0.8114936634678779, + "hellinger_sum": 3.7935228606235265, + "hellinger_mean": 0.7587045721247053, + "kld_sum": 40.22159405569385, + "kld_mean": 8.04431881113877, + "amount_count_2h": { + "tvd": 0.9990598979317755, + "hellinger": 0.9860541717475733, + "kld": 15.975132772583372 + }, + "amount_avg_2h": { + "tvd": 0.9019729934314947, + "hellinger": 0.8046642697553347, + "kld": 7.91538219147246 + }, + "amount_sum_2h": { + "tvd": 0.5447830439772423, + "hellinger": 0.5827239245591163, + "kld": 4.424521130663923 + }, + "amount_max_12h": { + "tvd": 0.7110223915219885, + "hellinger": 0.6174075801868897, + "kld": 3.8755852058078455 + } + }, + "sampling_percentage": 20 + } + }, { "kind": "model-endpoint", "metadata": { @@ -519,6 +781,264 @@ }, "sampling_percentage": null } + }, + { + "kind": "model-endpoint", + "metadata": { + "project": "default", + "labels": {}, + "endpoint_type": 3, + "name": "GradientBoostingClassifier2", + "created": "2024-12-03T09:18:59.079000", + "updated": "2024-12-03T09:40:58.317000", + "uid": "d6df9915e64e9ba9441a82983c4yc7f874550b31" + }, + "spec": { + "function_name": "transaction-fraud", + "function_tag": "latest", + "function_uid": "unversioned-latest", + "function_uri": "default/vizro@69200c7de5447f61f15bd28913714c5970b831eb", + "model_name": "GradientBoostingClassifier2", + "model_uid": "898baa010eb35b914558182ad487bc582defde34", + "model_tag": null, + "model_class": "ClassifierModel", + "model_uri": "store://models/default/train_model:latest", + "feature_names": [ + "amount_max_2h", + "amount_sum_2h", + "amount_count_2h", + "amount_avg_2h", + "amount_max_12h", + "label" + ], + "label_names": ["label", "__index_level_0__"], + "children": null, + "children_uids": null, + "feature_stats": { + "amount_max_2h": { + "count": 7446, + "mean": 41.994970453935, + "std": 104.4010819361322, + "min": 0, + "max": 4759.79, + "hist": [ + [7352, 57, 19, 6, 2, 2, 0, 1, 3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1], + [ + 0, 237.9895, 475.979, 713.9685, 951.958, 1189.9475, 1427.937, 1665.9265, 1903.916, + 2141.9055, 2379.895, 2617.8845, 2855.874, 3093.8635, 3331.853, 3569.8424999999997, + 3807.832, 4045.8215, 4283.811, 4521.8005, 4759.79 + ] + ] + }, + "amount_sum_2h": { + "count": 7446, + "mean": 46.912805533172175, + "std": 107.48110128941029, + "min": -147.49, + "max": 4770.01, + "hist": [ + [6920, 467, 32, 13, 2, 3, 1, 0, 4, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 1], + [ + -147.49, 98.38499999999999, 344.26, 590.135, 836.01, 1081.885, 1327.76, 1573.635, + 1819.51, 2065.385, 2311.26, 2557.135, 2803.01, 3048.885, 3294.76, 3540.635, 3786.51, + 4032.385, 4278.26, 4524.135, 4770.01 + ] + ] + }, + "amount_count_2h": { + "count": 7446, + "mean": 1.2539618587160892, + "std": 0.5436930806122989, + "min": -1, + "max": 6, + "hist": [ + [6, 0, 0, 0, 0, 5860, 0, 0, 1306, 0, 0, 229, 0, 0, 42, 0, 0, 2, 0, 1], + [ + -1, -0.65, -0.30000000000000004, 0.04999999999999982, 0.3999999999999999, 0.75, + 1.0999999999999996, 1.4499999999999997, 1.7999999999999998, 2.15, 2.5, + 2.8499999999999996, 3.1999999999999993, 3.55, 3.8999999999999995, 4.25, 4.6, + 4.949999999999999, 5.3, 5.6499999999999995, 6 + ] + ] + }, + "amount_avg_2h": { + "count": 7446, + "mean": 38.96664405945027, + "std": 140.24284088047725, + "min": -107.44000000000001, + "max": 6405.95, + "hist": [ + [7366, 49, 19, 4, 0, 0, 3, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2], + [ + -107.44000000000001, 218.22949999999997, 543.8989999999999, 869.5684999999999, + 1195.2379999999998, 1520.9074999999998, 1846.5769999999998, 2172.2464999999997, + 2497.9159999999997, 2823.5854999999997, 3149.2549999999997, 3474.9244999999996, + 3800.5939999999996, 4126.2635, 4451.933, 4777.6025, 5103.272, 5428.9415, 5754.611, + 6080.2805, 6405.95 + ] + ] + }, + "amount_max_12h": { + "count": 7446, + "mean": 53.890123556271824, + "std": 122.18467228149133, + "min": 0, + "max": 4759.79, + "hist": [ + [7300, 92, 24, 13, 3, 4, 0, 2, 3, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1], + [ + 0, 237.9895, 475.979, 713.9685, 951.958, 1189.9475, 1427.937, 1665.9265, 1903.916, + 2141.9055, 2379.895, 2617.8845, 2855.874, 3093.8635, 3331.853, 3569.8424999999997, + 3807.832, 4045.8215, 4283.811, 4521.8005, 4759.79 + ] + ] + }, + "label": { + "count": 7446, + "mean": 0.014907332796132152, + "std": 0.12119025003595912, + "min": 0, + "max": 1, + "hist": [ + [7335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111], + [ + 0, 0.05, 0.1, 0.15000000000000002, 0.2, 0.25, 0.30000000000000004, + 0.35000000000000003, 0.4, 0.45, 0.5, 0.55, 0.6000000000000001, 0.65, + 0.7000000000000001, 0.75, 0.8, 0.8500000000000001, 0.9, 0.9500000000000001, 1 + ] + ] + } + }, + "monitoring_feature_set_uri": "store://feature-sets/default/test-m2:latest" + }, + "status": { + "state": null, + "monitoring_mode": "enabled", + "current_stats": { + "amount_avg_2h": { + "count": 11, + "mean": 28.0887273020327, + "std": 11.304901433309531, + "min": 12.19, + "max": 38.615200064471935, + "hist": [ + [1, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 5], + [ + 12.19, 13.511260003223596, 14.832520006447194, 16.15378000967079, + 17.475040012894386, 18.796300016117982, 20.117560019341582, 21.438820022565178, + 22.760080025788774, 24.08134002901237, 25.402600032235966, 26.723860035459566, + 28.04512003868316, 29.36638004190676, 30.687640045130358, 32.00890004835395, + 33.33016005157755, 34.65142005480114, 35.97268005802474, 37.29394006124834, + 38.615200064471935 + ] + ] + }, + "amount_count_2h": { + "count": 11, + "mean": 0.5454545454545454, + "std": 0.5222329678670935, + "min": 0, + "max": 1, + "hist": [ + [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6], + [ + 0, 0.05, 0.1, 0.15000000000000002, 0.2, 0.25, 0.30000000000000004, + 0.35000000000000003, 0.4, 0.45, 0.5, 0.55, 0.6000000000000001, 0.65, + 0.7000000000000001, 0.75, 0.8, 0.8500000000000001, 0.9, 0.9500000000000001, 1 + ] + ] + }, + "amount_max_12h": { + "count": 11, + "mean": 55.03636363636363, + "std": 57.971923596293976, + "min": 20.92, + "max": 224.11, + "hist": [ + [3, 4, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [ + 20.92, 31.079500000000003, 41.239000000000004, 51.3985, 61.558, 71.7175, 81.877, + 92.0365, 102.196, 112.35549999999999, 122.515, 132.6745, 142.834, + 152.99349999999998, 163.15300000000002, 173.3125, 183.47199999999998, + 193.63150000000002, 203.791, 213.95049999999998, 224.11 + ] + ] + }, + "amount_max_2h": { + "count": 11, + "mean": 29.96273243391514, + "std": 13.260285022445734, + "min": 12.19, + "max": 42.738011354613306, + "hist": [ + [1, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5], + [ + 12.19, 13.717400567730666, 15.24480113546133, 16.772201703191996, + 18.299602270922662, 19.82700283865333, 21.354403406383994, 22.881803974114657, + 24.409204541845323, 25.93660510957599, 27.464005677306652, 28.991406245037318, + 30.518806812767984, 32.04620738049865, 33.573607948229316, 35.10100851595998, + 36.62840908369065, 38.155809651421315, 39.68321021915198, 41.21061078688264, + 42.738011354613306 + ] + ] + }, + "amount_sum_2h": { + "count": 11, + "mean": 10.536363636363637, + "std": 11.31334457419845, + "min": 0, + "max": 30.42, + "hist": [ + [5, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], + [ + 0, 1.5210000000000001, 3.0420000000000003, 4.563000000000001, 6.0840000000000005, + 7.605, 9.126000000000001, 10.647, 12.168000000000001, 13.689000000000002, 15.21, + 16.731, 18.252000000000002, 19.773000000000003, 21.294, 22.815, 24.336000000000002, + 25.857000000000003, 27.378000000000004, 28.899, 30.42 + ] + ] + } + }, + "first_request": "2022-05-02 11:14:21.082452+00:00", + "last_request": "2022-05-19 09:43:49.502382+00:00", + "error_count": null, + "avg_latency": null, + "drift_status": "DRIFT_DETECTED", + "drift_measures": { + "amount_max_2h": { + "tvd": 0.9006299904768882, + "hellinger": 0.8026729143746129, + "kld": 8.03097275516625 + }, + "tvd_sum": 4.0574683173393895, + "tvd_mean": 0.8114936634678779, + "hellinger_sum": 3.7935228606235265, + "hellinger_mean": 0.7587045721247053, + "kld_sum": 40.22159405569385, + "kld_mean": 8.04431881113877, + "amount_count_2h": { + "tvd": 0.9990598979317755, + "hellinger": 0.9860541717475733, + "kld": 15.975132772583372 + }, + "amount_avg_2h": { + "tvd": 0.9019729934314947, + "hellinger": 0.8046642697553347, + "kld": 7.91538219147246 + }, + "amount_sum_2h": { + "tvd": 0.5447830439772423, + "hellinger": 0.5827239245591163, + "kld": 4.424521130663923 + }, + "amount_max_12h": { + "tvd": 0.7110223915219885, + "hellinger": 0.6174075801868897, + "kld": 3.8755852058078455 + } + }, + "sampling_percentage": null + } } ] } diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 86cc3b1957..26f4b6b567 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -865,7 +865,7 @@ function getMonitoringApplicationsSummary(req, res) { function getMonitoringApplicationData(req, res) { const monitoringApplication = (monitoringApplications[req.params['project']] || []).find( application => { - return application.name.toLowerCase() === req.params['func'] + return application.name.toLowerCase() === req.params['func'].toLowerCase() } ) From bc75379291e8a68e452260862969a61912f71478 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 2 Sep 2025 17:05:04 +0300 Subject: [PATCH 134/228] Fix [Batch run] small issues in the Data inputs "Path" field (#3413) --- package.json | 2 +- src/common/TargetPath/TargetPath.jsx | 15 +++++- src/common/TargetPath/targetPath.util.js | 52 +++++++++++++++---- .../FormDataInputsRow/FormDataInputsRow.jsx | 2 + 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index e418388322..4152bb6720 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.8", + "iguazio.dashboard-react-controls": "3.1.9", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", diff --git a/src/common/TargetPath/TargetPath.jsx b/src/common/TargetPath/TargetPath.jsx index 18c753d454..84971086c1 100644 --- a/src/common/TargetPath/TargetPath.jsx +++ b/src/common/TargetPath/TargetPath.jsx @@ -36,6 +36,7 @@ import { handleStoreInputPathChange, isPathInputInvalid, pathPlaceholders, + prepareTargetPathInitialState, targetPathInitialState } from './targetPath.util' import { MLRUN_STORAGE_INPUT_PATH_SCHEME } from '../../constants' @@ -44,7 +45,9 @@ const TargetPath = ({ density = 'normal', formState, formStateFieldInfo, + formStateDataInputState = '', hiddenSelectOptionsIds = [], + inputDefaultState = null, inputDefaultValue = '', label = '', name, @@ -54,7 +57,9 @@ const TargetPath = ({ selectPlaceholder = '', setFieldState }) => { - const [dataInputState, setDataInputState] = useState(targetPathInitialState) + const [dataInputState, setDataInputState] = useState( + prepareTargetPathInitialState(inputDefaultState, inputDefaultValue, selectDefaultValue) + ) const dispatch = useDispatch() const handleOnChange = (selectValue, inputValue) => { @@ -215,9 +220,13 @@ const TargetPath = ({ if (value.length !== 0) { formState.form.change(`${formStateFieldInfo}.value`, value.replace(/[^:/]*:[/]{2,3}/, '')) formState.form.change(`${formStateFieldInfo}.pathType`, value.match(/^\w*:[/]{2,3}/)[0]) + + if (formStateDataInputState) { + formState.form.change(`${formStateDataInputState}`, dataInputState) + } } }, - [formState.form, formStateFieldInfo] + [dataInputState, formState.form, formStateDataInputState, formStateFieldInfo] ) return ( @@ -270,7 +279,9 @@ TargetPath.propTypes = { density: PropTypes.oneOf(['dense', 'normal', 'medium', 'chunky']), formState: PropTypes.object.isRequired, formStateFieldInfo: PropTypes.string.isRequired, + formStateDataInputState: PropTypes.string, hiddenSelectOptionsIds: PropTypes.arrayOf(PropTypes.string), + inputDefaultState: PropTypes.object, inputDefaultValue: PropTypes.string, label: PropTypes.string, name: PropTypes.string.isRequired, diff --git a/src/common/TargetPath/targetPath.util.js b/src/common/TargetPath/targetPath.util.js index 86ea3c0e86..7ef8437766 100644 --- a/src/common/TargetPath/targetPath.util.js +++ b/src/common/TargetPath/targetPath.util.js @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { get, isNil, uniqBy } from 'lodash' +import { debounce, get, isNil, uniqBy } from 'lodash' import { ARTIFACT_OTHER_TYPE, @@ -39,6 +39,7 @@ import { fetchArtifact, fetchArtifacts } from '../../reducers/artifactsReducer' import { fetchFeatureVector, fetchFeatureVectors } from '../../reducers/featureStoreReducer' import { fetchProjectsNames } from '../../reducers/projectReducer' import { isCommunityEdition } from '../../utils/helper' +import { parseUri } from '../../utils/parseUri' const targetPathRegex = /^(store|v3io|s3|az|gs):(\/\/\/|\/\/)(?!.*:\/\/)([\w\-._~:?#[\]@!$&'()*+,;=]+)\/([\w\-._~:/?#[\]%@!$&'()*+,;=]+)$/i @@ -332,7 +333,7 @@ export const generateArtifactsReferencesList = artifacts => { return uniqBy(generatedArtifacts, 'id') } -export const getProjectsNames = (dispatch, setDataInputState, projectName) => { +export const getProjectsNames = debounce((dispatch, setDataInputState, projectName) => { dispatch(fetchProjectsNames()) .unwrap() .then(result => { @@ -342,9 +343,9 @@ export const getProjectsNames = (dispatch, setDataInputState, projectName) => { })) }) .catch(() => {}) -} +}, 300) -export const getArtifacts = (dispatch, project, storePathType, setDataInputState) => { +export const getArtifacts = debounce((dispatch, project, storePathType, setDataInputState) => { dispatch( fetchArtifacts({ project, @@ -373,9 +374,9 @@ export const getArtifacts = (dispatch, project, storePathType, setDataInputState .catch(error => { showErrorNotification(dispatch, error, '', 'Failed to fetch artifacts') }) -} +}, 300) -export const getFeatureVectors = (dispatch, project, setDataInputState) => { +export const getFeatureVectors = debounce((dispatch, project, setDataInputState) => { dispatch(fetchFeatureVectors({ project, filters: {}, config: {} })) .unwrap() .then(featureVectors => { @@ -393,9 +394,9 @@ export const getFeatureVectors = (dispatch, project, setDataInputState) => { featureVectors: featureVectorsList })) }) -} +}, 300) -export const getArtifact = (dispatch, project, projectItem, setDataInputState) => { +export const getArtifact = debounce((dispatch, project, projectItem, setDataInputState) => { dispatch(fetchArtifact({ project, artifact: projectItem })) .unwrap() .then(artifacts => { @@ -409,9 +410,9 @@ export const getArtifact = (dispatch, project, projectItem, setDataInputState) = .catch(error => { showErrorNotification(dispatch, error, '', 'Failed to fetch artifact data') }) -} +}, 300) -export const getFeatureVector = (dispatch, project, projectItem, setDataInputState) => { +export const getFeatureVector = debounce((dispatch, project, projectItem, setDataInputState) => { dispatch(fetchFeatureVector({ project, featureVector: projectItem })) .unwrap() .then(featureVectors => { @@ -436,4 +437,35 @@ export const getFeatureVector = (dispatch, project, projectItem, setDataInputSta .catch(error => { showErrorNotification(dispatch, error, '', 'Failed to fetch feature vector data') }) +}, 300) + +export const prepareTargetPathInitialState = ( + inputDefaultState, + inputDefaultValue = '', + selectDefaultValue = '' +) => { + if (inputDefaultState) { + return inputDefaultState + } + + if (inputDefaultValue && selectDefaultValue.startsWith('store')) { + const state = { ...targetPathInitialState } + const { key, project, kind } = parseUri(selectDefaultValue + inputDefaultValue) + const projectItemReference = inputDefaultValue.split(`${kind}/${project}/${key}`)?.[1] || '' + state.storePathType = kind + state.project = project + state.projectItem = key + state.inputProjectItemPathEntered = true + state.inputProjectPathEntered = true + state.inputStorePathTypeEntered = true + + if (projectItemReference) { + state.projectItemReference = projectItemReference + state.inputProjectItemReferencePathEntered = true + } + + return state + } + + return targetPathInitialState } diff --git a/src/elements/FormDataInputsTable/FormDataInputsRow/FormDataInputsRow.jsx b/src/elements/FormDataInputsTable/FormDataInputsRow/FormDataInputsRow.jsx index 9f154929eb..fc6dba1831 100644 --- a/src/elements/FormDataInputsTable/FormDataInputsRow/FormDataInputsRow.jsx +++ b/src/elements/FormDataInputsTable/FormDataInputsRow/FormDataInputsRow.jsx @@ -106,6 +106,7 @@ const FormDataInputsRow = ({ density="normal" formState={formState} formStateFieldInfo={`${rowPath}.data.fieldInfo`} + formStateDataInputState={`${rowPath}.data.dataInputState`} hiddenSelectOptionsIds={ fieldData.data.name === MODEL_PATH_DATA_INPUT && fieldData.isPredefined ? [ @@ -120,6 +121,7 @@ const FormDataInputsRow = ({ : [] } inputDefaultValue={editingItem.data.fieldInfo?.value} + inputDefaultState={editingItem.data.dataInputState} name={`${rowPath}.data.path`} params={params} required From 7e3dfc76e8e85ebf4bba3555fd7ebdeffcf2bda6 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Tue, 2 Sep 2025 17:06:43 +0300 Subject: [PATCH 135/228] Fix [ESLint] Add `import/named` rule, fix eslint warnings (#3414) --- eslint.config.mjs | 5 ++++- package.json | 1 + src/common/MlChart/MlChart.jsx | 2 +- .../RegisterArtifactModal/RegisterArtifactModal.jsx | 2 -- src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx | 5 +++-- src/elements/RegisterModelModal/RegisterModelModal.jsx | 2 -- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 5fbdd6a2a6..6ec622e15d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -3,6 +3,7 @@ import globals from 'globals' import js from '@eslint/js' import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' +import eslintPluginImport from 'eslint-plugin-import' export default [ { ignores: ['dist'] }, @@ -21,7 +22,8 @@ export default [ }, plugins: { react: react, - 'react-hooks': reactHooks + 'react-hooks': reactHooks, + import: eslintPluginImport }, settings: { react: { @@ -34,6 +36,7 @@ export default [ 'react/react-in-jsx-scope': 'off', 'react/no-unescaped-entities': 'off', 'import/no-anonymous-default-export': 'off', + 'import/named': process.env.NODE_ENV === 'production' ? 2 : 1, 'no-unused-vars': process.env.NODE_ENV === 'production' ? 2 : 1, 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 1, 'no-console': process.env.NODE_ENV === 'production' ? 2 : 1, diff --git a/package.json b/package.json index 4152bb6720..2379ee692f 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,7 @@ "eslint": "^9.13.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-babel": "^5.3.1", + "eslint-plugin-import": "^2.32.0", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.37.4", "eslint-plugin-react-hooks": "^5.1.0", diff --git a/src/common/MlChart/MlChart.jsx b/src/common/MlChart/MlChart.jsx index 7300795a9c..58b45b6fb8 100644 --- a/src/common/MlChart/MlChart.jsx +++ b/src/common/MlChart/MlChart.jsx @@ -19,7 +19,7 @@ such restriction. */ import React, { useState, useRef, useEffect } from 'react' import PropTypes from 'prop-types' -import { Chart } from 'chart.js/auto' +import { Chart } from 'chart.js' import classnames from 'classnames' import { Loader } from 'igz-controls/components' diff --git a/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx b/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx index e25ca9aba3..da496174e5 100644 --- a/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx +++ b/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx @@ -41,8 +41,6 @@ import { convertChipsData } from '../../utils/convertChipsData' import { createArtifactMessages } from '../../utils/createArtifact.util' import { setFieldState, isSubmitDisabled } from 'igz-controls/utils/form.util' import { setNotification } from 'igz-controls/reducers/notificationReducer' -import { showErrorNotification } from 'igz-controls/utils/notification.util' -import { openPopUp } from 'igz-controls/utils/common.util' import { useModalBlockHistory } from '../../hooks/useModalBlockHistory.hook' import { processActionAfterTagUniquesValidation } from '../../utils/artifacts.util' diff --git a/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx b/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx index 27fe954e32..4bbb0a7933 100644 --- a/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx +++ b/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx @@ -166,14 +166,15 @@ const ArtifactPopUp = ({ artifactData, isOpen, onResolve }) => { onResolve() }) }, [ - artifactData, artifactContext, dispatch, onResolve, + artifactData.key, artifactData.iteration, artifactData.tree, artifactData.uid, - artifactData.tag + artifactData.tag, + artifactData.project ]) const actionsMenu = useMemo( diff --git a/src/elements/RegisterModelModal/RegisterModelModal.jsx b/src/elements/RegisterModelModal/RegisterModelModal.jsx index 917e35cb09..82ab960268 100644 --- a/src/elements/RegisterModelModal/RegisterModelModal.jsx +++ b/src/elements/RegisterModelModal/RegisterModelModal.jsx @@ -42,8 +42,6 @@ import { getChipOptions } from 'igz-controls/utils/chips.util' import { getValidationRules } from 'igz-controls/utils/validation.util' import { setFieldState, isSubmitDisabled } from 'igz-controls/utils/form.util' import { setNotification } from 'igz-controls/reducers/notificationReducer' -import { showErrorNotification } from 'igz-controls/utils/notification.util' -import { openPopUp } from 'igz-controls/utils/common.util' import { useModalBlockHistory } from '../../hooks/useModalBlockHistory.hook' import { processActionAfterTagUniquesValidation } from '../../utils/artifacts.util' From 95a4c26bcf2dab047f50c79a7a75210eec3c69ad Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Wed, 3 Sep 2025 19:02:11 +0800 Subject: [PATCH 136/228] Fix [Counters] UI crash - TypeError: Cannot read properties of undefined (reading 'endpoint_alerts_count') (#3409) --- src/components/ProjectsPage/projects.util.jsx | 47 +++++++++---------- src/elements/ProjectCard/projectCard.util.js | 4 +- src/elements/ProjectJobs/projectJobs.utils.js | 10 ++-- .../AlertsCounters.jsx | 16 +++---- 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/components/ProjectsPage/projects.util.jsx b/src/components/ProjectsPage/projects.util.jsx index a25d7a4c24..939ce3fa1d 100644 --- a/src/components/ProjectsPage/projects.util.jsx +++ b/src/components/ProjectsPage/projects.util.jsx @@ -222,9 +222,8 @@ export const pollDeletingProjects = (terminatePollRef, deletingProjects, refresh setNotification({ status: 200, id: Math.random(), - message: `Project "${ - deletingProjects?.[task.metadata.name] - }" was deleted successfully` + message: `Project "${deletingProjects?.[task.metadata.name] + }" was deleted successfully` }) ) } else { @@ -260,9 +259,9 @@ export const generateAlerts = (data, dispatch) => { data.forEach(project => { const projectName = project.name projectAlerts[projectName] = - (project.endpoint_alerts_count || 0) + - (project.job_alerts_count || 0) + - (project.other_alerts_count || 0) + (project?.endpoint_alerts_count || 0) + + (project?.job_alerts_count || 0) + + (project?.other_alerts_count || 0) }) dispatch(setProjectTotalAlerts(projectAlerts)) @@ -311,47 +310,47 @@ export const generateMonitoringCounters = (data, dispatch) => { } data.forEach(project => { - monitoringCounters.jobs.completed += project.runs_completed_recent_count || 0 - monitoringCounters.jobs.failed += project.runs_failed_recent_count || 0 - monitoringCounters.jobs.running += project.runs_running_count || 0 + monitoringCounters.jobs.completed += project?.runs_completed_recent_count || 0 + monitoringCounters.jobs.failed += project?.runs_failed_recent_count || 0 + monitoringCounters.jobs.running += project?.runs_running_count || 0 monitoringCounters.jobs.total = monitoringCounters.jobs.completed + monitoringCounters.jobs.failed + monitoringCounters.jobs.running - monitoringCounters.workflows.completed += project.pipelines_completed_recent_count || 0 - monitoringCounters.workflows.failed += project.pipelines_failed_recent_count || 0 - monitoringCounters.workflows.running += project.pipelines_running_count || 0 + monitoringCounters.workflows.completed += project?.pipelines_completed_recent_count || 0 + monitoringCounters.workflows.failed += project?.pipelines_failed_recent_count || 0 + monitoringCounters.workflows.running += project?.pipelines_running_count || 0 monitoringCounters.workflows.total = monitoringCounters.workflows.completed + monitoringCounters.workflows.failed + monitoringCounters.workflows.running - monitoringCounters.scheduled.jobs += project.distinct_scheduled_jobs_pending_count || 0 + monitoringCounters.scheduled.jobs += project?.distinct_scheduled_jobs_pending_count || 0 monitoringCounters.scheduled.workflows += - project.distinct_scheduled_pipelines_pending_count || 0 + project?.distinct_scheduled_pipelines_pending_count || 0 monitoringCounters.scheduled.total = monitoringCounters.scheduled.jobs + monitoringCounters.scheduled.workflows - monitoringCounters.alerts.endpoint += project.endpoint_alerts_count || 0 - monitoringCounters.alerts.jobs += project.job_alerts_count || 0 - monitoringCounters.alerts.application += project.other_alerts_count || 0 + monitoringCounters.alerts.endpoint += project?.endpoint_alerts_count || 0 + monitoringCounters.alerts.jobs += project?.job_alerts_count || 0 + monitoringCounters.alerts.application += project?.other_alerts_count || 0 monitoringCounters.alerts.total = monitoringCounters.alerts.endpoint + monitoringCounters.alerts.jobs + monitoringCounters.alerts.application - monitoringCounters.models.total += project.models_count || 0 + monitoringCounters.models.total += project?.models_count || 0 - monitoringCounters.monitoring_app.running += project.running_model_monitoring_functions || 0 - monitoringCounters.monitoring_app.failed += project.failed_model_monitoring_functions || 0 + monitoringCounters.monitoring_app.running += project?.running_model_monitoring_functions || 0 + monitoringCounters.monitoring_app.failed += project?.failed_model_monitoring_functions || 0 monitoringCounters.monitoring_app.total = monitoringCounters.monitoring_app.failed + monitoringCounters.monitoring_app.running - monitoringCounters.artifacts.llm_prompts += project.llm_prompts_count || 0 - monitoringCounters.artifacts.datasets += project.datasets_count || 0 - monitoringCounters.artifacts.files += project.files_count || 0 - monitoringCounters.artifacts.documents += project.documents_count || 0 + monitoringCounters.artifacts.llm_prompts += project?.llm_prompts_count || 0 + monitoringCounters.artifacts.datasets += project?.datasets_count || 0 + monitoringCounters.artifacts.files += project?.files_count || 0 + monitoringCounters.artifacts.documents += project?.documents_count || 0 monitoringCounters.artifacts.total = monitoringCounters.artifacts.llm_prompts + monitoringCounters.artifacts.datasets + diff --git a/src/elements/ProjectCard/projectCard.util.js b/src/elements/ProjectCard/projectCard.util.js index 41dd4c2677..f23a61cce2 100644 --- a/src/elements/ProjectCard/projectCard.util.js +++ b/src/elements/ProjectCard/projectCard.util.js @@ -45,7 +45,7 @@ export const generateProjectStatistic = ( className: !fetchProjectsSummaryFailure && !fetchNuclioFunctionsFailure && - projectSummary.runs_running_count + runningNuclioFunctions > 0 + projectSummary?.runs_running_count + runningNuclioFunctions > 0 ? 'running' : 'default', counterTooltip: 'ML jobs and Nuclio functions', @@ -56,7 +56,7 @@ export const generateProjectStatistic = ( ? 'N/A' : isEmpty(projectSummary) ? '-' - : projectSummary.runs_running_count + runningNuclioFunctions + : projectSummary?.runs_running_count + runningNuclioFunctions }, failedJobs: { className: diff --git a/src/elements/ProjectJobs/projectJobs.utils.js b/src/elements/ProjectJobs/projectJobs.utils.js index 69f8f1a7bc..40ab03691d 100644 --- a/src/elements/ProjectJobs/projectJobs.utils.js +++ b/src/elements/ProjectJobs/projectJobs.utils.js @@ -27,10 +27,10 @@ import { typesOfJob } from '../../utils/jobs.util' export const getJobsStatistics = (projectCounter, projectName) => { return { running: { - value: projectCounter.error ? 'N/A' : projectCounter.data.runs_running_count, + value: projectCounter.error ? 'N/A' : projectCounter?.data?.runs_running_count, label: 'In Process', className: - projectCounter.error || projectCounter.data.runs_running_count === 0 + projectCounter.error || projectCounter?.data?.runs_running_count === 0 ? 'default' : 'running', status: 'running', @@ -39,10 +39,10 @@ export const getJobsStatistics = (projectCounter, projectName) => { loading: projectCounter.loading }, failed: { - value: projectCounter.error ? 'N/A' : projectCounter.data.runs_failed_recent_count, + value: projectCounter.error ? 'N/A' : projectCounter?.data?.runs_failed_recent_count, label: 'Failed', className: - projectCounter.error || projectCounter.data.runs_failed_recent_count === 0 + projectCounter.error || projectCounter?.data?.runs_failed_recent_count === 0 ? 'running' : 'failed', status: 'failed', @@ -51,7 +51,7 @@ export const getJobsStatistics = (projectCounter, projectName) => { loading: projectCounter.loading }, succeeded: { - value: projectCounter.error ? 'N/A' : projectCounter.data.runs_completed_recent_count, + value: projectCounter.error ? 'N/A' : projectCounter?.data?.runs_completed_recent_count, label: 'Succeeded', status: 'succeeded', className: 'running', diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index e7e2233c1d..11236643e8 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -60,9 +60,9 @@ const AlertsCounters = () => { } if (projectName !== '*') { - const endpoint = projectStore.projectSummary.data.endpoint_alerts_count || 0 - const jobs = projectStore.projectSummary.data.job_alerts_count || 0 - const application = projectStore.projectSummary.data.other_alerts_count || 0 + const endpoint = projectStore?.projectSummary?.data?.endpoint_alerts_count || 0 + const jobs = projectStore?.projectSummary?.data?.job_alerts_count || 0 + const application = projectStore?.projectSummary?.data?.other_alerts_count || 0 return { projectName, @@ -77,14 +77,14 @@ const AlertsCounters = () => { return { projectName, - data: defaults({}, projectStore.jobsMonitoringData.alerts, defaultAlertData) + data: defaults({}, projectStore?.jobsMonitoringData?.alerts, defaultAlertData) } }, [ paramProjectName, - projectStore.jobsMonitoringData.alerts, - projectStore.projectSummary.data.endpoint_alerts_count, - projectStore.projectSummary.data.job_alerts_count, - projectStore.projectSummary.data.other_alerts_count + projectStore?.jobsMonitoringData?.alerts, + projectStore?.projectSummary?.data?.endpoint_alerts_count, + projectStore?.projectSummary?.data?.job_alerts_count, + projectStore?.projectSummary?.data?.other_alerts_count ]) const alertsStats = useMemo( From 2e8f578a0fcc8766222a5dfa6f6dad651967366e Mon Sep 17 00:00:00 2001 From: adi-gini Date: Wed, 3 Sep 2025 14:02:50 +0300 Subject: [PATCH 137/228] Fix [Projects Monitoring] Titles formatting and filtering defaults (#3415) --- src/utils/generateMonitoringData.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index 77e902f270..dd22d972d9 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -51,8 +51,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { const linkClassNameDetails = (projectName, noLine) => classNames(!noLine && 'stats__line', projectName && 'stats__link') - const linkClassNameHeader = projectName => - classNames(projectName && 'stats__link') + const linkClassNameHeader = projectName => classNames(projectName && 'stats__link') const navigateToTab = (projectName, tab) => { projectName && navigate(`/projects/${projectName}/${tab}`) @@ -224,7 +223,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { counter: data.running || 0, className: classNames(projectName && 'stats__link'), link: () => navigateToTab(projectName, MONITORING_APP_PAGE), - statusClass: 'completed', + statusClass: 'running', label: RUNNING, popUpClassName: classNames({ 'card-popup_text_link': projectName }) }, From 5bbd347adf5bb5524d128aaa60b3f9f123378ee7 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Wed, 3 Sep 2025 15:44:24 +0300 Subject: [PATCH 138/228] Fix [Model Endpoints] Page crash on `Features analysis` and `Metrics` tabs (#3416) --- src/common/MlChart/MlChart.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/MlChart/MlChart.jsx b/src/common/MlChart/MlChart.jsx index 58b45b6fb8..ddae2ab2be 100644 --- a/src/common/MlChart/MlChart.jsx +++ b/src/common/MlChart/MlChart.jsx @@ -19,7 +19,7 @@ such restriction. */ import React, { useState, useRef, useEffect } from 'react' import PropTypes from 'prop-types' -import { Chart } from 'chart.js' +import Chart from 'chart.js/auto' import classnames from 'classnames' import { Loader } from 'igz-controls/components' From e76d3c569acb4fa178772b1e296ecddb14726c6f Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Thu, 4 Sep 2025 15:06:30 +0300 Subject: [PATCH 139/228] Fix [Artifacts] Clicking on the current artifacts screen does not trigger a request (#3417) --- src/App.jsx | 20 ++++++--- src/elements/NavbarLink/NavbarLink.jsx | 1 + ...apComponentForNavbarNavigationTracking.jsx | 41 +++++++++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 src/utils/wrapComponentForNavbarNavigationTracking.jsx diff --git a/src/App.jsx b/src/App.jsx index 25858deefa..84ead1754b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -41,6 +41,7 @@ import localStorageService from './utils/localStorageService' import { lazyRetry } from './lazyWithRetry' import { useMode } from './hooks/mode.hook' import { useNuclioMode } from './hooks/nuclioMode.hook' +import wrapComponentForNavbarNavigationTracking from './utils/wrapComponentForNavbarNavigationTracking' import { ALERTS_PAGE_PATH, @@ -148,6 +149,13 @@ const App = () => { const isHeaderShown = localStorageService.getStorageValue('mlrunUi.headerHidden') !== 'true' const mlAppContainerClasses = classNames('ml-app-container', isHeaderShown && 'has-header') + const FilesComponent = wrapComponentForNavbarNavigationTracking(Files) + const DatasetsComponent = wrapComponentForNavbarNavigationTracking(Datasets) + const DocumentsComponent = wrapComponentForNavbarNavigationTracking(Documents) + const LLMPromptsComponent = wrapComponentForNavbarNavigationTracking(LLMPrompts) + const FunctionsOldComponent = wrapComponentForNavbarNavigationTracking(FunctionsOld) + const FunctionsComponent = wrapComponentForNavbarNavigationTracking(Functions) + const router = createBrowserRouter( createRoutesFromElements( <> @@ -255,7 +263,7 @@ const App = () => { } + element={} /> )) @@ -265,7 +273,7 @@ const App = () => { 'projects/:projectName/functions/:funcName/:tag/:tab' ].map((path, index) => ( - } /> + } /> ))} {[ @@ -275,7 +283,7 @@ const App = () => { `projects/:projectName/datasets/:artifactName/${ALL_VERSIONS_PATH}/:id/:tab` ].map((path, index) => ( - } /> + } /> ))} { `projects/:projectName/files/:artifactName/${ALL_VERSIONS_PATH}/:id/:tab` ].map((path, index) => ( - } /> + } /> ))} {[ @@ -366,7 +374,7 @@ const App = () => { `projects/:projectName/documents/:artifactName/${ALL_VERSIONS_PATH}/:id/:tab` ].map((path, index) => ( - } /> + } /> ))} {[ @@ -376,7 +384,7 @@ const App = () => { `projects/:projectName/llm-prompts/:artifactName/${ALL_VERSIONS_PATH}/:id/:tab` ].map((path, index) => ( - } /> + } /> ))} } /> diff --git a/src/elements/NavbarLink/NavbarLink.jsx b/src/elements/NavbarLink/NavbarLink.jsx index 8a96a0b814..554a17d697 100644 --- a/src/elements/NavbarLink/NavbarLink.jsx +++ b/src/elements/NavbarLink/NavbarLink.jsx @@ -37,6 +37,7 @@ const NavbarLink = ({ externalLink = false, icon = {}, label = '', link = '', .. {...props} className="nav-link__button btn btn-secondary" activeclassname="active" + state={{navbarNavigate: true}} > {icon} {label} diff --git a/src/utils/wrapComponentForNavbarNavigationTracking.jsx b/src/utils/wrapComponentForNavbarNavigationTracking.jsx new file mode 100644 index 0000000000..26cd2e304f --- /dev/null +++ b/src/utils/wrapComponentForNavbarNavigationTracking.jsx @@ -0,0 +1,41 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import { useMemo, useRef } from 'react' +import { useLocation } from 'react-router-dom' + +const wrapComponentForNavbarNavigationTracking = WrappedComponent => { + const Wrap = props => { + const location = useLocation() + const savedKeyRef = useRef(0) + const key = useMemo(() => { + if (location.state?.navbarNavigate) { + return ++savedKeyRef.current + } + + return savedKeyRef.current + }, [location.state?.navbarNavigate]) + + return + } + + return Wrap +} + +export default wrapComponentForNavbarNavigationTracking \ No newline at end of file From a9a2f048e7defde856d9594288caab79cac18847 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Sat, 6 Sep 2025 05:04:42 +0300 Subject: [PATCH 140/228] Fix [Download] Issues with the download container (#3418) --- src/common/Download/DownloadContainer.jsx | 4 ++-- src/common/Download/downloadContainer.scss | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/common/Download/DownloadContainer.jsx b/src/common/Download/DownloadContainer.jsx index 171db576a8..61cbb5594c 100644 --- a/src/common/Download/DownloadContainer.jsx +++ b/src/common/Download/DownloadContainer.jsx @@ -74,8 +74,8 @@ const DownloadContainer = () => {
      - {downloadStore.downloadList.map((downloadItem, index) => { - return + {downloadStore.downloadList.map((downloadItem) => { + return })}
      diff --git a/src/common/Download/downloadContainer.scss b/src/common/Download/downloadContainer.scss index 365f2af2c9..6c4fbb1b2a 100644 --- a/src/common/Download/downloadContainer.scss +++ b/src/common/Download/downloadContainer.scss @@ -3,7 +3,7 @@ .download-container { position: relative; - z-index: 10; + z-index: 9; align-self: flex-end; opacity: 0; width: 220px; @@ -48,8 +48,12 @@ } } + &__status { + margin-left: auto; + } + &__buttons { - min-width: 20px; + min-width: 10px; .round-icon-cp__circle { width: 20px; From 3f353ca37a38986e9402ba9a7bc692d262bc2080 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:33:33 +0300 Subject: [PATCH 141/228] Fix [Monitoring app] Wrong redirection to function details from System functions section (#3420) --- .../MonitoringApplications/monitoringApplications.util.js | 4 +++- src/elements/ApplicationTableRow/ApplicationTableRow.jsx | 2 ++ src/elements/ApplicationTableRow/applicationTableRow.scss | 5 +++++ src/utils/createApplicationContent.jsx | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 src/elements/ApplicationTableRow/applicationTableRow.scss diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js index 68c25e7756..298b7e6eba 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js @@ -48,10 +48,12 @@ export const generateOperatingFunctionsTable = (functions, projectName) => { ] const tableBody = functions.map(func => { + const nuclioFunctionName = `${projectName}-${func.name.toLowerCase()}`.slice(0, 63) + return { name: { value: capitalize(func.name), - link: generateNuclioLink(`/projects/${projectName}/functions/${func.name}`), + href: generateNuclioLink(`/projects/${projectName}/functions/${nuclioFunctionName}`), className: 'table-cell_big' }, status: { diff --git a/src/elements/ApplicationTableRow/ApplicationTableRow.jsx b/src/elements/ApplicationTableRow/ApplicationTableRow.jsx index 717ad74d9a..e1c362032e 100644 --- a/src/elements/ApplicationTableRow/ApplicationTableRow.jsx +++ b/src/elements/ApplicationTableRow/ApplicationTableRow.jsx @@ -25,6 +25,8 @@ import { TableCell, ActionsMenu } from 'igz-controls/components' import { ACTIONS_MENU } from 'igz-controls/types' +import './applicationTableRow.scss' + const ApplicationTableRow = ({ actionsMenu, hideActionsMenu = false, rowItem }) => { const rowClassNames = classnames('table-row', 'table-body-row', 'parent-row') diff --git a/src/elements/ApplicationTableRow/applicationTableRow.scss b/src/elements/ApplicationTableRow/applicationTableRow.scss new file mode 100644 index 0000000000..a453fe793f --- /dev/null +++ b/src/elements/ApplicationTableRow/applicationTableRow.scss @@ -0,0 +1,5 @@ + .table-body__cell { + a { + display: flex; + } + } diff --git a/src/utils/createApplicationContent.jsx b/src/utils/createApplicationContent.jsx index 26cfe6c7e6..402ee2584a 100644 --- a/src/utils/createApplicationContent.jsx +++ b/src/utils/createApplicationContent.jsx @@ -100,6 +100,7 @@ export const createApplicationContent = (application, projectName) => { className: 'table-cell-2', getLink: () => generateNuclioLink(`/projects/${projectName}/functions/${nuclioFunctionName}`), + linkIsExternal: true, showStatus: true } ] From 7fd6264351d96a9eeb80d42ff4b458625d1dcab3 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:34:05 +0300 Subject: [PATCH 142/228] Fix [Counters] Add info icon to cross-project and project-screen (#3419) --- src/elements/PageHeader/pageHeader.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/elements/PageHeader/pageHeader.scss b/src/elements/PageHeader/pageHeader.scss index 9a44603745..c83d2604f1 100644 --- a/src/elements/PageHeader/pageHeader.scss +++ b/src/elements/PageHeader/pageHeader.scss @@ -26,11 +26,11 @@ .tooltip-wrapper { display: flex; align-items: center; - margin-left: 10px; + margin-left: 5px; svg { - width: 20px; - height: 20px; + width: 16px; + height: 16px; path { fill: variables.$secondaryTextColor; From 59a3f66c15aaecaa69d33a605e18d636936e1880 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 9 Sep 2025 09:40:42 +0300 Subject: [PATCH 143/228] Fix [Monitoring Applications] Applications KPI includes infra funcs (#3422) --- .../monitoringApplicationCounters.util.jsx | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index 332d2f62af..77a1572441 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -37,10 +37,7 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => counterData: [ { id: 'applications', - title: monitoringApplicationError - ? null - : monitoringApplications.operatingFunctions.length + - monitoringApplications.applications.length + title: monitoringApplicationError ? null : monitoringApplications.applications.length } ] }, @@ -151,13 +148,13 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => return params.name ? { - content: applicationCountersContent, - loading: monitoringApplicationIsLoading, - error: monitoringApplicationError - } + content: applicationCountersContent, + loading: monitoringApplicationIsLoading, + error: monitoringApplicationError + } : { - content: applicationsCountersContent, - loading: applicationsSummary.loading, - error: applicationsSummary.error - } + content: applicationsCountersContent, + loading: applicationsSummary.loading, + error: applicationsSummary.error + } } From f6c2839b788b62e6c2e56b8e889f77d24c0b00c4 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 9 Sep 2025 12:28:07 +0300 Subject: [PATCH 144/228] Impl [Monitoring app] In application UI add useful links (#3423) --- src/api/modelEndpoints-api.js | 9 +++++++++ .../FilterMenu/filterMenu.settings.js | 19 ++++++++++++++++++- .../ModelEndpoints/ModelEndpointsFilters.jsx | 8 ++++++-- .../ModelEndpoints/modelEndpoints.util.jsx | 9 ++++++++- .../MonitoringApplicationCard.jsx | 3 +++ .../monitoringApplicationCounters.scss | 7 +++++++ .../monitoringApplicationCounters.util.jsx | 12 ++++++++++-- src/constants.js | 3 +++ .../ApplicationTableRow.jsx | 2 +- .../applicationTableRow.scss | 2 ++ 10 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/api/modelEndpoints-api.js b/src/api/modelEndpoints-api.js index eac2ab097c..d28f4c92e6 100644 --- a/src/api/modelEndpoints-api.js +++ b/src/api/modelEndpoints-api.js @@ -18,6 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import { mainHttpClient } from '../httpClient' +import { BATCH_FILTER, FILTER_ALL_ITEMS, ME_MODE_FILTER, REAL_TIME_FILTER } from '../constants' const modelEndpointsApi = { getModelEndpoint: (project, name, uid) => @@ -25,6 +26,10 @@ const modelEndpointsApi = { `/projects/${project}/model-endpoints/${name}?endpoint_id=${uid}&feature_analysis=true` ), getModelEndpoints: (project, filters, config = {}, params = {}) => { + const modesMap = { + [REAL_TIME_FILTER]: 0, + [BATCH_FILTER]: 1 + } const newConfig = { ...config, params @@ -34,6 +39,10 @@ const modelEndpointsApi = { newConfig.params.label = filters.labels?.split(',') } + if (filters[ME_MODE_FILTER] && filters[ME_MODE_FILTER] !== FILTER_ALL_ITEMS) { + newConfig.params.mode = modesMap[filters[ME_MODE_FILTER]] + } + return mainHttpClient.get(`/projects/${project}/model-endpoints`, newConfig) }, getModelEndpointMetrics: (project, uid, type = 'all') => diff --git a/src/components/FilterMenu/filterMenu.settings.js b/src/components/FilterMenu/filterMenu.settings.js index 977a474d26..406fe98cf3 100644 --- a/src/components/FilterMenu/filterMenu.settings.js +++ b/src/components/FilterMenu/filterMenu.settings.js @@ -42,7 +42,9 @@ import { SORT_BY, STATUS_FILTER, TAG_FILTER_ALL_ITEMS, - TAG_FILTER_LATEST + TAG_FILTER_LATEST, + REAL_TIME_FILTER, + BATCH_FILTER } from '../../constants' export const jobsStatuses = [ @@ -107,6 +109,21 @@ export const generateTypeFilter = tab => { ] } +export const modelEndpointsModesList = [ + { + id: FILTER_ALL_ITEMS, + label: 'All' + }, + { + id: REAL_TIME_FILTER, + label: 'Real-time' + }, + { + id: BATCH_FILTER, + label: 'Batch' + } +] + export const filterSelectOptions = { [STATUS_FILTER]: generateStatusFilter(false), [GROUP_BY_FILTER]: [ diff --git a/src/components/ModelsPage/ModelEndpoints/ModelEndpointsFilters.jsx b/src/components/ModelsPage/ModelEndpoints/ModelEndpointsFilters.jsx index 7505a6a7b7..e4134e48ca 100644 --- a/src/components/ModelsPage/ModelEndpoints/ModelEndpointsFilters.jsx +++ b/src/components/ModelsPage/ModelEndpoints/ModelEndpointsFilters.jsx @@ -17,9 +17,10 @@ such restriction. import React from 'react' import { useForm } from 'react-final-form' -import { FormInput, FormOnChange } from 'igz-controls/components' +import { FormInput, FormOnChange, FormSelect } from 'igz-controls/components' -import { LABELS_FILTER } from '../../../constants' +import { modelEndpointsModesList } from '../../FilterMenu/filterMenu.settings' +import { LABELS_FILTER, ME_MODE_FILTER } from '../../../constants' const ModelEndpointsFilters = () => { const form = useForm() @@ -30,6 +31,9 @@ const ModelEndpointsFilters = () => { return (
      +
      + +
      ) : error || isNil(counter.title) ? ( 'N/A' + ) : counter.link ? ( + {counter.title} ) : ( counter.title )} diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss index b3bb9fed24..7f1f0857df 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss @@ -21,6 +21,13 @@ cursor: pointer; } + &__link:hover { + color: colors.$topaz; + text-decoration: underline; + text-underline-offset: 1px; + text-decoration-thickness: 1px; + } + .stats-card__row:last-child { padding-bottom: 10px; } diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index 77a1572441..100593f582 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -20,6 +20,12 @@ such restriction. import { capitalize } from 'lodash' import { formatMinutesToString } from '../../../../utils/measureTime' +import { + BATCH_FILTER, ME_MODE_FILTER, + MODEL_ENDPOINTS_TAB, + MODELS_PAGE, + REAL_TIME_FILTER +} from '../../../../constants' export const generateCountersContent = (params, monitoringApplicationsStore) => { const { @@ -64,13 +70,15 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => title: 'Endpoints', counterData: [ { - id: 'batch', + id: BATCH_FILTER, title: applicationsSummary.batch_model_endpoint_count, + link: `/projects/${params.projectName}/${MODELS_PAGE}/${MODEL_ENDPOINTS_TAB}?${ME_MODE_FILTER}=${BATCH_FILTER}`, subtitle: 'Batch' }, { - id: 'realTime', + id: REAL_TIME_FILTER, title: applicationsSummary.real_time_model_endpoint_count, + link: `/projects/${params.projectName}/${MODELS_PAGE}/${MODEL_ENDPOINTS_TAB}?${ME_MODE_FILTER}=${REAL_TIME_FILTER}`, subtitle: 'Real-time' } ] diff --git a/src/constants.js b/src/constants.js index e248057a67..fa0298e0f9 100644 --- a/src/constants.js +++ b/src/constants.js @@ -368,8 +368,11 @@ export const GROUP_BY_FILTER = 'groupBy' export const ITERATIONS_FILTER = 'iter' export const LABELS_FILTER = 'labels' export const NAME_FILTER = 'name' +export const ME_MODE_FILTER = 'me-mode' export const DATES_FILTER = 'dates' export const PROJECT_FILTER = 'project' +export const REAL_TIME_FILTER = 'realTime' +export const BATCH_FILTER = 'batch' export const TYPE_FILTER = 'type' export const SHOW_UNTAGGED_FILTER = 'showUntagged' export const SORT_BY = 'sortBy' diff --git a/src/elements/ApplicationTableRow/ApplicationTableRow.jsx b/src/elements/ApplicationTableRow/ApplicationTableRow.jsx index e1c362032e..ac9b9dcc1e 100644 --- a/src/elements/ApplicationTableRow/ApplicationTableRow.jsx +++ b/src/elements/ApplicationTableRow/ApplicationTableRow.jsx @@ -28,7 +28,7 @@ import { ACTIONS_MENU } from 'igz-controls/types' import './applicationTableRow.scss' const ApplicationTableRow = ({ actionsMenu, hideActionsMenu = false, rowItem }) => { - const rowClassNames = classnames('table-row', 'table-body-row', 'parent-row') + const rowClassNames = classnames('table-row', 'table-body-row', 'parent-row', 'application-table-row') return (
      diff --git a/src/elements/ApplicationTableRow/applicationTableRow.scss b/src/elements/ApplicationTableRow/applicationTableRow.scss index a453fe793f..152d8298cc 100644 --- a/src/elements/ApplicationTableRow/applicationTableRow.scss +++ b/src/elements/ApplicationTableRow/applicationTableRow.scss @@ -1,5 +1,7 @@ +.application-table-row { .table-body__cell { a { display: flex; } } +} From d0108fd2652ed5aa300bc6391300293e401d9ea4 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Tue, 9 Sep 2025 13:38:26 +0300 Subject: [PATCH 145/228] Fix [Pipelines] Remove the Retry and Terminate options from the Action Bar in Workflow (#3424) --- .../Jobs/MonitorWorkflows/monitorWorkflows.util.jsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx index 080020f8eb..c0b96812b1 100644 --- a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx +++ b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import React from 'react' -import { debounce } from 'lodash' +import { debounce, isNil } from 'lodash' import { FUNCTIONS_PAGE, @@ -145,6 +145,7 @@ export const generateActionsMenu = ( ] ] } else { + const accessKeyExists = !isNil(job?.access_key) const runningStates = ['running', 'pending', 'terminating'] return [ @@ -156,7 +157,7 @@ export const generateActionsMenu = ( }, { disabled: rerunIsDisabled || [PENDING_STATE, UNKNOWN_STATE].includes(job?.state?.value), - hidden: runningStates.includes(job?.state?.value), + hidden: runningStates.includes(job?.state?.value) || accessKeyExists, icon: , label: 'Retry', onClick: () => handleRerun(job), @@ -169,7 +170,7 @@ export const generateActionsMenu = ( icon: , className: 'danger', onClick: handleConfirmTerminateWorkflow, - hidden: !ce && !accessibleProjectsMap[job?.project], + hidden: (!ce && !accessibleProjectsMap[job?.project]) || accessKeyExists, disabled: job?.state?.value !== FUNCTION_RUNNING_STATE } ] From 159e6a05de30705449738ee3a5b4ff18d1edc294 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Wed, 10 Sep 2025 11:09:28 +0300 Subject: [PATCH 146/228] Fix [Monitoring app] Date picker issues (#3427) --- src/common/DatePicker/DatePicker.jsx | 13 +++++++------ tests/mockServer/data/metrics.json | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/common/DatePicker/DatePicker.jsx b/src/common/DatePicker/DatePicker.jsx index 8dd8806962..70e2a9d874 100644 --- a/src/common/DatePicker/DatePicker.jsx +++ b/src/common/DatePicker/DatePicker.jsx @@ -116,8 +116,7 @@ const DatePicker = ({ ).filter( option => option.timeFrameMilliseconds <= timeFrameLimit && - (!excludeCustomRange || - option.id !== CUSTOM_RANGE_DATE_OPTION) + (!excludeCustomRange || option.id !== CUSTOM_RANGE_DATE_OPTION) ) }, [customOptions, excludeCustomRange, hasFutureOptions, timeFrameLimit]) @@ -205,6 +204,8 @@ const DatePicker = ({ const validateTimeRange = useCallback( ([dateFrom, dateTo]) => { + const timeFrameLimitRoundedUp = + timeFrameLimit === Infinity ? Infinity : roundSeconds(timeFrameLimit, true).getTime() let timeRangeInvalidMessage = '' let isTimeRangeInvalid = false let timeRangeIsNegative = false @@ -214,12 +215,12 @@ const DatePicker = ({ timeRangeInvalidMessage = '“To” must be later than “From”' timeRangeIsNegative = true isTimeRangeInvalid = true - } else if (dateTo.getTime() - dateFrom.getTime() > timeFrameLimit) { + } else if (dateTo.getTime() - dateFrom.getTime() > timeFrameLimitRoundedUp) { timeRangeInvalidMessage = getTimeFrameWarningMsg(timeFrameLimit) isTimeRangeInvalid = true } } else if (!isRange && dateFrom) { - if (Date.now() - dateFrom.getTime() > timeFrameLimit) { + if (Date.now() - dateFrom.getTime() > timeFrameLimitRoundedUp) { timeRangeInvalidMessage = getTimeFrameWarningMsg(timeFrameLimit) isTimeRangeInvalid = true } @@ -307,7 +308,7 @@ const DatePicker = ({ payload: new Date( datePickerState[configId].visibleDate.getFullYear(), datePickerState[configId].visibleDate.getMonth() + 1, - datePickerState[configId].visibleDate.getDate() + 1 ) }) } @@ -320,7 +321,7 @@ const DatePicker = ({ payload: new Date( datePickerState[configId].visibleDate.getFullYear(), datePickerState[configId].visibleDate.getMonth() - 1, - datePickerState[configId].visibleDate.getDate() + 1 ) }) } diff --git a/tests/mockServer/data/metrics.json b/tests/mockServer/data/metrics.json index d10def30b8..056fc370c0 100644 --- a/tests/mockServer/data/metrics.json +++ b/tests/mockServer/data/metrics.json @@ -61,9 +61,9 @@ "project": "default" }, { - "full_name": "default.monitorAppV2.metric.kld_mean_1", + "full_name": "default.monitorAppV1.metric.kld_mean_1", "type": "metric", - "app": "monitorAppV2", + "app": "monitorAppV1", "name": "kld_mean_1", "project": "default" }, @@ -156,7 +156,7 @@ ] }, { - "full_name": "default.monitorAppV2.metric.kld_mean_1", + "full_name": "default.monitorAppV1.metric.kld_mean_1", "type": "metric", "data": "true", "values": [ From a27e32806566f6defb7c08de02addbe603207864 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Wed, 10 Sep 2025 11:09:45 +0300 Subject: [PATCH 147/228] Fix [Feature vector] Content shifting on action bar in Add to feature vector page (#3426) --- .../AddToFeatureVectorView.jsx | 8 +++---- .../addToFeatureVector.scss | 16 +++++++++++-- src/components/Artifacts/ArtifactsTable.jsx | 23 +++++++++++-------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.jsx b/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.jsx index 6f124dca92..d9f0b89ecf 100644 --- a/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.jsx +++ b/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.jsx @@ -62,9 +62,9 @@ const AddToFeatureVectorView = React.forwardRef( const params = useParams() return (
      -
      - +
      +
      -
      - {(featureStore.loading || featureStore.features.loading) && } -
      + {(featureStore.loading || featureStore.features.loading) && }
      {featureStore.loading || featureStore.features.loading ? null : content.length === 0 ? ( { + const renderHistoryBackLink = () => { + if (!isAllVersions) return null + + return isOnlyTabScreen ? ( +
      + +
      + ) : ( + + ) + } + return (
      - {renderPageTabs && renderPageTabs()} + {renderPageTabs ? renderPageTabs() : renderHistoryBackLink()}
      - {isAllVersions && - (isOnlyTabScreen ? ( -
      - -
      - ) : ( - - ))} + {renderPageTabs && renderHistoryBackLink()} {artifactsStore.loading ? null : tableContent.length === 0 && isEmpty(selectedArtifact) ? ( Date: Mon, 15 Sep 2025 10:32:42 +0300 Subject: [PATCH 148/228] Fix [CE] UI crash in monitoring-app screen (#3428) --- src/utils/createApplicationContent.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/createApplicationContent.jsx b/src/utils/createApplicationContent.jsx index 402ee2584a..290df160ca 100644 --- a/src/utils/createApplicationContent.jsx +++ b/src/utils/createApplicationContent.jsx @@ -60,7 +60,7 @@ export const createApplicationContent = (application, projectName) => { headerId: 'commitedOffset', tip: 'Total number of messages handled by the app', headerLabel: 'Commited offset', - value: application.stats.stream_stats.committed ?? 0, + value: application.stats.stream_stats?.committed ?? 0, className: 'table-cell-2' }, { From c9bdae1ea7cfd6ffcf11f020248470f8fae6b7a8 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:30:22 +0300 Subject: [PATCH 149/228] Impl [Monitoring apps] status KPI will be taken from the nuclio functions status (#3430) --- .../monitoringApplicationCounters.util.jsx | 22 +++++++--- src/constants.js | 1 + src/reducers/monitoringApplicationsReducer.js | 40 +++++++++++++++---- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index 100593f582..b0673b71a9 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -21,10 +21,14 @@ import { capitalize } from 'lodash' import { formatMinutesToString } from '../../../../utils/measureTime' import { - BATCH_FILTER, ME_MODE_FILTER, + BATCH_FILTER, + ERROR_STATE, + FUNCTION_READY_STATE, + ME_MODE_FILTER, MODEL_ENDPOINTS_TAB, MODELS_PAGE, - REAL_TIME_FILTER + REAL_TIME_FILTER, + UNHEALTHY_STATE } from '../../../../constants' export const generateCountersContent = (params, monitoringApplicationsStore) => { @@ -36,6 +40,14 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => error: monitoringApplicationError } = monitoringApplicationsStore + const { ready: appReady, error: appError } = monitoringApplications.applications.reduce( + (acc, { status }) => ({ + ready: acc.ready + (status === FUNCTION_READY_STATE ? 1 : 0), + error: acc.error + ([ERROR_STATE, UNHEALTHY_STATE].includes(status) ? 1 : 0) + }), + { ready: 0, error: 0 } + ) + const applicationsCountersContent = [ { id: 'applicationsStatus', @@ -53,13 +65,13 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => counterData: [ { id: 'running', - title: applicationsSummary.running_model_monitoring_functions, + title: appReady, subtitle: 'Running', subtitleStatus: 'running' }, { id: 'failed', - title: applicationsSummary.failed_model_monitoring_functions, + title: appError, subtitle: 'Failed', subtitleStatus: 'failed' } @@ -162,7 +174,7 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => } : { content: applicationsCountersContent, - loading: applicationsSummary.loading, + loading: applicationsSummary.loading || monitoringApplicationIsLoading, error: applicationsSummary.error } } diff --git a/src/constants.js b/src/constants.js index fa0298e0f9..a88b4e0a80 100644 --- a/src/constants.js +++ b/src/constants.js @@ -50,6 +50,7 @@ export const ERROR_STATE = 'error' export const FAIL_STATE = 'fail' export const FAILED_STATE = 'failed' export const PENDING_STATE = 'pending' +export const UNHEALTHY_STATE = 'unhealthy' export const UNKNOWN_STATE = 'unknown' /*=========== PAGINATION =============*/ diff --git a/src/reducers/monitoringApplicationsReducer.js b/src/reducers/monitoringApplicationsReducer.js index b2a0fd8554..0599ffa3c1 100644 --- a/src/reducers/monitoringApplicationsReducer.js +++ b/src/reducers/monitoringApplicationsReducer.js @@ -18,10 +18,12 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import { createSlice, createAsyncThunk } from '@reduxjs/toolkit' +import { get } from 'lodash' import { defaultPendingHandler, defaultRejectedHandler } from './redux.util' import { splitApplicationsContent } from '../utils/applications.utils' import monitoringApplicationsApi from '../api/monitoringApplications-api' +import nuclioApi from '../api/nuclio' import { DATES_FILTER } from '../constants' const initialState = { @@ -60,12 +62,15 @@ export const fetchMEPWithDetections = createAsyncThunk( const savedStartDate = filters[DATES_FILTER].value[0].getTime() const savedEndDate = (filters[DATES_FILTER].value[1] || new Date()).getTime() - + return monitoringApplicationsApi.getMEPWithDetections(project, params).then(response => { return { - values: response.data.values.map(([date, suspected, detected]) => [date, suspected + detected]), - start: savedStartDate, - end: savedEndDate + values: response.data.values.map(([date, suspected, detected]) => [ + date, + suspected + detected + ]), + start: savedStartDate, + end: savedEndDate } }) } @@ -90,7 +95,7 @@ export const fetchMonitoringApplication = createAsyncThunk( export const fetchMonitoringApplications = createAsyncThunk( 'fetchMonitoringApplications', - ({ project, filters }) => { + async ({ project, filters }) => { const params = { start: filters[DATES_FILTER].value[0].getTime() } @@ -99,9 +104,30 @@ export const fetchMonitoringApplications = createAsyncThunk( params.end = filters[DATES_FILTER].value[1].getTime() } - return monitoringApplicationsApi.getMonitoringApplications(project, params).then(response => { - return splitApplicationsContent(response.data) + const [mlrunResult, nuclioResult] = await Promise.allSettled([ + monitoringApplicationsApi.getMonitoringApplications(project, params), + nuclioApi.getFunctions(project) + ]) + + if (mlrunResult.status !== 'fulfilled') { + throw new Error(mlrunResult.reason) + } + + const mlrunApiApps = get(mlrunResult, 'value.data') + const nuclioApiApps = get(nuclioResult, 'value.data') + + const splitApps = splitApplicationsContent(mlrunApiApps) + + const applications = splitApps.applications.map(mlrunApp => { + const match = nuclioApiApps[`${mlrunApp.project_name}-${mlrunApp.name}`] + + return { + ...mlrunApp, + status: match?.status?.state ?? mlrunApp.status + } }) + + return { ...splitApps, applications } } ) From 444c5914e6c4c60b03c853e7b9191cbf9df89c1c Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:32:37 +0300 Subject: [PATCH 150/228] Fix [Jobs] Missing (current) project in batch run functions dropdown (#3431) --- package.json | 2 +- .../JobWizardFunctionSelection.jsx | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2379ee692f..63bdfb3409 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.9", + "iguazio.dashboard-react-controls": "3.1.10", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx index 6799395a2d..086d8601b6 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx @@ -423,7 +423,11 @@ const JobWizardFunctionSelection = ({
      - +
      {!loading && From fd6db7e0ab47161b9f0868f811b865c6863b0698 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:07:56 +0300 Subject: [PATCH 151/228] Fix [Alerts] Multiple issues on Alerts tab in Model Endpoints page (#3432) --- src/components/Alerts/alerts.util.js | 1 - src/components/DetailsAlerts/DetailsAlerts.jsx | 6 +++++- .../ModelsPage/ModelEndpoints/modelEndpoints.util.jsx | 3 +-- src/elements/AlertsTable/alertsTable.scss | 9 +++++++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/components/Alerts/alerts.util.js b/src/components/Alerts/alerts.util.js index 1d73511fde..9c99aee72c 100644 --- a/src/components/Alerts/alerts.util.js +++ b/src/components/Alerts/alerts.util.js @@ -66,7 +66,6 @@ export const getAlertsFiltersConfig = (timeFrameLimit = false, isAlertsPage = fa datePickerPastOptions, isAlertsPage ? PAST_MONTH_DATE_OPTION : PAST_24_HOUR_DATE_OPTION ), - hidden: isAlertsPage, label: 'Start time:', timeFrameLimit: timeFrameLimit ? TIME_FRAME_LIMITS.MONTH : Infinity }, diff --git a/src/components/DetailsAlerts/DetailsAlerts.jsx b/src/components/DetailsAlerts/DetailsAlerts.jsx index da56359a67..0d185b9924 100644 --- a/src/components/DetailsAlerts/DetailsAlerts.jsx +++ b/src/components/DetailsAlerts/DetailsAlerts.jsx @@ -50,7 +50,11 @@ const DetailsAlerts = () => { parseAlertsQueryParamsCallback ) - const { alerts, requestErrorMessage } = useRefreshAlerts(alertsFilters) + const filters = useMemo(() => { + return {...alertsFilters, 'entity-type': 'model-endpoint-result'} + }, [alertsFilters]) + + const { alerts, requestErrorMessage } = useRefreshAlerts(filters) const tableContent = useMemo(() => { if (alerts) { diff --git a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx index 659701a466..a86e62fb79 100644 --- a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx +++ b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx @@ -72,8 +72,7 @@ const detailsMenu = [ { label: 'alerts', id: 'alerts', - icon: , - query: '?entity-type=model-endpoint-result' //TODO: temp solution for query params + icon: } ] diff --git a/src/elements/AlertsTable/alertsTable.scss b/src/elements/AlertsTable/alertsTable.scss index cacc33b538..0bf9fe21ab 100644 --- a/src/elements/AlertsTable/alertsTable.scss +++ b/src/elements/AlertsTable/alertsTable.scss @@ -4,6 +4,15 @@ &__wrapper { display: flex; height: 100%; + + .table__flex { + width: 100%; + min-width: 800px; + } + + .table__content { + width: 100%; + } } &__content-info { From 8d5d7f2ae4196dd7a5605aec61f547ca802776c6 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:25:38 +0300 Subject: [PATCH 152/228] Fix [Monitoring app] Application view starts in middle of page after drill-down (#3433) --- .../MonitoringApplicationsPage.jsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index 168c4a917c..e2041ecd30 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useCallback, useEffect, useMemo } from 'react' +import React, { useCallback, useEffect, useMemo, useRef } from 'react' import { Outlet, useNavigate, useParams, useSearchParams } from 'react-router-dom' import { useDispatch } from 'react-redux' @@ -50,6 +50,7 @@ const MonitoringApplicationsPage = () => { const filtersConfig = useMemo(() => getFiltersConfig(), []) const filters = useFiltersFromSearchParams(filtersConfig) const [, setSearchParams] = useSearchParams() + const contentRef = useRef(null) const refreshMonitoringApplications = useCallback( (filters, isFilterApplyAction) => { @@ -129,12 +130,18 @@ const MonitoringApplicationsPage = () => { } }, [params.name, refreshMonitoringApplications, refreshMonitoringApplication, filters]) + useEffect(() => { + if (contentRef.current) { + contentRef.current.scrollTo(0, 0) + } + }, [params.name]) + return (
      -
      +
      {params.name && ( From 586c44f809b4517783c4dfdc9685821c908a4cfc Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:10:36 +0300 Subject: [PATCH 153/228] Fix [LLM prompt ] Failure message not clear when try to add exist tag to prompt artifact (#3434) --- src/components/LLMPrompts/llmPrompts.util.jsx | 2 +- src/constants.js | 4 +++- .../AddArtifactTagPopUp/AddArtifactTagPopUp.jsx | 10 +++------- src/utils/artifacts.util.js | 10 +++++++--- src/utils/createArtifact.util.js | 4 ++++ 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/components/LLMPrompts/llmPrompts.util.jsx b/src/components/LLMPrompts/llmPrompts.util.jsx index 42e9dbe562..082e05e69e 100644 --- a/src/components/LLMPrompts/llmPrompts.util.jsx +++ b/src/components/LLMPrompts/llmPrompts.util.jsx @@ -246,7 +246,7 @@ export const generateActionsMenu = ( }, { label: 'Preview', - id: 'llm-prompt-preview', + id: 'artifact-preview', disabled: !isTargetPathValid, icon: , onClick: llmPromptMin => { diff --git a/src/constants.js b/src/constants.js index a88b4e0a80..45c67fce0a 100644 --- a/src/constants.js +++ b/src/constants.js @@ -286,6 +286,7 @@ export const FUNCTION_FILTERS = 'FUNCTION_FILTERS' export const ARTIFACTS_TAB = 'artifacts' export const ARTIFACT_PREVIEW_TABLE_ROW_LIMIT = 100 +export const LLM_PROMPT_TITLE = 'LLM prompt' /*=========== DETAILS =============*/ @@ -501,4 +502,5 @@ export const RESULT_TYPE = 'result' /*========= GENERAL TEXT =============*/ -export const COUNTERS_GENERAL_MESSAGE = 'Counters use a caching mechanism, and are not auto-refreshed.' \ No newline at end of file +export const COUNTERS_GENERAL_MESSAGE = + 'Counters use a caching mechanism, and are not auto-refreshed.' diff --git a/src/elements/AddArtifactTagPopUp/AddArtifactTagPopUp.jsx b/src/elements/AddArtifactTagPopUp/AddArtifactTagPopUp.jsx index 34ca785736..8358f79f2d 100644 --- a/src/elements/AddArtifactTagPopUp/AddArtifactTagPopUp.jsx +++ b/src/elements/AddArtifactTagPopUp/AddArtifactTagPopUp.jsx @@ -27,10 +27,7 @@ import { createForm } from 'final-form' import { Button, FormInput, Modal, Loader } from 'igz-controls/components' import { DATASET_TYPE, MODEL_TYPE, TAG_LATEST } from '../../constants' -import { - PRIMARY_BUTTON, - TERTIARY_BUTTON -} from 'igz-controls/constants' +import { PRIMARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' import { addTag } from '../../reducers/artifactsReducer' import { getValidationRules } from 'igz-controls/utils/validation.util' import { setNotification } from 'igz-controls/reducers/notificationReducer' @@ -106,9 +103,8 @@ const AddArtifactTagPopUp = ({ artifact, isOpen, onAddTag = () => {}, onResolve, getCustomErrorMsg: () => 'Failed to add a tag', onErrorCallback: resolveModal, showLoader: () => setIsLoading(true), - hideLoader: () => setIsLoading(false), - } - ) + hideLoader: () => setIsLoading(false) + }) } const getModalActions = formState => { diff --git a/src/utils/artifacts.util.js b/src/utils/artifacts.util.js index e86d3cd180..0bc767e103 100644 --- a/src/utils/artifacts.util.js +++ b/src/utils/artifacts.util.js @@ -34,7 +34,9 @@ import { MODELS_PAGE, TAG_FILTER_ALL_ITEMS, TAG_FILTER_LATEST, - ALL_VERSIONS_PATH + ALL_VERSIONS_PATH, + LLM_PROMPT_TYPE, + LLM_PROMPT_TITLE } from '../constants' import { VIEW_SEARCH_PARAMETER } from 'igz-controls/constants' import { @@ -169,7 +171,9 @@ export const processActionAfterTagUniquesValidation = ({ closePopUp: () => reject(), header: messagesByKind.overwriteConfirmTitle, message: messagesByKind.getOverwriteConfirmMessage( - response.data.artifacts[0].kind || ARTIFACT_TYPE + response.data.artifacts[0].kind === LLM_PROMPT_TYPE + ? LLM_PROMPT_TITLE + : response.data.artifacts[0].kind || ARTIFACT_TYPE ), className: 'override-artifact-dialog' }) @@ -197,7 +201,7 @@ export const processActionAfterTagUniquesValidation = ({ onErrorCallback?.() hideLoader() - + if (throwError) throw error }) } diff --git a/src/utils/createArtifact.util.js b/src/utils/createArtifact.util.js index 75c69ef43c..e4d431e104 100644 --- a/src/utils/createArtifact.util.js +++ b/src/utils/createArtifact.util.js @@ -41,5 +41,9 @@ export const createArtifactMessages = { model: { overwriteConfirmTitle: 'Overwrite model?', getOverwriteConfirmMessage + }, + 'llm-prompt': { + overwriteConfirmTitle: 'Overwrite LLM prompt?', + getOverwriteConfirmMessage } } From 23cf9a0f1ac787b3bbca3d0e43ad884fdf194d2b Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Wed, 17 Sep 2025 12:53:34 +0300 Subject: [PATCH 154/228] Fix [Monitoring app] Change MEP with detections request (#3436) --- src/api/monitoringApplications-api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/monitoringApplications-api.js b/src/api/monitoringApplications-api.js index 64da43979a..74c34aa548 100644 --- a/src/api/monitoringApplications-api.js +++ b/src/api/monitoringApplications-api.js @@ -21,7 +21,7 @@ import { mainHttpClient } from '../httpClient' const monitoringApplications = { getMEPWithDetections: (project, params) => - mainHttpClient.get(`projects/${project}/model-endpoints/drift-over-time`, { + mainHttpClient.get(`projects/${project}/model-monitoring/drift-over-time`, { params }), getMonitoringApplication: (project, functionName, params) => From 9023cb44727560b10a2823299ebe20d710535eb6 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Wed, 17 Sep 2025 16:00:17 +0300 Subject: [PATCH 155/228] Fix [Feature store] make "transformation" graph static (#3437) --- .../DetailsTransformations/detailsTransformations.scss | 1 + src/scss/main.scss | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/DetailsTransformations/detailsTransformations.scss b/src/components/DetailsTransformations/detailsTransformations.scss index 3d93fd430d..03a7bd3b7b 100644 --- a/src/components/DetailsTransformations/detailsTransformations.scss +++ b/src/components/DetailsTransformations/detailsTransformations.scss @@ -4,6 +4,7 @@ .transformations-tab { display: flex; flex: 1 1; + height: 100%; .graph-pane { .config-item { diff --git a/src/scss/main.scss b/src/scss/main.scss index 897e1fb6a3..daee56e3ac 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -315,7 +315,7 @@ main { flex-direction: column; width: 25%; min-width: 350px; - overflow: hidden; + overflow-y: auto; background: colors.$white; border: borders.$secondaryBorder; box-shadow: 0 0 30px rgba(colors.$black, 0.15); From caaf86cd4b364c80eb94a7402c1b5ae4e7cdc7bf Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Sat, 20 Sep 2025 09:44:10 +0300 Subject: [PATCH 156/228] Fix [LLM Prompts] Prompt not displayed via target path (#3439) --- src/components/Details/DetailsPromptTemplate/PromptTab.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx index f23ca7bb90..8781fdf792 100644 --- a/src/components/Details/DetailsPromptTemplate/PromptTab.jsx +++ b/src/components/Details/DetailsPromptTemplate/PromptTab.jsx @@ -120,7 +120,10 @@ const PromptTab = ({ ) } } else if (isEmpty(artifactsStore.LLMPrompts.promptTemplate)) { - if (!selectedItem.target_path.endsWith('.txt')) { + if ( + !selectedItem.target_path.endsWith('.txt') && + !selectedItem.target_path.endsWith('.json') + ) { setShowError(true) } else { setLoading(true) From 0fb17d19ed965096165648afe48d140128c36907 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Sat, 20 Sep 2025 09:50:53 +0300 Subject: [PATCH 157/228] Bump DRC version to `3.1.11` (#3441) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 63bdfb3409..bec888acc5 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.10", + "iguazio.dashboard-react-controls": "3.1.11", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", From 9468168cb09f130deb340e3ee4e9b636cded3849 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Sat, 20 Sep 2025 09:52:50 +0300 Subject: [PATCH 158/228] Fix [Artifacts] Download notification not interactable (#3438) --- src/common/Download/DownloadItem.jsx | 6 +++++- src/common/Download/downloadContainer.scss | 12 ++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/common/Download/DownloadItem.jsx b/src/common/Download/DownloadItem.jsx index 7b02b79581..e5b89d3cfa 100644 --- a/src/common/Download/DownloadItem.jsx +++ b/src/common/Download/DownloadItem.jsx @@ -180,7 +180,11 @@ const DownloadItem = ({ downloadItem }) => { return (
      - }> + } + > {file}
      diff --git a/src/common/Download/downloadContainer.scss b/src/common/Download/downloadContainer.scss index 6c4fbb1b2a..d5219a3bb2 100644 --- a/src/common/Download/downloadContainer.scss +++ b/src/common/Download/downloadContainer.scss @@ -1,21 +1,25 @@ @use 'igz-controls/scss/colors'; @use 'igz-controls/scss/shadows'; +.tooltip.download-item__filename-tooltip { + z-index: 10; +} + .download-container { position: relative; - z-index: 9; + z-index: 10; align-self: flex-end; - opacity: 0; width: 220px; min-height: 90px; max-height: 200px; + margin-right: 24px; + margin-bottom: 10px; padding: 15px; color: colors.$white; background-color: colors.$darkPurple; border-radius: 5px; box-shadow: shadows.$tooltipShadow; - margin-right: 24px; - margin-bottom: 10px; + opacity: 0; &__header { margin-bottom: 15px; From b96fb4576dc665c78561757527db235de8b9fbb5 Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Sat, 20 Sep 2025 08:54:17 +0200 Subject: [PATCH 159/228] Tests [QA] v1.10.0-rc27 (#3440) --- package.json | 2 +- tests/features/common-tools/common-consts.js | 19 +- .../common/page-objects/info-pane.po.js | 2 +- .../common/page-objects/monitoring-app.po.js | 22 +- .../common/page-objects/project.po.js | 28 +- .../common/page-objects/projects.po.js | 58 ++-- tests/features/featureStore.feature | 1 + tests/features/jobsAndWorkflows.feature | 27 +- tests/features/jobsMonitoring.feature | 315 +++++++++++++++--- tests/features/models.feature | 6 +- tests/features/monitoringApp.feature | 44 +-- tests/features/projectMonitoring.feature | 60 ++-- tests/features/projectsPage.feature | 67 ++-- tests/mockServer/data/run.json | 41 +++ tests/mockServer/data/runs.json | 41 +++ 15 files changed, 513 insertions(+), 220 deletions(-) diff --git a/package.json b/package.json index bec888acc5..3c73efda4d 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "babel-runtime": "^6.26.0", "body-parser": "^1.19.0", "chai": "^4.3.4", - "chromedriver": "^138.0.0", + "chromedriver": "^140.0.0", "cross-env": "^7.0.3", "css-loader": "^6.5.1", "cucumber-html-reporter": "^5.3.0", diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index 8b5d2fc62a..d0b1c0809a 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -34,9 +34,10 @@ export default { 'Train model', 'Batch inference', 'Create real-time function', + 'Register model', 'ML function', 'Feature set', - 'Register model' + 'Create feature vector' ], Online_Status: 'online', Data_Collection_Description: @@ -535,6 +536,7 @@ export default { ' You can browse them in the Artifacts page.', Model_Endpoint_With_Detections: 'This chart displays the number of model endpoints that had at least one detected issue, in any monitoring application, in the relevant time period', + Project_Monitoring_Counters: 'Counters use a caching mechanism, and are not auto-refreshed.', Operating_Functions: 'System functions that are used for the monitoring application operation', Lag: 'Number of messages currently waiting in the app\'s queue', Commited_Offset: 'Total number of messages handled by the app', @@ -576,11 +578,13 @@ export default { Terminate_Workflow_Message: /Are you sure you want to terminate the workflow "(.+?)" \(stop its execution\)\? Workflows termination cannot be undone\./, Workflows_Action_Menu_Options: ['View YAML', 'Retry', 'Terminate'], Workflows_Running_Action_Menu_Options: ['View YAML', 'Terminate'], - Workflows_Info_Pane_Action_Menu_Options: ['Batch re-run', 'Monitoring', 'View YAML', 'Delete', 'Terminate'], + Workflows_Info_Pane_Action_Menu_Options: ['Batch re-run', 'Monitoring', 'View YAML', 'Delete'], Pending_Job_Action_Menu_Options: ['Batch re-run', 'Run\'s resource monitoring', 'Abort', 'View YAML'], Schedule_Action_Menu_Options: ['Run now', 'Edit', 'Delete', 'View YAML'], Workflows_Unsuccessful_Run_Message: 'Workflow did not run successfully\nRETRY', - Workflows_Unsuccessful_Terminate_Message: 'Workflow "stocks-admin-main 2021-08-30 05-36-35 failed to terminate' + Workflows_Successful_Run_Message: 'Workflow run successfully.', + Workflows_Unsuccessful_Terminate_Message: 'Workflow "stocks-admin-main 2021-08-30 05-36-35 failed to terminate', + Workflows_Trigger_Termination_Message: 'A request to terminate workflow "stocks-admin-main 2021-08-30 05-36-35" was issued' }, Jobs_Monitor_Tab_Info_Pane: { Pending_State: 'Pending', @@ -602,8 +606,8 @@ export default { 'Log level:', 'Output path:', 'Total iterations:', - 'Retry count:', - 'Maximum retries:' + 'Attempt count:', + 'Maximum attempts:' ] }, Jobs_Monitor_Tab: { @@ -699,7 +703,8 @@ export default { 'Past hour', 'Past 24 hours', 'Past week', - 'Past month' + 'Past month', + 'Custom range' ], Scheduled_Date_Picker_Filter_Options: [ 'Any time', @@ -760,7 +765,7 @@ export default { Common_Message_Jobs_Monitoring_Scheduled: /No data matches the filter: "Scheduled at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, Common_Message_Scheduled_Type: - /No data matches the filter: "Type: (.+?)"/, + /No data matches the filter: "Scheduled at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Type: (.+?)"/, Common_Message: 'No data matches the filter: "Version Tag: latest, Name: ccccc"', Common_Message_Feature: 'No data matches the filter: "Version Tag: latest"', Common_Message_Feature_Vector_Tab: diff --git a/tests/features/common/page-objects/info-pane.po.js b/tests/features/common/page-objects/info-pane.po.js index abf58665ea..cc02bfc567 100644 --- a/tests/features/common/page-objects/info-pane.po.js +++ b/tests/features/common/page-objects/info-pane.po.js @@ -982,7 +982,7 @@ export default { Alerts_FilterBy_Button: By.css('[data-testid="detailsPanel"] [data-testid="filter-menu-btn-tooltip-wrapper"]'), Alerts_Refresh_Button: By.css('[data-testid="detailsPanel"] [data-testid="refresh-tooltip-wrapper"]'), Alerts_Table: commonTable(alertsTable), - Metrics_Stats_Card: By.css('.alert-row__expanded-row .alerts-table__metrics .stats-card') + Metrics_Stats_Card: By.css('.alert-row__expanded-row .alerts-table .stats-card') }, modelsRealTimePipelineInfoPane: { Arrow_Back: commonArrowBack, diff --git a/tests/features/common/page-objects/monitoring-app.po.js b/tests/features/common/page-objects/monitoring-app.po.js index 94b3eb5e84..664711d890 100644 --- a/tests/features/common/page-objects/monitoring-app.po.js +++ b/tests/features/common/page-objects/monitoring-app.po.js @@ -284,22 +284,22 @@ export default { Date_Picker_Filter_Dropdown: commonDatePickerFilter, Custom_Range_Filter_Dropdown: commonCustomRangeFilter, Date_Time_Picker: datepicker(dateTimePickerCalendars), - Applications_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__row:nth-of-type(1) .stats-card__title span'), + Applications_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__row:nth-of-type(1) .stats-card__title .data-ellipsis.tooltip-wrapper'), Applications_Stats_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__row:nth-of-type(2) .stats__counter'), - Apps_Status_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(1) .stats-card__title span'), + Apps_Status_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(1) .stats-card__title .data-ellipsis.tooltip-wrapper'), Apps_Status_Running_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="running_status"] .stats__subtitle'), Apps_Status_Failed_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="failed_status"] .stats__subtitle'), Apps_Status_Running_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-running"] .stats__counter'), Apps_Status_Failed_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-failed"] .stats__counter'), Apps_Status_Running_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="running_status"] i'), Apps_Status_Failed_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__row:nth-of-type(2) [data-testid="failed_status"] i'), - Endpoints_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(1) .stats-card__title span'), + Endpoints_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(1) .stats-card__title .data-ellipsis.tooltip-wrapper'), Endpoints_Batch_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="batch_status"] .stats__subtitle'), Endpoints_RealTime_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="realTime_status"] .stats__subtitle'), Endpoints_Batch_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-batch"] .stats__counter'), Endpoints_RealTime_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-realTime"] .stats__counter'), - RunningFrequency_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__row:nth-of-type(1) .stats-card__title span'), - RunningFrequency_Value_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-undefined"] .stats__counter'), + RunningFrequency_Stats_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__row:nth-of-type(1) .stats-card__title .data-ellipsis.tooltip-wrapper'), + RunningFrequency_Value_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__row:nth-of-type(2) [data-testid="monitoring-app-interval"] .stats__counter'), Model_Endpoint_Detections_Title: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(1) .monitoring-app__section-item:nth-of-type(1) .section-item_title span'), Model_Endpoint_Detections_Tip: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(1) .monitoring-app__section-item:nth-of-type(1) .section-item_title [data-testid="tip"]'), Model_Endpoint_Detections_Chart: By.css('.monitoring-apps .monitoring-app__section:nth-of-type(1) .monitoring-app__section-item:nth-of-type(1) .section-item_chart-wrapper .chart-container'), @@ -321,19 +321,19 @@ export default { Date_Time_Picker: datepicker(dateTimePickerCalendars), Application_Metrics_Button: By.css('.action-bar [data-testid="btn"] span'), Refresh_Button: By.css('.action-bar [data-testid="refresh"] button'), - App_Status_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__title span'), + App_Status_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) .stats-card__title .data-ellipsis.tooltip-wrapper'), App_Status_SubTitle: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(1) [data-testid="monitoring-app-appStatus"] .stats__counter'), - Endpoints_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__title span'), + Endpoints_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) .stats-card__title .data-ellipsis.tooltip-wrapper'), Endpoints_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) [data-testid="tip"] svg'), Endpoints_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(2) [data-testid="monitoring-app-endpoints"] .stats__counter'), - Detections_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__title span'), + Detections_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) .stats-card__title .data-ellipsis.tooltip-wrapper'), Detections_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(3) [data-testid="monitoring-app-detections"] .stats__counter'), - Possible_Detections_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__title span'), + Possible_Detections_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) .stats-card__title .data-ellipsis.tooltip-wrapper'), Possible_Detections_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(4) [data-testid="monitoring-app-possibleDetections"] .stats__counter'), - Lag_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(5) .stats-card__title span'), + Lag_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(5) .stats-card__title .data-ellipsis.tooltip-wrapper'), Lag_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(5) [data-testid="tip"] svg'), Lag_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(5) [data-testid="monitoring-app-lag"] .stats__counter'), - Commited_Offset_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(6) .stats-card__title span'), + Commited_Offset_Title: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(6) .stats-card__title .data-ellipsis.tooltip-wrapper'), Commited_Offset_Tip: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(6) [data-testid="tip"] svg'), Commited_Offset_Counter: By.css('.monitoring-application__statistics-section .stats-card:nth-of-type(6) [data-testid="monitoring-app-commitedOffset"] .stats__counter'), Artifacts_Title: By.css('.monitoring-app__section .section-item_title span'), diff --git a/tests/features/common/page-objects/project.po.js b/tests/features/common/page-objects/project.po.js index 4235e6a469..a5569fff89 100644 --- a/tests/features/common/page-objects/project.po.js +++ b/tests/features/common/page-objects/project.po.js @@ -33,7 +33,7 @@ const quickActionsObject = dropdownComponent( generateDropdownGroup( '.main-info__toolbar .create-new-menu', '.select__header', - '[data-testid="select-body"] [data-testid="select-option"] .tooltip-wrapper', + '[data-testid="select-body"] [data-testid="select-option"]:not(.hidden) .tooltip-wrapper', false ) ) @@ -83,7 +83,7 @@ const runsTable = { header: { root: '.project-data-card__header', sorters: { - title: '.project-data-card__header-text span a', + title: '.project-data-card__header-text a', time_period: '.project-data-card__header-info span', in_process_counter_number: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-value', in_process_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label span', @@ -276,18 +276,18 @@ const shardLagsTable = { export default { project: { - Project_Name: By.css('.main-info .project-details__header'), + Project_Name: By.css('.main-info .page-header__title'), Created_Details: By.css('.project-details__details-label:nth-of-type(1)'), Owner_Details: By.css('.project-details__details-label:nth-of-type(2)'), - Info_Baner: By.css('.main-info__toolbar .main-info__toolbar-banner'), + Info_Baner_Icon: By.css('.main-info .page-header__title [data-testid="tip"] svg'), Quick_Actions: quickActionsObject, Refresh_Button: By.css('[data-testid="refresh"]'), Mono_Values_Cards: By.css('.projects-monitoring-container .projects-monitoring-stats'), Artifacts_Stats_Container: { Artifacts_Stats_Title: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__title .tooltip-wrapper'), - Artifacts_Stats_Counter: By.css('.projects-monitoring-stats > div:nth-child(1) [data-testid="data_total_counter"] .stats__counter'), + Artifacts_Stats_Counter: By.css('.projects-monitoring-stats > div:nth-child(1) [data-testid="artifacts_total_counter"] .stats__counter'), Datasets_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(1) h6'), - Datasets_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(1) .stats__counter'), + Datasets_Counter_Number: By.css('.projects-monitoring-container > div > div:nth-child(1) .stats__details .stats-card__row:nth-of-type(1) .stats__counter'), Documents_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(2) h6'), Documents_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(1) .stats__details .stats-card__row:nth-of-type(2) .stats__counter'), LLM_Prompts_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(3) h6'), @@ -298,7 +298,7 @@ export default { Workflows_Stats_Container: { Workflows_Stats_Title: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__title .tooltip-wrapper'), Filtering_Time_Period: By.css('.projects-monitoring-stats > div:nth-child(2) .project-card__info span'), - Workflows_Stats_Counter: By.css('.projects-monitoring-stats > div:nth-child(2) [data-testid="scheduled_total_counter"] .stats__counter'), + Workflows_Stats_Counter: By.css('.projects-monitoring-stats > div:nth-child(2) [data-testid="wf_total_counter"] .stats__counter'), In_Process_Counter_Subtitle: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(1) h6'), In_Process_Counter_Status_Icon: By.css('.projects-monitoring-stats > div:nth-child(2) .stats-card__row:nth-of-type(1) i.state-running'), In_Process_Counter_Number: By.css('.projects-monitoring-stats > div:nth-child(2) .stats__details .stats-card__row:nth-of-type(1) div:nth-child(2)'), @@ -324,12 +324,12 @@ export default { }, Monitoring_App_Stats_Container: { Monitoring_App_Stats_Title: By.css('.projects-monitoring-stats .application-card .stats-card__title .tooltip-wrapper'), - Monitoring_App_Succeeded_Stats_Counter: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(1) .stats__counter'), - Monitoring_App_Succeeded_Counter_Subtitle: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(1) .stats__label'), - Monitoring_App_Succeeded_Counter_Status_Icon: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(1) .stats__label .state-completed'), - Monitoring_App_Failed_Stats_Counter: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(2) .stats__counter'), - Monitoring_App_Failed_Counter_Subtitle: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(2) .stats__label'), - Monitoring_App_Failed_Counter_Status_Icon: By.css('.projects-monitoring-stats .application-card .stats__container:nth-of-type(2) .stats__label .state-failed') + Monitoring_App_Running_Stats_Counter: By.css('.projects-monitoring-stats .application-card [data-testid="app_running_counter"] .stats__counter'), + Monitoring_App_Running_Counter_Subtitle: By.css('.application-card > div > div:nth-child(2) .stats__details .stats-card__col:nth-of-type(1) .stats__subtitle'), + Monitoring_App_Running_Counter_Status_Icon: By.css('.application-card > div > div:nth-child(2) .stats__details .stats-card__col:nth-of-type(1) .state-running'), + Monitoring_App_Failed_Stats_Counter: By.css('.projects-monitoring-stats .application-card [data-testid="app_failed_counter"] .stats__counter'), + Monitoring_App_Failed_Counter_Subtitle: By.css('.application-card > div > div:nth-child(2) .stats__details .stats-card__col:nth-of-type(2) .stats__subtitle'), + Monitoring_App_Failed_Counter_Status_Icon: By.css('.application-card > div > div:nth-child(2) .stats__details .stats-card__col:nth-of-type(2) .state-failed') }, Alerts_Stats_Container: { Alerts_Stats_Title: By.css('.projects-monitoring-stats > div:nth-child(5) .stats-card__title .tooltip-wrapper'), @@ -345,7 +345,7 @@ export default { }, Runs_Statistic_Table: commonTable(runsTable), Runs_Statistic_Section_Container: { - Runs_Statistic_Section_Title_Tip: By.css('.d-flex:nth-of-type(1) [data-testid="tip"]'), + Runs_Statistic_Section_Title_Tip: By.css('.d-flex:nth-of-type(1) [data-testid="tip"] svg'), In_Process_Counter_Subtitle: By.css('.d-flex:nth-of-type(1) .project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label span'), Failed_Counter_Subtitle: By.css('.d-flex:nth-of-type(1) .project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-label span'), Succeeded_Counter_Subtitle: By.css('.d-flex:nth-of-type(1) .project-data-card__statistics-item:nth-of-type(3) .project-data-card__statistics-label span'), diff --git a/tests/features/common/page-objects/projects.po.js b/tests/features/common/page-objects/projects.po.js index 113267f1d6..6b0d2832c4 100644 --- a/tests/features/common/page-objects/projects.po.js +++ b/tests/features/common/page-objects/projects.po.js @@ -204,59 +204,56 @@ export default { }, Monitoring_Workflows_Box: { Monitoring_Workflows_Box_Title: By.css( - '.projects-monitoring-stats .stats-card:nth-of-type(2) .stats-card__title' + '.projects-monitoring-stats .stats-card:nth-of-type(3) .stats-card__title' ), - Filtering_Time_Period: By.css('.stats-card:nth-of-type(2) .stats-card__col > div > span'), + Filtering_Time_Period: By.css('.stats-card:nth-of-type(3) .stats-card__row > div > span'), Total_Counter_Number: By.css( - '.projects-monitoring-stats > div:nth-child(3) [data-testid="scheduled_total_counter"]' + '.projects-monitoring-stats > div:nth-child(3) [data-testid="wf_total_counter"] .stats__counter' ), - Counter_Running_Status_Number: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_running_counter"] .stats__counter' + Counter_In_Process_Status_Number: By.css( + '.stats-card:nth-of-type(3) [data-testid="wf_running_counter"] .stats__counter' ), - Counter_Running_Status_Subtitle: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_running_counter"] .stats__subtitle' + Counter_In_Process_Status_Subtitle: By.css( + '.stats-card:nth-of-type(3) [data-testid="wf_running_counter"] .stats__subtitle' ), - Counter_Running_Status_Icon: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_running_counter"] .state-running' + Counter_In_Process_Status_Icon: By.css( + '.stats-card:nth-of-type(3) [data-testid="wf_running_counter"] .state-running' ), Counter_Failed_Status_Number: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_failed_counter"] .stats__counter' + '.stats-card:nth-of-type(3) [data-testid="wf_failed_counter"] .stats__counter' ), Counter_Failed_Status_Subtitle: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_failed_counter"] .stats__subtitle' + '.stats-card:nth-of-type(3) [data-testid="wf_failed_counter"] .stats__subtitle' ), Counter_Failed_Status_Icon: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_failed_counter"] .state-failed' + '.stats-card:nth-of-type(3) [data-testid="wf_failed_counter"] .state-failed' ), Counter_Completed_Status_Number: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_completed_counter"] .stats__counter' + '.stats-card:nth-of-type(3) [data-testid="wf_completed_counter"] .stats__counter' ), Counter_Completed_Status_Subtitle: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_completed_counter"] .stats__subtitle' + '.stats-card:nth-of-type(3) [data-testid="wf_completed_counter"] .stats__subtitle' ), Counter_Completed_Status_Icon: By.css( - '.stats-card:nth-of-type(2) [data-testid="wf_completed_counter"] .state-completed' + '.stats-card:nth-of-type(3) [data-testid="wf_completed_counter"] .state-completed' ) }, Monitoring_Scheduled_Box: { Monitoring_Scheduled_Box_Title: By.css( - '.projects-monitoring-stats .stats-card:nth-of-type(3) .stats-card__title' + '.projects-monitoring-stats .stats-card:nth-of-type(4) .stats-card__title' ), - Filtering_Time_Period: By.css('.stats-card:nth-of-type(3) .stats-card__col > div > span'), + Filtering_Time_Period: By.css('.stats-card:nth-of-type(4) .stats-card__row > div > span'), Total_Job_Counter_Title: By.css( - '.stats-card:nth-of-type(3) [data-testid="scheduled_jobs_counter"] .stats__subtitle' + '.stats-card:nth-of-type(4) [data-testid="scheduled_jobs_counter"] .stats__subtitle' ), Total_Workflows_Counter_Title: By.css( - '.stats-card:nth-of-type(3) [data-testid="scheduled_wf_counter"] .stats__subtitle' - ), - Total_Scheduled_Title: By.css( - '.stats-card:nth-of-type(3) .stats-card__col > div > div > span' + '.stats-card:nth-of-type(4) [data-testid="scheduled_workflows_counter"] .stats__subtitle' ), Total_Job_Counter_Number: By.css( - '.stats-card:nth-of-type(3) [data-testid="scheduled_jobs_counter"] .stats__counter' + '.stats-card:nth-of-type(4) [data-testid="scheduled_jobs_counter"] .stats__counter' ), Total_Workflows_Counter_Number: By.css( - '.stats-card:nth-of-type(3) [data-testid="scheduled_wf_counter"] .stats__counter' + '.stats-card:nth-of-type(4) [data-testid="scheduled_workflows_counter"] .stats__counter' ), Total_Scheduled_Number: By.css( '.projects-monitoring-stats > div:nth-child(4) [data-testid="scheduled_total_counter"]' @@ -267,30 +264,27 @@ export default { '.projects-monitoring-stats .alerts-card .stats-card__title .data-ellipsis' ), Monitoring_Alerts_Box_Title_Icon: By.css( - '.projects-monitoring-stats .stats-card:nth-of-type(4) .stats-card__title svg' + '.projects-monitoring-stats .alerts-card .stats-card__title svg' ), - Filtering_Time_Period: By.css('.stats-card:nth-of-type(4) .stats-card__col > div > span'), + Filtering_Time_Period: By.css('.alerts-card .stats-card__row > div > span'), Total_Endpoint_Counter_Number: By.css( - '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_endpoints_counter"]' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_endpoints_counter"] .stats__counter' ), Total_Endpoint_Counter_Title: By.css( '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_endpoints_counter"] h6' ), Total_Jobs_Counter_Number: By.css( - '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_job_counter"]' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_job_counter"] .stats__counter' ), Total_Jobs_Counter_Title: By.css( '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_job_counter"] h6' ), Total_Application_Counter_Number: By.css( - '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_application_counter"]' + '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_application_counter"] .stats__counter' ), Total_Application_Counter_Title: By.css( '.projects-monitoring-stats .alerts-card .stats__details [data-testid="alerts_application_counter"] .stats__subtitle' ), - Total_Alerts_Title: By.css( - '.stats-card:nth-of-type(4) .stats-card__col > div > div > span' - ), Total_Alerts_Number: By.css( '.projects-monitoring-stats .alerts-card [data-testid="alerts_total_counter"]' ) diff --git a/tests/features/featureStore.feature b/tests/features/featureStore.feature index e1f6e9927d..29eabdbbd8 100644 --- a/tests/features/featureStore.feature +++ b/tests/features/featureStore.feature @@ -575,6 +575,7 @@ Feature: Feature Store Page And wait load page And select "Feature Vectors" tab in "Feature_Store_Tab_Selector" on "Feature_Store_Feature_Sets_Tab" wizard Then click on "Table_FilterBy_Button" element on "Feature_Store_Features_Vectors_Tab" wizard + And wait load page When select "test-tag" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index 0b546c0cbd..08cdfb15ab 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -228,6 +228,7 @@ Feature: Jobs and workflows And wait load page When pick up "Custom range" from "03/31/2014 10:30" to "03/21/2015 19:15" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard And wait load page + And wait load page Then verify from "03/31/2014 10:30" to "03/21/2015 19:15" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard When pick up "Custom range" from "03/31/2044 10:30" to "03/21/2015 19:15" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard And wait load page @@ -236,8 +237,8 @@ Feature: Jobs and workflows When pick up "Custom range" from "03/31/2030 10:30" to "03/31/2030 10:31" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard And wait load page Then verify from "03/31/2030 10:30" to "03/31/2030 10:31" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard - When pick up "Custom range" from "03/31/2025 10:31" to "03/21/2025 10:30" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard And wait load page + When pick up "Custom range" from "03/31/2025 10:31" to "03/21/2025 10:30" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard And wait load page Then verify error message in "Date_Time_Picker" on "Jobs_Monitor_Tab" wizard with value "Date_Time_Picker"."Error_Message" @@ -448,6 +449,7 @@ Feature: Jobs and workflows And wait load page Then verify from "11/07/2021 17:00" to "11/08/2021 17:00" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard And wait load page + And wait load page Then value in "datetime" column in "Jobs_Monitor_Table" on "Jobs_Monitor_Tab" wizard should be from "11/07/2021 18:00" to "11/08/2021 18:00" @MLJW @@ -1016,10 +1018,10 @@ Feature: Jobs and workflows And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard - Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is enabled + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is disabled Then verify "Workflow_List_View_Table" element visibility on "Workflows_Monitor_Tab" wizard Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard Then "Terminate_Button" element on "Workflows_Monitor_Tab" should contains "Terminate" value @@ -1052,7 +1054,7 @@ Feature: Jobs and workflows And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard @@ -1369,9 +1371,10 @@ Feature: Jobs and workflows Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard When click on "Delete_Button" element on "Confirm_Popup" wizard And wait load page + And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard @@ -1477,6 +1480,7 @@ Feature: Jobs and workflows # Then verify arrow lines position on "Workflow_Graph" on "Workflows_Monitor_Tab" wizard When click on node with index 2 in "Workflow_Graph" graph on "Workflows_Monitor_Tab" wizard And wait load page + And wait load page Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard Then verify "Updated" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard Then verify "Cross_Close_Button" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard @@ -1515,7 +1519,7 @@ Feature: Jobs and workflows Then "Notification_Pop_Up" element on "Notification_Popup" should contains "The batch run was started" value Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard - When click on cell with value "test-m_ingest" in "name" column in "Jobs_And_Workflows" table on "Project" wizard + When click on cell with value "test-m_ingest" in "name" column in "Runs_Statistic_Table" table on "Project" wizard And wait load page Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard When click on "link" value where option is "Function:" in "Overview_Headers" on "Jobs_Monitor_Tab_Info_Pane" wizard @@ -1587,7 +1591,7 @@ Feature: Jobs and workflows And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard Then click on "Project_Monitoring_Button" element on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard - When click on cell with value "test-m_ingest" in "name" column in "Jobs_And_Workflows" table on "Project" wizard + When click on cell with value "test-m_ingest" in "name" column in "Runs_Statistic_Table" table on "Project" wizard And wait load page When click on "link" value where option is "Function:" in "Overview_Headers" on "Jobs_Monitor_Tab_Info_Pane" wizard And wait load page @@ -2926,11 +2930,11 @@ Feature: Jobs and workflows And wait load page Then value in "status" column with "tooltip" in "Jobs_Monitor_Table" on "Jobs_Monitor_Tab" wizard should contains "Aborting" Then wait for 10 seconds + Then click on "Table_Refresh_Button" element on "Jobs_Monitor_Tab" wizard Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard And wait load page Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Job erann-test (...e19ea57) was aborted" value And wait load page - And wait load page Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard Then verify "Table_Refresh_Button" element visibility on "Jobs_Monitor_Tab" wizard @@ -2941,8 +2945,7 @@ Feature: Jobs and workflows @MLJW @passive @smoke - # retry action is using KFP API and so this can’t be implemented in the mock - https://iguazio.atlassian.net/browse/ML-9124 - #TODO: need to add check Retry option for error and running status + #TODO: need to add check Retry option for error and running status, add check for retryed job visibility Scenario: MLJW087 - Check Retry option in action menu on Workflows Monitor tab Given open url And wait load page @@ -2960,9 +2963,7 @@ Feature: Jobs and workflows And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Run_Message" - Then verify "Retry_Button" element visibility on "Notification_Popup" wizard - Then "Retry_Button" element on "Notification_Popup" should contains "RETRY" value + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Successful_Run_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard diff --git a/tests/features/jobsMonitoring.feature b/tests/features/jobsMonitoring.feature index 29df3fb998..ead871e264 100644 --- a/tests/features/jobsMonitoring.feature +++ b/tests/features/jobsMonitoring.feature @@ -10,7 +10,7 @@ Feature: Jobs Monitoring Page Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then verify "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "Jobs_Monitoring"."Tab_List" @@ -108,7 +108,7 @@ Feature: Jobs Monitoring Page Then "Status_Jobs_Completed_Checkbox" element should be checked on "FilterBy_Popup" wizard Then verify "Jobs_Table" element visibility on "Jobs_Monitoring_Jobs_Tab" wizard And select "crossTab" with "Jobs monitoring" value in breadcrumbs menu - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=completed&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=completed&dates=past24hours&bePage=1&fePage=1" Then click on breadcrumbs "projectsPage" label on "commonPagesHeader" wizard And wait load page When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard @@ -128,7 +128,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Jobs_Tab" wizard When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Jobs_Tab" wizard And wait load page @@ -139,7 +139,9 @@ Feature: Jobs Monitoring Page And wait load page Then value in "name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "test" And select "Scheduled" tab in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Scheduled_Tab" wizard + And wait load page And select "Jobs" tab in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Jobs_Tab" wizard + And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" @@ -189,7 +191,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then verify "BE_Pagination_Navigate_Prev" element visibility on "Pagination_Info_Pane" wizard Then verify "BE_Pagination_Navigate_Prev" element on "Pagination_Info_Pane" wizard is disabled Then verify "BE_Pagination_Navigate_Next" element visibility on "Pagination_Info_Pane" wizard @@ -252,7 +254,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" @@ -297,6 +299,13 @@ Feature: Jobs Monitoring Page And wait load page Then verify "Jobs_Table" element visibility on "Jobs_Monitoring_Jobs_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "6 items selected" + When select "Pending retry" option in "Status_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Jobs_Table" element visibility on "Jobs_Monitoring_Jobs_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard Then select "View YAML" option in action menu on "Jobs_Monitoring_Jobs_Tab" wizard in "Jobs_Table" table at row with "test" value in "name" column @@ -311,7 +320,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" @@ -376,7 +385,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" @@ -512,6 +521,26 @@ Feature: Jobs Monitoring Page And wait load page Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then select "Delete all runs" option in action menu on "Jobs_Monitoring_Jobs_Tab" wizard in "Jobs_Table" table at row with "fesf" value in "name" column + And wait load page + Then verify if "Confirm_Popup" popup dialog appears + Then "Confirm_Dialog_Message" component on "Confirm_Popup" should be equal "Jobs_And_Workflows"."Delete_All_Runs_Message" + Then "Title" element on "Confirm_Popup" should contains "Delete job?" value + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + Then "Cancel_Button" element on "Confirm_Popup" should contains "Cancel" value + Then verify "Cancel_Button" element on "Confirm_Popup" wizard is enabled + Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard + Then "Delete_Button" element on "Confirm_Popup" should contains "Delete" value + When click on "Delete_Button" element on "Confirm_Popup" wizard + And wait load page + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Job is successfully deleted" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Monitor_Jobs_Name" @@ -525,7 +554,7 @@ Feature: Jobs Monitoring Page Then verify "Total_Counter_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then verify "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Workflows_Tab" wizard should contains "Jobs_Monitoring"."Tab_List" @@ -557,13 +586,13 @@ Feature: Jobs Monitoring Page Then verify "Apply_Button" element on "FilterBy_Popup" wizard is disabled Then navigate back And wait load page - Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - When click on "Counter_Running_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard + Then verify "Counter_In_Process_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard + When click on "Counter_In_Process_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page Then verify "Workflows" tab is active in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Workflows_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Workflows_Tab" wizard selected option value "Any time" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard - Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Running" + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Running, Terminating" Then click on "Status_Filter_Element" element on "FilterBy_Popup" wizard Then "Status_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard Then "Status_Workflows_Running_Checkbox" element should be checked on "FilterBy_Popup" wizard @@ -626,7 +655,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard And wait load page @@ -688,12 +717,12 @@ Feature: Jobs Monitoring Page @MLJM @smoke - Scenario: MLJM015 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status + Scenario: MLJM015 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status on main table list Given open url And wait load page When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard And wait load page @@ -729,13 +758,45 @@ Feature: Jobs Monitoring Page And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard When click on cell with row index 1 in "name" column in "Workflows_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard And wait load page Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled + Then click on "Arrow_Back" element on "Workflows_Monitor_Tab_Info_Pane" wizard + And wait load page + Then verify that in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "main 2021-08-30 05-36-35" value in "name" column "Terminate" option is disabled + And wait load page + + @MLJM + @smoke + # !!! restart mock is required + Scenario: MLJM018 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status on workflow runs graph view + Given open url + And wait load page + When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Workflows_Tab" wizard selected option value "Any time" + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "stocks-admin" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify options in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "Running" value in "status" column should contains "Jobs_And_Workflows"."Workflows_Running_Action_Menu_Options" + Then check that "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard is enabled + And wait load page + When click on cell with row index 1 in "name" column in "Workflows_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is enabled Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard Then verify if "Confirm_Popup" popup dialog appears @@ -752,9 +813,42 @@ Feature: Jobs Monitoring Page And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled + Then click on "Arrow_Back" element on "Workflows_Monitor_Tab_Info_Pane" wizard + And wait load page + Then verify that in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "main 2021-08-30 05-36-35" value in "name" column "Terminate" option is disabled + And wait load page + + @MLJM + @smoke + # !!! restart mock is required + Scenario: MLJM019 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status on workflow runs list view + Given open url + And wait load page + When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Workflows_Tab" wizard selected option value "Any time" + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "stocks-admin" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify options in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "Running" value in "status" column should contains "Jobs_And_Workflows"."Workflows_Running_Action_Menu_Options" + Then check that "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard is enabled + And wait load page + When click on cell with row index 1 in "name" column in "Workflows_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is enabled Then verify "Toggle_View_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard Then click on "Toggle_View_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard And wait load page @@ -777,9 +871,42 @@ Feature: Jobs Monitoring Page And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled + Then click on "Arrow_Back" element on "Workflows_Monitor_Tab_Info_Pane" wizard + And wait load page + Then verify that in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "main 2021-08-30 05-36-35" value in "name" column "Terminate" option is disabled + And wait load page + + @MLJM + @smoke + # !!! restart mock is required + Scenario: MLJM020 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status with run detail pane + Given open url + And wait load page + When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Workflows_Tab" wizard selected option value "Any time" + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "stocks-admin" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify options in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "Running" value in "status" column should contains "Jobs_And_Workflows"."Workflows_Running_Action_Menu_Options" + Then check that "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard is enabled + And wait load page + When click on cell with row index 1 in "name" column in "Workflows_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then click on "Toggle_View_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + And wait load page + Then verify "Workflow_List_View_Table" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard When click on cell with row index 1 in "name" column in "Workflow_List_View_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard And wait load page Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard @@ -806,9 +933,17 @@ Feature: Jobs Monitoring Page And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Terminate_Message" + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled + Then click on "Cross_Close_Button" element on "Jobs_Monitor_Tab_Info_Pane" wizard + And wait load page + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled + Then click on "Arrow_Back" element on "Workflows_Monitor_Tab_Info_Pane" wizard + And wait load page + Then verify that in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "main 2021-08-30 05-36-35" value in "name" column "Terminate" option is disabled + And wait load page @MLJM @smoke @@ -817,7 +952,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Workflows_Tab" wizard And wait load page @@ -862,7 +997,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" When select "Error" option in "Status_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard @@ -893,6 +1028,13 @@ Feature: Jobs Monitoring Page And wait load page Then verify "Workflows_Table" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "4 items selected" + When select "Terminating" option in "Status_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Workflows_Table" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard Then select "View YAML" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table at row with "kfpipeline 2021-07-06 11-16-28" value in "name" column @@ -906,19 +1048,8 @@ Feature: Jobs Monitoring Page And wait load page Then verify if "Notification_Popup" popup dialog appears Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Run_Message" - Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard - Then verify "Retry_Button" element visibility on "Notification_Popup" wizard - Then "Retry_Button" element on "Notification_Popup" should contains "RETRY" value - Then click on "Retry_Button" element on "Notification_Popup" wizard - And wait load page - Then verify if "Notification_Popup" popup dialog appears - Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Unsuccessful_Run_Message" - Then verify "Retry_Button" element visibility on "Notification_Popup" wizard - Then "Retry_Button" element on "Notification_Popup" should contains "RETRY" value + Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Successful_Run_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard - Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard @MLJM @smoke @@ -929,12 +1060,10 @@ Feature: Jobs Monitoring Page Then verify "Monitoring_Scheduled_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Scheduled_Box_Title" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard Then "Monitoring_Scheduled_Box_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Scheduled" value - Then verify "Total_Scheduled_Title" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard - Then "Total_Scheduled_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Total" value Then verify "Total_Scheduled_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard When click on "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then verify "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Scheduled_Tab" wizard should contains "Jobs_Monitoring"."Tab_List" @@ -968,7 +1097,8 @@ Feature: Jobs Monitoring Page Then verify "Total_Job_Counter_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard When click on "Total_Job_Counter_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=job" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=job&dates=next24hours" + And wait load page Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then verify "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Scheduled_Tab" wizard should contains "Jobs_Monitoring"."Tab_List" @@ -1001,7 +1131,8 @@ Feature: Jobs Monitoring Page Then "Total_Workflows_Counter_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Workflows" value Then verify "Total_Workflows_Counter_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard When click on "Total_Workflows_Counter_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=workflow" + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=workflow&dates=next24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then verify "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Scheduled_Tab" wizard should contains "Jobs_Monitoring"."Tab_List" @@ -1027,14 +1158,12 @@ Feature: Jobs Monitoring Page Then click on breadcrumbs "projectsPage" label on "commonPagesHeader" wizard And wait load page Then verify redirection to "projects" - Then verify "Total_Scheduled_Title" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard - Then "Total_Scheduled_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Total" value Then verify "Total_Job_Counter_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard Then verify "Total_Workflows_Counter_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard Then verify "Total_Scheduled_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard When click on "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" @@ -1051,7 +1180,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then verify that 8 row elements are displayed in "Scheduled_Table" on "Jobs_Monitoring_Scheduled_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard @@ -1119,7 +1248,7 @@ Feature: Jobs Monitoring Page And wait load page When click on "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" When select "Job" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard @@ -1150,13 +1279,14 @@ Feature: Jobs Monitoring Page @MLJM @smoke + # TODO: Total wf counter = 4, 3 row elements are displayed - known bug (due to running not in 24h period), couln't be fixed yet Scenario: MLJM012 - Check jobs/workflows/scheduled count consistency among counter data and Jobs monitoring Tabs Given open url And wait load page Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then verify "Jobs" tab is active in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Jobs_Tab" wizard Then verify "Jobs_Table" element visibility on "Jobs_Monitoring_Jobs_Tab" wizard Then "Pagination_Count" element on "Pagination_Info_Pane" should contains "Showing 1 - 50" value @@ -1186,19 +1316,19 @@ Feature: Jobs Monitoring Page Then click on breadcrumbs "projectsPage" label on "commonPagesHeader" wizard And wait load page Then verify "Total_Counter_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "3" value + Then "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "4" value When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" Then verify "Workflows_Table" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard Then verify that 3 row elements are displayed in "Workflows_Table" on "Jobs_Monitoring_Workflows_Tab" wizard Then navigate back And wait load page - Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then "Counter_Running_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "0" value - When click on "Counter_Running_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard + Then verify "Counter_In_Process_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard + Then "Counter_In_Process_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "1" value + When click on "Counter_In_Process_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify that 0 row elements are displayed in "Workflows_Table" on "Jobs_Monitoring_Workflows_Tab" wizard + Then verify that 1 row elements are displayed in "Workflows_Table" on "Jobs_Monitoring_Workflows_Tab" wizard Then click on breadcrumbs "projectsPage" label on "commonPagesHeader" wizard And wait load page Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard @@ -1221,7 +1351,7 @@ Feature: Jobs Monitoring Page Then "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" should contains "8" value When click on "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" Then verify that 8 row elements are displayed in "Scheduled_Table" on "Jobs_Monitoring_Scheduled_Tab" wizard Then navigate back And wait load page @@ -1250,7 +1380,7 @@ Feature: Jobs Monitoring Page Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then verify "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "Jobs_Monitoring"."Tab_List" @@ -1315,3 +1445,86 @@ Feature: Jobs Monitoring Page Then "Pagination_Count" element on "Pagination_Info_Pane" should contains "Showing 1 - 50" value Then verify "BE_Pagination_Navigate_Next" element on "Pagination_Info_Pane" wizard is disabled Then verify "BE_Pagination_Navigate_Next" element on "Pagination_Info_Pane" wizard should display hover tooltip "Common_Tooltips"."Auto_Refresh" + + @MLJM + @smoke + Scenario: MLJM017 - Check filtering of different projects within identical job function runs + Given open url + And wait load page + Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" + Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value + Then verify breadcrumbs "projectsPage" label should be equal "Projects" value + Then verify "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "Jobs_Monitoring"."Tab_List" + Then verify "Jobs" tab is active in "Cross_Jobs_Tab_Selector" on "Jobs_Monitoring_Jobs_Tab" wizard + Then verify "Jobs_Table" element visibility on "Jobs_Monitoring_Jobs_Tab" wizard + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Jobs_Tab" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Jobs_Tab" wizard selected option value "Any time" + Then verify "Search_By_Name_Filter_Input" element visibility on "Jobs_Monitoring_Jobs_Tab" wizard + Then type value "fesf" to "Search_By_Name_Filter_Input" field on "Jobs_Monitoring_Jobs_Tab" wizard + Then click on "Refresh_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard + And wait load page + Then value in "name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "fesf" + Then verify that 2 row elements are displayed in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard + When click on cell with row index 1 in "name" column in "Jobs_Table" table on "Jobs_Monitoring_Jobs_Tab" wizard + And wait load page + Then verify that 3 row elements are displayed in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard + Then value in "project_name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "cat-vs-dog-classification" + Then click on "Arrow_Back" element on "Jobs_Monitor_Tab" wizard + And wait load page + When click on cell with row index 2 in "name" column in "Jobs_Table" table on "Jobs_Monitoring_Jobs_Tab" wizard + And wait load page + Then verify that 1 row elements are displayed in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard + Then value in "project_name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "fsdemo-admin" + Then click on breadcrumbs "projectsPage" label on "commonPagesHeader" wizard + And wait load page + When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" + Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Jobs_Tab" wizard + And wait load page + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Jobs_Tab" wizard selected option value "Any time" + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard + Then "Title" element on "FilterBy_Popup" should contains "Filter by" value + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "cat-vs-dog-classification" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + And wait load page + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then value in "project_name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "cat-vs-dog-classification" + When click on cell with value "fesf" in "name" column in "Jobs_Table" table on "Jobs_Monitoring_Jobs_Tab" wizard + And wait load page + Then verify that 3 row elements are displayed in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard + Then value in "project_name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "cat-vs-dog-classification" + Then click on "Arrow_Back" element on "Jobs_Monitor_Tab" wizard + And wait load page + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard + Then click on "Clear_Button" element on "FilterBy_Popup" wizard + And wait load page + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard + Then "Title" element on "FilterBy_Popup" should contains "Filter by" value + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "fsdemo-admin" option in "Project_Name_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + And wait load page + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then value in "project_name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "fsdemo-admin" + When click on cell with value "fesf" in "name" column in "Jobs_Table" table on "Jobs_Monitoring_Jobs_Tab" wizard + And wait load page + Then verify that 1 row elements are displayed in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard + Then value in "project_name" column with "text" in "Jobs_Table" on "Jobs_Monitoring_Jobs_Tab" wizard should contains "fsdemo-admin" + Then click on "Arrow_Back" element on "Jobs_Monitor_Tab" wizard + And wait load page + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard + Then click on "Clear_Button" element on "FilterBy_Popup" wizard + And wait load page + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Jobs_Tab" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + \ No newline at end of file diff --git a/tests/features/models.feature b/tests/features/models.feature index f1594e4d89..b431dc3374 100644 --- a/tests/features/models.feature +++ b/tests/features/models.feature @@ -1090,6 +1090,7 @@ Feature: Models Page And wait load page And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard Then "No_Data_Message" element on "commonPagesHeader" should contains "The ingestion function has no steps and therefore no graph." value + And wait load page @MLM @smoke @@ -1459,7 +1460,7 @@ Feature: Models Page And wait load page And select "Model Endpoints" tab in "Models_Tab_Selector" on "Models" wizard And wait load page - When click on cell with row index 1 in "name" column in "Model_Endpoints_Table" table on "Model_Endpoints" wizard + When click on cell with row index 3 in "name" column in "Model_Endpoints_Table" table on "Model_Endpoints" wizard And wait load page Then verify "Info_Pane_Tab_Selector" element visibility on "Model_Endpoints_Info_Pane" wizard Then verify "Info_Pane_Tab_Selector" on "Model_Endpoints_Info_Pane" wizard should contains "Models_Endpoints_Info_Pane"."Tab_List" @@ -1516,7 +1517,7 @@ Feature: Models Page And wait load page And select "Model Endpoints" tab in "Models_Tab_Selector" on "Models" wizard And wait load page - When click on cell with row index 1 in "name" column in "Model_Endpoints_Table" table on "Model_Endpoints" wizard + When click on cell with row index 3 in "name" column in "Model_Endpoints_Table" table on "Model_Endpoints" wizard Then select "Metrics" tab in "Info_Pane_Tab_Selector" on "Model_Endpoints_Info_Pane" wizard Then click on "Choose_Metrics_Dropdown" element on "Model_Endpoints_Info_Pane" wizard And wait load page @@ -1541,6 +1542,7 @@ Feature: Models Page @MLM @smoke + # !!! restart mock is required Scenario: MLM037 - Verify the Delete option in Models table, details panel, full view action menu Given open url And wait load page diff --git a/tests/features/monitoringApp.feature b/tests/features/monitoringApp.feature index 074bc854d8..e7be622978 100644 --- a/tests/features/monitoringApp.feature +++ b/tests/features/monitoringApp.feature @@ -100,12 +100,12 @@ Feature: Monitoring app Page Then verify breadcrumbs "tab" label should be equal "Monitoring app" value And wait load page Then verify "Model_Endpoint_Detections_Title" element visibility on "Monitoring_App" wizard - Then "Model_Endpoint_Detections_Title" element on "Monitoring_App" should contains "Model Endpoint with detections" value + Then "Model_Endpoint_Detections_Title" element on "Monitoring_App" should contains "Model Endpoints with suspected/detected issue" value Then verify "Model_Endpoint_Detections_Tip" element visibility on "Monitoring_App" wizard Then verify "Model_Endpoint_Detections_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Model_Endpoint_With_Detections" Then verify "Model_Endpoint_Detections_Chart" element visibility on "Monitoring_App" wizard Then verify "Operating_Functions_Title" element visibility on "Monitoring_App" wizard - Then "Operating_Functions_Title" element on "Monitoring_App" should contains "Operating functions" value + Then "Operating_Functions_Title" element on "Monitoring_App" should contains "System functions" value Then verify "Operating_Functions_Tip" element visibility on "Monitoring_App" wizard Then verify "Operating_Functions_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Operating_Functions" Then verify "Operating_Functions_Table" element visibility on "Monitoring_App" wizard @@ -134,15 +134,15 @@ Feature: Monitoring app Page Then verify "All_Applications_Lag_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Lag" Then verify "All_Applications_Commited_Offset_Tip" element visibility on "Monitoring_App" wizard Then verify "All_Applications_Commited_Offset_Tip" element on "Monitoring_App" wizard should display hover hint "Label_Hint"."Commited_Offset" - Then verify "open_metrics" option is present on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column - Then verify "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column should display hover tooltip "Common_Tooltips"."Open_Metrics" with scroll "false" - Then click on "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column with scroll "false" + Then verify "open_metrics" option is present on "Monitoring_App" wizard in "All_Applications_Table" table with "monitorAppV1" value in "name" column + Then verify "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "monitorAppV1" value in "name" column should display hover tooltip "Common_Tooltips"."Open_Metrics" with scroll "false" + Then click on "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "monitorAppV1" value in "name" column with scroll "false" And wait load page Then verify "Application_Monitoring_Button" element visibility on "Application_Metrics" wizard Then "Application_Monitoring_Button" element on "Application_Metrics" should contains "Application monitoring" value Then navigate back And wait load page - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Application_Metrics_Button" element visibility on "Application_Monitoring" wizard Then "Application_Metrics_Button" element on "Application_Monitoring" should contains "Application metrics" value @@ -164,7 +164,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV2" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Back_Button" element visibility on "Application_Monitoring" wizard Then verify "Back_Button" element on "Application_Monitoring" wizard should display hover tooltip "Common_Tooltips"."Back_Button" @@ -172,7 +172,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv2" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV2" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Application_Name" element visibility on "Application_Monitoring" wizard Then "Application_Name" element on "Application_Monitoring" should contains "monitorAppV2" value @@ -226,7 +226,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Back_Button" element visibility on "Application_Monitoring" wizard Then verify "App_Status_Title" element visibility on "Application_Monitoring" wizard @@ -272,7 +272,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Artifacts_Title" element visibility on "Application_Monitoring" wizard Then "Artifacts_Title" element on "Application_Monitoring" should contains "Artifacts" value @@ -282,7 +282,9 @@ Feature: Monitoring app Page And wait load page Then verify breadcrumbs "tab" label should be equal "Artifacts" value And wait load page - Then "Table_Name_Filter_Input" element on "Files" should contains "monitorAppV1" attribute value + Then click on "Table_FilterBy_Button" element on "Files" wizard + And wait load page + Then "Table_Label_Filter_Input" element on "FilterBy_Popup" should contains "mlrun/app-name=monitorAppV1" attribute value And wait load page @MLMA @@ -302,7 +304,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Results_Title" element visibility on "Application_Monitoring" wizard Then "Results_Title" element on "Application_Monitoring" should contains "Results" value @@ -325,7 +327,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Metrics_Title" element visibility on "Application_Monitoring" wizard Then "Metrics_Title" element on "Application_Monitoring" should contains "Metrics" value @@ -350,7 +352,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page When scroll to the "Shards_Partitions_Status_Title" element on "Application_Monitoring" wizard Then verify "Shards_Partitions_Status_Title" element visibility on "Application_Monitoring" wizard @@ -380,7 +382,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Application_Metrics_Button" element visibility on "Application_Monitoring" wizard Then "Application_Metrics_Button" element on "Application_Monitoring" should contains "Application metrics" value @@ -395,8 +397,8 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then verify "open_metrics" option is present on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column - Then click on "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "Monitorappv1" value in "name" column with scroll "false" + Then verify "open_metrics" option is present on "Monitoring_App" wizard in "All_Applications_Table" table with "monitorAppV1" value in "name" column + Then click on "open_metrics" option on "Monitoring_App" wizard in "All_Applications_Table" table with "monitorAppV1" value in "name" column with scroll "false" And wait load page Then verify "Applications_Metrics_Title" element visibility on "Application_Metrics" wizard Then "Applications_Metrics_Title" element on "Application_Metrics" should contains "Applications metrics:" value @@ -431,7 +433,7 @@ Feature: Monitoring app Page And wait load page Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value - Then click on cell with value "Monitorappv1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard + Then click on cell with value "monitorAppV1" in "name" column in "All_Applications_Table" table on "Monitoring_App" wizard And wait load page Then verify "Application_Metrics_Button" element visibility on "Application_Monitoring" wizard Then "Application_Metrics_Button" element on "Application_Monitoring" should contains "Application metrics" value @@ -441,14 +443,14 @@ Feature: Monitoring app Page Then "Applications_Metrics_Title" element on "Application_Metrics" should contains "Applications metrics:" value Then verify "Endpoints_List_Section" element visibility on "Application_Metrics" wizard Then verify "Search_Endpoints_Counter" element visibility on "Application_Metrics" wizard - Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "2 endpoints found" value + Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "4 endpoints found" value Then verify "Endpoints_List_Table" element visibility on "Application_Metrics" wizard Then verify "Search_By_Endpoint_Filter_Input" element visibility on "Application_Metrics" wizard Then type value "boo" to "Search_By_Endpoint_Filter_Input" field on "Application_Metrics" wizard And wait load page Then value in "name" column with "text" in "Endpoints_List_Table" on "Application_Metrics" wizard should contains "GradientBoostingClassifier" - Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "1 endpoint found" value - Then type value "for" to "Search_By_Endpoint_Filter_Input" field on "Application_Metrics" wizard + Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "2 endpoints found" value + Then type value "RandomForestClassifier2" to "Search_By_Endpoint_Filter_Input" field on "Application_Metrics" wizard And wait load page Then value in "name" column with "text" in "Endpoints_List_Table" on "Application_Metrics" wizard should contains "RandomForestClassifier" Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "1 endpoint found" value diff --git a/tests/features/projectMonitoring.feature b/tests/features/projectMonitoring.feature index ed783387ca..63bbf4da9d 100644 --- a/tests/features/projectMonitoring.feature +++ b/tests/features/projectMonitoring.feature @@ -15,11 +15,11 @@ Feature: Project Monitoring Page Then verify "Project_Name" element visibility on "Project" wizard Then "Project_Name" element on "Project" should contains "default" value Then verify "Created_Details" element visibility on "Project" wizard - Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 15:21:14 PM" value + Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 17:21:14 PM" value Then verify "Owner_Details" element visibility on "Project" wizard Then "Owner_Details" element on "Project" should contains "Owner: igz_nobody" value - Then verify "Info_Baner" element visibility on "Project" wizard - Then "Info_Baner" element on "Project" should contains "Counters use a caching mechanism, and are not auto-refreshed." value + Then verify "Info_Baner_Icon" element visibility on "Project" wizard + Then verify "Info_Baner_Icon" element on "Project" wizard should display hover hint "Label_Hint"."Project_Monitoring_Counters" Then verify "Quick_Actions" element visibility on "Project" wizard Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options" Then verify "Refresh_Button" element visibility on "Project" wizard @@ -35,18 +35,18 @@ Feature: Project Monitoring Page Then "Documents_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "Documents" value Then verify "Documents_Counter_Number" element visibility in "Artifacts_Stats_Container" on "Project" wizard Then verify "LLM_Prompts_Counter_Subtitle" element visibility in "Artifacts_Stats_Container" on "Project" wizard - Then "LLM_Prompts_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "LLM Prompts" value + Then "LLM_Prompts_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "LLM prompt artifacts" value Then verify "LLM_Prompts_Counter_Number" element visibility in "Artifacts_Stats_Container" on "Project" wizard Then verify "Other_Artifacts_Counter_Subtitle" element visibility in "Artifacts_Stats_Container" on "Project" wizard - Then "Other_Artifacts_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "Other Artifacts" value + Then "Other_Artifacts_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "Other artifacts" value Then verify "Other_Artifacts_Counter_Number" element visibility in "Artifacts_Stats_Container" on "Project" wizard Then verify "Workflows_Stats_Title" element visibility in "Workflows_Stats_Container" on "Project" wizard Then "Workflows_Stats_Title" element in "Workflows_Stats_Container" on "Project" should contains "Workflows" value Then verify "Filtering_Time_Period" element visibility in "Workflows_Stats_Container" on "Project" wizard - Then "Filtering_Time_Period" element in "Workflows_Stats_Container" on "Project" should contains "24 hrs" value + Then "Filtering_Time_Period" element in "Workflows_Stats_Container" on "Project" should contains "Last 24 hrs" value Then verify "Workflows_Stats_Counter" element visibility in "Workflows_Stats_Container" on "Project" wizard Then verify "In_Process_Counter_Subtitle" element visibility in "Workflows_Stats_Container" on "Project" wizard - Then "In_Process_Counter_Subtitle" element in "Workflows_Stats_Container" on "Project" should contains "In Process" value + Then "In_Process_Counter_Subtitle" element in "Workflows_Stats_Container" on "Project" should contains "In process" value Then verify "In_Process_Counter_Status_Icon" element visibility in "Workflows_Stats_Container" on "Project" wizard Then verify "In_Process_Counter_Status_Icon" element in "Workflows_Stats_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" Then verify "In_Process_Counter_Number" element visibility in "Workflows_Stats_Container" on "Project" wizard @@ -64,7 +64,7 @@ Feature: Project Monitoring Page Then verify "Scheduled_Stats_Title" element visibility in "Scheduled_Stats_Container" on "Project" wizard Then "Scheduled_Stats_Title" element in "Scheduled_Stats_Container" on "Project" should contains "Scheduled" value Then verify "Filtering_Time_Period" element visibility in "Scheduled_Stats_Container" on "Project" wizard - Then "Filtering_Time_Period" element in "Scheduled_Stats_Container" on "Project" should contains "24 hrs" value + Then "Filtering_Time_Period" element in "Scheduled_Stats_Container" on "Project" should contains "Next 24 hrs" value Then verify "Scheduled_Stats_Counter" element visibility in "Scheduled_Stats_Container" on "Project" wizard Then verify "Jobs_Counter_Subtitle" element visibility in "Scheduled_Stats_Container" on "Project" wizard Then "Jobs_Counter_Subtitle" element in "Scheduled_Stats_Container" on "Project" should contains "Jobs" value @@ -76,11 +76,11 @@ Feature: Project Monitoring Page Then "Models_Stats_Title" element in "Models_Stats_Container" on "Project" should contains "Models" value Then verify "Model_Stats_Counter" element visibility in "Models_Stats_Container" on "Project" wizard Then verify "Monitoring_App_Stats_Title" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard - Then "Monitoring_App_Stats_Title" element in "Monitoring_App_Stats_Container" on "Project" should contains "Monitoring App" value - Then verify "Monitoring_App_Succeeded_Stats_Counter" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard - Then verify "Monitoring_App_Succeeded_Counter_Subtitle" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard - Then "Monitoring_App_Succeeded_Counter_Subtitle" element in "Monitoring_App_Stats_Container" on "Project" should contains "Succeeded" value - Then verify "Monitoring_App_Succeeded_Counter_Status_Icon" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then "Monitoring_App_Stats_Title" element in "Monitoring_App_Stats_Container" on "Project" should contains "Monitoring apps" value + Then verify "Monitoring_App_Running_Stats_Counter" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then verify "Monitoring_App_Running_Counter_Subtitle" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard + Then "Monitoring_App_Running_Counter_Subtitle" element in "Monitoring_App_Stats_Container" on "Project" should contains "Running" value + Then verify "Monitoring_App_Running_Counter_Status_Icon" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard Then verify "Monitoring_App_Failed_Stats_Counter" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard Then verify "Monitoring_App_Failed_Counter_Subtitle" element visibility in "Monitoring_App_Stats_Container" on "Project" wizard Then "Monitoring_App_Failed_Counter_Subtitle" element in "Monitoring_App_Stats_Container" on "Project" should contains "Failed" value @@ -89,7 +89,7 @@ Feature: Project Monitoring Page Then "Alerts_Stats_Title" element in "Alerts_Stats_Container" on "Project" should contains "Alerts" value Then verify "Alerts_Stats_Title_Icon" element visibility in "Alerts_Stats_Container" on "Project" wizard Then verify "Filtering_Time_Period" element visibility in "Alerts_Stats_Container" on "Project" wizard - Then "Filtering_Time_Period" element in "Alerts_Stats_Container" on "Project" should contains "24 hrs" value + Then "Filtering_Time_Period" element in "Alerts_Stats_Container" on "Project" should contains "Last 24 hrs" value Then verify "Alerts_Stats_Counter" element visibility in "Alerts_Stats_Container" on "Project" wizard Then verify "Alerts_Stats_Endpoint_Subtitle" element visibility in "Alerts_Stats_Container" on "Project" wizard Then "Alerts_Stats_Endpoint_Subtitle" element in "Alerts_Stats_Container" on "Project" should contains "Endpoint" value @@ -114,11 +114,11 @@ Feature: Project Monitoring Page Then verify "Project_Name" element visibility on "Project" wizard Then "Project_Name" element on "Project" should contains "default" value Then verify "Created_Details" element visibility on "Project" wizard - Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 15:21:14 PM" value + Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 17:21:14 PM" value Then verify "Owner_Details" element visibility on "Project" wizard Then "Owner_Details" element on "Project" should contains "Owner: igz_nobody" value - Then verify "Info_Baner" element visibility on "Project" wizard - Then "Info_Baner" element on "Project" should contains "Counters use a caching mechanism, and are not auto-refreshed." value + Then verify "Info_Baner_Icon" element visibility on "Project" wizard + Then verify "Info_Baner_Icon" element on "Project" wizard should display hover hint "Label_Hint"."Project_Monitoring_Counters" Then verify "Quick_Actions" element visibility on "Project" wizard Then verify "Quick_Actions" dropdown element on "Project" wizard should contains "Project"."Quick_Actions_Options" Then verify "Refresh_Button" element visibility on "Project" wizard @@ -132,7 +132,7 @@ Feature: Project Monitoring Page Then check "Last 24 hrs" header value in "time_period" column in "Runs_Statistic_Table" table on "Project" wizard Then verify visibility of header column "in_process_counter_number" in "Runs_Statistic_Table" table on "Project" wizard Then verify visibility of header column "in_process_counter_subtitle" in "Runs_Statistic_Table" table on "Project" wizard - Then check "In Progress" header value in "in_process_counter_subtitle" column in "Runs_Statistic_Table" table on "Project" wizard + Then check "In Process" header value in "in_process_counter_subtitle" column in "Runs_Statistic_Table" table on "Project" wizard Then verify visibility of header column "in_process_counter_icon" in "Runs_Statistic_Table" table on "Project" wizard Then verify "In_Process_Counter_Subtitle" element in "Runs_Statistic_Section_Container" on "Project" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" Then verify visibility of header column "failed_counter_number" in "Runs_Statistic_Table" table on "Project" wizard @@ -941,7 +941,7 @@ Feature: Project Monitoring Page Then verify "Schedule" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "Table_Name_Filter_Input" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard - Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Any time" + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Next 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" @@ -956,7 +956,7 @@ Feature: Project Monitoring Page Then verify "Schedule" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "Table_Name_Filter_Input" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard - Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Any time" + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Next 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Job" @@ -971,7 +971,7 @@ Feature: Project Monitoring Page Then verify "Schedule" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "Table_Name_Filter_Input" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard - Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Any time" + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Next 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" @@ -994,7 +994,7 @@ Feature: Project Monitoring Page Then verify "Monitor Workflows" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "Table_Name_Filter_Input" element visibility on "Workflows_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Workflows_Monitor_Tab" wizard - Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past week" + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Workflows_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Workflows_Monitor_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" @@ -1022,7 +1022,7 @@ Feature: Project Monitoring Page Then verify "Monitor Workflows" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "Table_Name_Filter_Input" element visibility on "Workflows_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Workflows_Monitor_Tab" wizard - Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past week" + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Workflows_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Workflows_Monitor_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Error, Failed" @@ -1036,7 +1036,7 @@ Feature: Project Monitoring Page Then verify "Monitor Workflows" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard Then verify "Table_Name_Filter_Input" element visibility on "Workflows_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Workflows_Monitor_Tab" wizard - Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past week" + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Past 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Workflows_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Workflows_Monitor_Tab" wizard Then verify "Status_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Completed" @@ -1053,7 +1053,7 @@ Feature: Project Monitoring Page And wait load page And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page - When click on "Monitoring_App_Succeeded_Stats_Counter" element in "Monitoring_App_Stats_Container" on "Project" wizard + When click on "Monitoring_App_Running_Stats_Counter" element in "Monitoring_App_Stats_Container" on "Project" wizard And wait load page Then verify breadcrumbs "tab" label should be equal "Monitoring app" value Then verify redirection to "projects/default/monitoring-app" @@ -1196,11 +1196,11 @@ Feature: Project Monitoring Page And wait load page Then verify "Search_Input" element visibility on "Consumer_Groups" wizard Then verify "Consumer_Groups_Table" element visibility on "Consumer_Groups" wizard - Then type value "C" to "Search_Input" field on "Consumer_Groups" wizard + Then type value "c" to "Search_Input" field on "Consumer_Groups" wizard Then value in "consumer_group_name" column with "text" in "Consumer_Groups_Table" on "Consumer_Groups" wizard should contains "C" - Then type value "CONSUMER" to "Search_Input" field on "Consumer_Groups" wizard + Then type value "consumer" to "Search_Input" field on "Consumer_Groups" wizard Then value in "consumer_group_name" column with "text" in "Consumer_Groups_Table" on "Consumer_Groups" wizard should contains "Consumer" - Then type value "randomText" to "Search_Input" field on "Consumer_Groups" wizard + Then type value "randomtext" to "Search_Input" field on "Consumer_Groups" wizard Then check "ConsumerGroup1" value not in "consumer_group_name" column in "Consumer_Groups_Table" table on "Consumer_Groups" wizard @MLPM @@ -1248,12 +1248,12 @@ Feature: Project Monitoring Page And wait load page Then verify "Search_Input" element visibility on "Consumer_Groups" wizard Then verify "Shard_Lags_Table" element visibility on "Consumer_Groups" wizard - Then type value "SHARD" to "Search_Input" field on "Consumer_Groups" wizard + Then type value "shard" to "Search_Input" field on "Consumer_Groups" wizard Then click on "Refresh_Button" element on "Consumer_Groups" wizard Then value in "shard_name" column with "text" in "Shard_Lags_Table" on "Consumer_Groups" wizard should contains "shard" Then type value "shard-id-0" to "Search_Input" field on "Consumer_Groups" wizard Then value in "shard_name" column with "text" in "Shard_Lags_Table" on "Consumer_Groups" wizard should contains "shard-id-0" - Then type value "randomText" to "Search_Input" field on "Consumer_Groups" wizard + Then type value "randomtext" to "Search_Input" field on "Consumer_Groups" wizard Then check "shard-id-0" value not in "shard_name" column in "Shard_Lags_Table" table on "Consumer_Groups" wizard @MLPM diff --git a/tests/features/projectsPage.feature b/tests/features/projectsPage.feature index 05fbea66f3..c91c72e097 100644 --- a/tests/features/projectsPage.feature +++ b/tests/features/projectsPage.feature @@ -167,6 +167,7 @@ Feature: Projects Page @MLPr @sanity @smoke + #TODO: update "Labels_Value" options rules Scenario: MLPr007 - Create new ML Project with description Given open url And wait load page @@ -186,7 +187,7 @@ Feature: Projects Page Then type into "Description_Input" on "Create_New_Project" popup dialog "automation test description new" value Then type value "/" to "Labels_Value" field on "Create_New_Project" wizard Then verify labels warning should display options "Input_Hint"."Projects_Labels_Warning_Value" - Then verify "Labels_Value" options rules on "Create_New_Project" wizard with labels + # Then verify "Labels_Value" options rules on "Create_New_Project" wizard with labels And wait load page Then type value "/" to "Labels_Key" field on "Create_New_Project" wizard Then type value "/" to "Labels_Value" field on "Create_New_Project" wizard @@ -320,11 +321,6 @@ Feature: Projects Page And click on row root with value "navigation-test" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard - And click on cell with value "Quick actions" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard - And hover "MLRun_Logo" component on "commonPagesHeader" wizard - And wait load page - Then verify value should equal "navigation-test" in "Header_Name_Label" on "Demo_Project" wizard - And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard Then click on "Pin_Quick_Link_Button" element on "commonPagesHeader" wizard And click on cell with value "Project monitoring" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And wait load page @@ -402,13 +398,13 @@ Feature: Projects Page Then verify "Monitoring_Jobs_Box_Title_Tip" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Monitoring_Jobs_Box_Title_Tip" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover hint "Common_Tooltips"."Monitoring_Jobs_Box_Title_Tip" Then verify "Filtering_Time_Period" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then "Filtering_Time_Period" element in "Monitoring_Jobs_Box" on "Projects" should contains "Past 24 hrs" value + Then "Filtering_Time_Period" element in "Monitoring_Jobs_Box" on "Projects" should contains "Last 24 hrs" value Then verify "Total_Counter_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Running_Status_Subtitle" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then "Counter_Running_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "Running" value - Then verify "Counter_Running_Status_Icon" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then verify "Counter_Running_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" + Then "Counter_Running_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "In process" value + Then verify "Counter_In_Process_Status_Icon" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard + Then verify "Counter_In_Process_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Failed_Status_Subtitle" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then "Counter_Failed_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "Failed" value @@ -418,7 +414,7 @@ Feature: Projects Page Then verify "Counter_Completed_Status_Subtitle" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then "Counter_Completed_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "Succeeded" value Then verify "Counter_Completed_Status_Icon" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then verify "Counter_Running_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" + Then verify "Counter_In_Process_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" Then verify "Counter_Completed_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."Succeeded" Then "Counter_Completed_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" should contains "1" value When click on "Counter_Running_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard @@ -428,21 +424,21 @@ Feature: Projects Page And wait load page When click on "Counter_Failed_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=error%2Caborted&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=error%2Caborted&dates=past24hours&bePage=1&fePage=1" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then navigate back And wait load page When click on "Counter_Completed_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=completed&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=completed&dates=past24hours&bePage=1&fePage=1" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then navigate back And wait load page When click on "Total_Counter_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&bePage=1&fePage=1" + Then verify redirection to "projects/*/jobs-monitoring/jobs?state=all&dates=past24hours&bePage=1&fePage=1" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then navigate back @@ -461,13 +457,13 @@ Feature: Projects Page Then verify "Monitoring_Workflows_Box_Title" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Monitoring_Workflows_Box_Title" element in "Monitoring_Workflows_Box" on "Projects" should contains "Workflows" value Then verify "Filtering_Time_Period" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then "Filtering_Time_Period" element in "Monitoring_Workflows_Box" on "Projects" should contains "Past 24 hours" value + Then "Filtering_Time_Period" element in "Monitoring_Workflows_Box" on "Projects" should contains "Last 24 hrs" value Then verify "Total_Counter_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then verify "Counter_Running_Status_Subtitle" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then "Counter_Running_Status_Subtitle" element in "Monitoring_Workflows_Box" on "Projects" should contains "In Process" value - Then verify "Counter_Running_Status_Icon" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then verify "Counter_Running_Status_Icon" element in "Monitoring_Workflows_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" + Then verify "Counter_In_Process_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard + Then verify "Counter_In_Process_Status_Subtitle" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard + Then "Counter_In_Process_Status_Subtitle" element in "Monitoring_Workflows_Box" on "Projects" should contains "In process" value + Then verify "Counter_In_Process_Status_Icon" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard + Then verify "Counter_In_Process_Status_Icon" element in "Monitoring_Workflows_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then verify "Counter_Failed_Status_Subtitle" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Counter_Failed_Status_Subtitle" element in "Monitoring_Workflows_Box" on "Projects" should contains "Failed" value @@ -477,30 +473,31 @@ Feature: Projects Page Then verify "Counter_Completed_Status_Subtitle" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Counter_Completed_Status_Subtitle" element in "Monitoring_Workflows_Box" on "Projects" should contains "Succeeded" value Then verify "Counter_Completed_Status_Icon" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard + Then verify "Counter_In_Process_Status_Icon" element in "Monitoring_Workflows_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" Then verify "Counter_Completed_Status_Icon" element in "Monitoring_Workflows_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."Succeeded" - When click on "Counter_Running_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard + When click on "Counter_In_Process_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=running&dates=anyTime" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=running%2Cterminating&dates=anyTime" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then navigate back And wait load page When click on "Counter_Failed_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=error%2Cfailed" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=error%2Cfailed&dates=past24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then navigate back And wait load page When click on "Counter_Completed_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=completed" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=completed&dates=past24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then navigate back And wait load page When click on "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" wizard - Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all" + Then verify redirection to "projects/*/jobs-monitoring/workflows?state=all&dates=past24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value Then navigate back @@ -519,33 +516,31 @@ Feature: Projects Page Then verify "Monitoring_Scheduled_Box_Title" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard Then "Monitoring_Scheduled_Box_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Scheduled" value Then verify "Filtering_Time_Period" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard - Then "Filtering_Time_Period" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Next 24 hours" value + Then "Filtering_Time_Period" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Next 24 hrs" value Then verify "Total_Job_Counter_Title" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard Then "Total_Job_Counter_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Jobs" value Then verify "Total_Workflows_Counter_Title" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard Then "Total_Workflows_Counter_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Workflows" value Then verify "Total_Job_Counter_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard Then verify "Total_Workflows_Counter_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard - Then verify "Total_Scheduled_Title" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard - Then "Total_Scheduled_Title" element in "Monitoring_Scheduled_Box" on "Projects" should contains "Total" value Then verify "Total_Scheduled_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard When click on "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value And wait load page Then navigate back And wait load page When click on "Total_Workflows_Counter_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=workflow" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=workflow&dates=next24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value And wait load page Then navigate back And wait load page When click on "Total_Job_Counter_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=job" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=job&dates=next24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value And wait load page @@ -566,7 +561,7 @@ Feature: Projects Page Then "Monitoring_Alerts_Box_Title" element in "Monitoring_Alerts_Box" on "Projects" should contains "Alerts" value Then verify "Monitoring_Alerts_Box_Title_Icon" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard Then verify "Filtering_Time_Period" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard - Then "Filtering_Time_Period" element in "Monitoring_Alerts_Box" on "Projects" should contains "Past 24 hours" value + Then "Filtering_Time_Period" element in "Monitoring_Alerts_Box" on "Projects" should contains "Last 24 hrs" value Then verify "Total_Endpoint_Counter_Title" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard Then "Total_Endpoint_Counter_Title" element in "Monitoring_Alerts_Box" on "Projects" should contains "Endpoint" value Then verify "Total_Endpoint_Counter_Number" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard @@ -576,8 +571,6 @@ Feature: Projects Page Then verify "Total_Application_Counter_Title" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard Then "Total_Application_Counter_Title" element in "Monitoring_Alerts_Box" on "Projects" should contains "Application" value Then verify "Total_Application_Counter_Number" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard - Then verify "Total_Alerts_Title" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard - Then "Total_Alerts_Title" element in "Monitoring_Alerts_Box" on "Projects" should contains "Total" value Then verify "Total_Alerts_Number" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard Then "Total_Alerts_Number" element in "Monitoring_Alerts_Box" on "Projects" should contains "39" value When click on "Total_Alerts_Number" element in "Monitoring_Alerts_Box" on "Projects" wizard @@ -620,7 +613,7 @@ Feature: Projects Page Then verify "Monitoring_Container_Title" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then "Monitoring_Container_Title" element in "Projects_Monitoring_Container" on "Projects" should contains "Monitoring" value Then verify "Monitoring_Jobs_Box_Title" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then "Monitoring_Jobs_Box_Title" element in "Monitoring_Jobs_Box" on "Projects" should contains "Jobs" value + Then "Monitoring_Jobs_Box_Title" element in "Monitoring_Jobs_Box" on "Projects" should contains "Runs" value Then verify "Total_Counter_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard @@ -631,8 +624,8 @@ Feature: Projects Page Then "Monitoring_Workflows_Box_Title" element in "Monitoring_Workflows_Box" on "Projects" should contains "Workflows" value Then verify "Total_Counter_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Total_Counter_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "4" value - Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard - Then "Counter_Running_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "1" value + Then verify "Counter_In_Process_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard + Then "Counter_In_Process_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "1" value Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard Then "Counter_Failed_Status_Number" element in "Monitoring_Workflows_Box" on "Projects" should contains "1" value Then verify "Counter_Completed_Status_Number" element visibility in "Monitoring_Workflows_Box" on "Projects" wizard diff --git a/tests/mockServer/data/run.json b/tests/mockServer/data/run.json index 85b19099bd..d4f2b453da 100644 --- a/tests/mockServer/data/run.json +++ b/tests/mockServer/data/run.json @@ -371,6 +371,47 @@ "retry_count": 0 } }, + { + "kind": "run", + "metadata": { + "name": "fesf", + "uid": "c1a32f275eb743f781fd13d7a316a657", + "iteration": 0, + "project": "fsdemo-admin", + "labels": { + "v3io_user": "admin", + "owner": "admin", + "kind": "job" + }, + "annotations": {} + }, + "spec": { + "function": "fsdemo-admin/fesf@cfa663e14f1c7b71c7072afbc91827a23a86e964", + "log_level": "info", + "parameters": {}, + "outputs": [], + "output_path": "v3io:///projects/fsdemo-admin/artifacts/c1a32f275eb743f781fd13d7a316a657", + "inputs": {}, + "hyperparams": {}, + "hyper_param_options": {}, + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } + }, + "status": { + "state": "error", + "results": {}, + "start_time": "2021-09-10T11:46:36.715480+00:00", + "last_update": "2021-09-10T11:46:36.768280+00:00", + "artifacts": [], + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:46:36 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-frtb9\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-frtb9\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 0 + } + }, { "kind": "run", "metadata": { diff --git a/tests/mockServer/data/runs.json b/tests/mockServer/data/runs.json index 0e536fae5e..2f89e038f7 100644 --- a/tests/mockServer/data/runs.json +++ b/tests/mockServer/data/runs.json @@ -495,6 +495,47 @@ "retry_count": 1 } }, + { + "kind": "run", + "metadata": { + "name": "fesf", + "uid": "c1a32f275eb743f781fd13d7a316a657", + "iteration": 0, + "project": "fsdemo-admin", + "labels": { + "v3io_user": "admin", + "owner": "admin", + "kind": "job" + }, + "annotations": {} + }, + "spec": { + "function": "fsdemo-admin/fesf@cfa663e14f1c7b71c7072afbc91827a23a86e964", + "log_level": "info", + "parameters": {}, + "outputs": [], + "output_path": "v3io:///projects/fsdemo-admin/artifacts/c1a32f275eb743f781fd13d7a316a657", + "inputs": {}, + "hyperparams": {}, + "hyper_param_options": {}, + "data_stores": [], + "retry": { + "count": 6, + "backoff": { + "base_delay": "30s" + } + } + }, + "status": { + "state": "error", + "results": {}, + "start_time": "2021-09-10T11:46:36.715480+00:00", + "last_update": "2021-09-10T11:46:36.768280+00:00", + "artifacts": [], + "error": "(422)\nReason: Unprocessable Entity\nHTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Fri, 10 Sep 2021 11:46:36 GMT', 'Content-Length': '970'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Pod \\\"fesf-frtb9\\\" is invalid: [spec.volumes[0].name: Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'), spec.containers[0].volumeMounts[0].name: Not found: \\\"NAME\\\"]\",\"reason\":\"Invalid\",\"details\":{\"name\":\"fesf-frtb9\",\"kind\":\"Pod\",\"causes\":[{\"reason\":\"FieldValueInvalid\",\"message\":\"Invalid value: \\\"NAME\\\": a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')\",\"field\":\"spec.volumes[0].name\"},{\"reason\":\"FieldValueNotFound\",\"message\":\"Not found: \\\"NAME\\\"\",\"field\":\"spec.containers[0].volumeMounts[0].name\"}]},\"code\":422}\n\n", + "retry_count": 0 + } + }, { "kind": "run", "metadata": { From ab6a9ed556446b38c8083f5781bbc3be76f50dcb Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Wed, 24 Sep 2025 14:13:12 +0300 Subject: [PATCH 160/228] Tests [LLM Prompts] Add mock data (#3442) --- tests/mockServer/data/artifacts.json | 188 ++++++++++++++++++++++ tests/mockServer/data/modelEndpoints.json | 99 ++++++++++++ tests/mockServer/data/projects.json | 62 +++++++ tests/mockServer/data/summary.json | 52 ++++++ tests/mockServer/mock.js | 7 +- 5 files changed, 403 insertions(+), 5 deletions(-) diff --git a/tests/mockServer/data/artifacts.json b/tests/mockServer/data/artifacts.json index 0104899524..c2c780ffeb 100644 --- a/tests/mockServer/data/artifacts.json +++ b/tests/mockServer/data/artifacts.json @@ -40029,6 +40029,194 @@ "state": "created" }, "project": "churn-project-admin" + }, + { + "kind": "llm-prompt", + "metadata": { + "key": "my_llm", + "project": "llmdeploy332", + "iter": 0, + "tree": "c00325f6-c2cb-4c62-ad93-8d5de6d0d10d", + "hash": "43efded68eae128eeb22b4a9252b7d455c36a287", + "uid": "1d459c52a1102adcbbe242e6bb36e99129f2a8b9", + "updated": "2025-08-11 11:56:12.279000+00:00", + "labels": { + "example": "single", + "hebrew": "english" + }, + "created": "2025-08-11 11:56:12.279000+00:00", + "tag": "latest" + }, + "spec": { + "target_path": "v3io:///projects/llmdeploy332/artifacts/my_llm", + "size": 262, + "license": "", + "model_configuration": { + "temperature": 0.5 + }, + "producer": { + "kind": "project", + "name": "llmdeploy332", + "tag": "c00325f6-c2cb-4c62-ad93-8d5de6d0d10d", + "owner": "normal-user" + }, + "prompt_legend": { + "something_with_meaning": { + "field": "word", + "description": "The essence of all things" + } + }, + "prompt_template": [ + { + "role": "system", + "content": "don't tell them anything" + }, + { + "role": "user", + "content": "What is the meaning of {something_with_meaning}?" + }, + { + "role": "system", + "content": "tell you story" + }, + { + "role": "user", + "content": "What is the biggest of {country} at all?" + } + ], + "has_children": false, + "db_key": "my_llm", + "parent_uri": "store://models/llmdeploy332/model_art1#0:v1@418c1ad0-ab41-45df-afb9-722d48d5d65a^bff98dcfd64bd3db006488b7808e9d2dcf37b56f" + }, + "status": { + "state": "created" + }, + "project": "llmdeploy332" + }, + { + "kind": "model", + "metadata": { + "key": "model_art1", + "project": "llmdeploy332", + "iter": 0, + "tree": "418c1ad0-ab41-45df-afb9-722d48d5d65a", + "hash": "dae3b5936acdb82b153b8a17d7d71ba7a66b6b60", + "uid": "bff98dcfd64bd3db006488b7808e9d2dcf37b56f", + "updated": "2025-08-11 11:56:12.178000+00:00", + "created": "2025-08-11 11:56:12.178000+00:00", + "tag": "latest" + }, + "spec": { + "target_path": "llmdeploy332/model_art1/", + "size": 4370, + "license": "", + "framework": "", + "producer": { + "kind": "project", + "name": "llmdeploy332", + "tag": "418c1ad0-ab41-45df-afb9-722d48d5d65a", + "owner": "normal-user" + }, + "model_file": "RandomForestClassifier_file1.pkl", + "has_children": true, + "db_key": "model_art1", + "parameters": { + "default_config": { + "model_version": "4" + } + }, + "parent_uri": null + }, + "status": { + "state": "created" + }, + "project": "llmdeploy332" + }, + { + "kind": "llm-prompt", + "metadata": { + "key": "my_llm", + "project": "llmdeploy335", + "iter": 0, + "tree": "9dea0dcc-8251-4f4e-94a8-c76b9a64db45", + "hash": "b18c9d7f42c212330a52d6a6d093e37e9fad2491", + "uid": "dc193ddf0914485f8c49d734d4cf8e240dcae118", + "updated": "2025-08-27 14:29:33.222000+00:00", + "labels": { + "example": "single", + "hebrew": "english" + }, + "created": "2025-08-27 14:29:33.222000+00:00", + "tag": "latest" + }, + "spec": { + "src_path": "my_llm.txt", + "target_path": "v3io:///projects/llmdeploy335/artifacts/my_llm.txt", + "size": 173, + "description": "my first promt description for testing", + "prompt_legend": { + "something_with_meaning": { + "field": "something_with_meaning", + "description": "The essence of all things" + } + }, + "has_children": false, + "license": "", + "producer": { + "kind": "project", + "name": "llmdeploy335", + "tag": "9dea0dcc-8251-4f4e-94a8-c76b9a64db45", + "owner": "normal-user" + }, + "model_configuration": { + "temperature": 0.5 + }, + "db_key": "my_llm", + "parent_uri": "store://models/llmdeploy335/model_art1#0:v1@47e2a43f-07fc-4e60-970b-10e10dcd2daf^0a571c5752ee1eb1efdf74c435088ee80b0c521b" + }, + "status": { + "state": "created" + }, + "project": "llmdeploy335" + }, + { + "kind": "model", + "metadata": { + "key": "model_art1", + "project": "llmdeploy335", + "iter": 0, + "tree": "47e2a43f-07fc-4e60-970b-10e10dcd2daf", + "hash": "dae3b5936acdb82b153b8a17d7d71ba7a66b6b60", + "uid": "0a571c5752ee1eb1efdf74c435088ee80b0c521b", + "updated": "2025-08-27 14:29:33.058000+00:00", + "created": "2025-08-27 14:29:33.058000+00:00", + "tag": "latest" + }, + "spec": { + "target_path": "llmdeploy335/model_art1/", + "size": 4370, + "framework": "", + "has_children": true, + "license": "", + "producer": { + "kind": "project", + "name": "llmdeploy335", + "tag": "47e2a43f-07fc-4e60-970b-10e10dcd2daf", + "owner": "normal-user" + }, + "model_file": "RandomForestClassifier_file1.pkl", + "db_key": "model_art1", + "parameters": { + "default_config": { + "model_version": "4" + } + }, + "parent_uri": null + }, + "status": { + "state": "created" + }, + "project": "llmdeploy335" } ] } \ No newline at end of file diff --git a/tests/mockServer/data/modelEndpoints.json b/tests/mockServer/data/modelEndpoints.json index 100968951d..1f3dbb8fe9 100644 --- a/tests/mockServer/data/modelEndpoints.json +++ b/tests/mockServer/data/modelEndpoints.json @@ -1039,6 +1039,105 @@ }, "sampling_percentage": null } + }, + { + "kind": "model-endpoint", + "metadata": { + "name": "my-endpoint", + "project": "llmdeploy335", + "tag": null, + "labels": { + "example": "single", + "hebrew": "english" + }, + "updated": "2025-08-27T14:29:33.747000", + "created": "2025-08-12T09:05:30.007000", + "uid": "f7172d26e7f94233994e0998aa404efb", + "endpoint_type": 1, + "mode": 0 + }, + "spec": { + "model_class": "mlrun.serving.Model", + "function_name": "function-with-llm", + "function_tag": "latest", + "model_path": "store://llm-prompts/llmdeploy335/my_llm#0@5780e34d-c0ed-46ed-ab49-39addf35a7ec^5ddece12a48b7199688a122911344f3a217addd7", + "model_name": "my_llm", + "model_tags": [ + "latest", + "111" + ], + "feature_names": [], + "label_names": [], + "feature_stats": {}, + "function_uri": "llmdeploy335/function-with-llm@unversioned-latest", + "model_uri": "store://llm-prompts/llmdeploy335/my_llm#0@9dea0dcc-8251-4f4e-94a8-c76b9a64db45^dc193ddf0914485f8c49d734d4cf8e240dcae118", + "children": null, + "children_uids": null, + "monitoring_feature_set_uri": "" + }, + "status": { + "state": "ready", + "first_request": null, + "monitoring_mode": "disabled", + "sampling_percentage": 100.0, + "last_request": null, + "result_status": -1, + "avg_latency": null, + "error_count": 0, + "current_stats": {}, + "current_stats_timestamp": null, + "drift_measures": {}, + "drift_measures_timestamp": null + } + }, + { + "kind": "model-endpoint", + "metadata": { + "name": "my-endpoint", + "project": "llmdeploy332", + "tag": null, + "labels": { + "example": "single", + "hebrew": "english" + }, + "updated": "2025-08-11T11:56:13.020000", + "created": "2025-08-11T11:56:13.020000", + "uid": "b2a773fdd4a94719850102cfffb25601", + "endpoint_type": 1, + "mode": 0 + }, + "spec": { + "model_class": "mlrun.serving.Model", + "function_name": "function-with-llm", + "function_tag": "latest", + "model_path": "store://llm-prompts/llmdeploy332/my_llm#0@c00325f6-c2cb-4c62-ad93-8d5de6d0d10d^1d459c52a1102adcbbe242e6bb36e99129f2a8b9", + "model_name": "my_llm", + "model_tags": [ + "latest" + ], + "feature_names": [], + "label_names": [], + "feature_stats": {}, + "function_uri": "llmdeploy332/function-with-llm@unversioned-latest", + "model_uri": "store://llm-prompts/llmdeploy332/my_llm#0@c00325f6-c2cb-4c62-ad93-8d5de6d0d10d^1d459c52a1102adcbbe242e6bb36e99129f2a8b9", + "children": null, + "children_uids": null, + "monitoring_feature_set_uri": "" + }, + "status": { + "state": "ready", + "first_request": null, + "monitoring_mode": "disabled", + "sampling_percentage": 100.0, + "last_request": null, + "result_status": -1, + "avg_latency": null, + "error_count": 0, + "current_stats": {}, + "current_stats_timestamp": null, + "drift_measures": {}, + "drift_measures_timestamp": null + } } ] } diff --git a/tests/mockServer/data/projects.json b/tests/mockServer/data/projects.json index fee8e0e84b..7b57c9f5fb 100644 --- a/tests/mockServer/data/projects.json +++ b/tests/mockServer/data/projects.json @@ -1641,6 +1641,68 @@ "status": { "state": "online" } + }, + { + "kind": "project", + "metadata": { + "name": "llmdeploy335", + "created": "2025-08-11T12:32:38.084000", + "labels": {}, + "annotations": {} + }, + "spec": { + "description": null, + "owner": "normal-user", + "goals": null, + "params": {}, + "functions": null, + "workflows": null, + "artifacts": null, + "artifact_path": null, + "conda": "", + "source": "", + "subpath": null, + "origin_url": null, + "desired_state": "online", + "custom_packagers": null, + "default_image": null, + "build": null, + "default_function_node_selector": {} + }, + "status": { + "state": "online" + } + }, + { + "kind": "project", + "metadata": { + "name": "llmdeploy332", + "created": "2025-08-11T11:54:20.014000", + "labels": {}, + "annotations": {} + }, + "spec": { + "description": null, + "owner": "normal-user", + "goals": null, + "params": {}, + "functions": null, + "workflows": null, + "artifacts": null, + "artifact_path": null, + "conda": "", + "source": "", + "subpath": null, + "origin_url": null, + "desired_state": "online", + "custom_packagers": null, + "default_image": null, + "build": null, + "default_function_node_selector": {} + }, + "status": { + "state": "online" + } } ] } diff --git a/tests/mockServer/data/summary.json b/tests/mockServer/data/summary.json index 1f73884801..e1293ce6b0 100644 --- a/tests/mockServer/data/summary.json +++ b/tests/mockServer/data/summary.json @@ -380,6 +380,58 @@ "datasets_count": 2, "documents_count": 1, "llm_prompts_count": 4 + }, + { + "name": "llmdeploy335", + "files_count": 0, + "feature_sets_count": 0, + "models_count": 1, + "runs_completed_recent_count": 0, + "runs_failed_recent_count": 0, + "runs_running_count": 0, + "distinct_schedules_count": 0, + "distinct_scheduled_jobs_pending_count": 0, + "distinct_scheduled_pipelines_pending_count": 0, + "pipelines_completed_recent_count": 0, + "pipelines_failed_recent_count": 0, + "pipelines_running_count": 0, + "updated": "2025-09-22T17:55:02.296348+00:00", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, + "datasets_count": 0, + "documents_count": 0, + "llm_prompts_count": 1, + "running_model_monitoring_functions": 0, + "failed_model_monitoring_functions": 0, + "real_time_model_endpoint_count": 1, + "batch_model_endpoint_count": 0 + }, + { + "name": "llmdeploy332", + "files_count": 0, + "feature_sets_count": 0, + "models_count": 1, + "runs_completed_recent_count": 0, + "runs_failed_recent_count": 0, + "runs_running_count": 0, + "distinct_schedules_count": 0, + "distinct_scheduled_jobs_pending_count": 0, + "distinct_scheduled_pipelines_pending_count": 0, + "pipelines_completed_recent_count": 0, + "pipelines_failed_recent_count": 0, + "pipelines_running_count": 0, + "updated": "2025-09-22T18:01:05.616740+00:00", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, + "datasets_count": 0, + "documents_count": 0, + "llm_prompts_count": 1, + "running_model_monitoring_functions": 0, + "failed_model_monitoring_functions": 0, + "real_time_model_endpoint_count": 1, + "batch_model_endpoint_count": 0 } ] } diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 26f4b6b567..ea8bb29c00 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -214,6 +214,7 @@ const artifactsCategories = { dataset: ['dataset'], document: ['document'], model: ['model'], + 'llm-prompt': ['llm-prompt'], other: ['', 'table', 'link', 'plot', 'chart', 'plotly', 'artifact'] } @@ -968,11 +969,7 @@ function getRuns(req, res) { pathToPartition.push('metadata.project') } - collectedRuns = getPartitionedData( - collectedRuns, - pathToPartition, - 'status.last_update' - ) + collectedRuns = getPartitionedData(collectedRuns, pathToPartition, 'status.last_update') } if (req.query['name']) { From 4732ec906933d5ba528a92eb91695e7ed8071e45 Mon Sep 17 00:00:00 2001 From: adi-gini Date: Thu, 25 Sep 2025 10:53:39 +0300 Subject: [PATCH 161/228] Fix [Counters] Add tooltips to counters on monitoring pages (#3444) --- .../monitoringApplicationCounters.util.jsx | 2 + .../ProjectFunctions/ProjectFunctions.jsx | 2 + .../ApplicationCounters.jsx | 42 ++++++++++--------- src/utils/generateMonitoringData.js | 6 ++- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index b0673b71a9..77cdf96acd 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -66,12 +66,14 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => { id: 'running', title: appReady, + tooltipText: 'Running', subtitle: 'Running', subtitleStatus: 'running' }, { id: 'failed', title: appError, + tooltipText: 'Failed, Error, Unhealthy', subtitle: 'Failed', subtitleStatus: 'failed' } diff --git a/src/elements/ProjectFunctions/ProjectFunctions.jsx b/src/elements/ProjectFunctions/ProjectFunctions.jsx index b5b6c5bce4..bf04d451f5 100644 --- a/src/elements/ProjectFunctions/ProjectFunctions.jsx +++ b/src/elements/ProjectFunctions/ProjectFunctions.jsx @@ -83,6 +83,7 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { return { running: { + counterTooltip: 'Running', value: functionsRunning, label: 'Running', className: 'running', @@ -91,6 +92,7 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { loading: nuclioStore.loading }, failed: { + counterTooltip: 'Failed, Error, Unhealthy', value: functionsFailed, label: 'Failed', status: 'failed', diff --git a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx index fd3a48fbda..a5b96364e7 100644 --- a/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ApplicationCounters.jsx @@ -18,7 +18,7 @@ import React, { useMemo, useRef, useState } from 'react' import { useSelector } from 'react-redux' import { useNavigate, useParams } from 'react-router-dom' -import { Loader, PopUpDialog } from 'igz-controls/components' +import { Loader, PopUpDialog, TextTooltipTemplate, Tooltip } from 'igz-controls/components' import { APPLICATION } from '../../constants' import StatsCard from '../../common/StatsCard/StatsCard' @@ -93,25 +93,29 @@ const ApplicationCounter = () => {
      - {applicationStats.counters.map(({ counter, className, label, statusClass, link }) => ( -
      - - {projectStore?.projectsSummary?.loading ? ( - - ) : ( - counter.toLocaleString() - )} - -
      -
      {label}
      - + {applicationStats.counters.map( + ({ counter, className, label, statusClass, link, tooltip }) => ( +
      + + {projectStore?.projectsSummary?.loading ? ( + + ) : ( + counter.toLocaleString() + )} + + }> +
      +
      {label}
      + +
      +
      -
      - ))} + ) + )}
      {showPopup && ( diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index dd22d972d9..9b13bbf62b 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -225,7 +225,8 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { link: () => navigateToTab(projectName, MONITORING_APP_PAGE), statusClass: 'running', label: RUNNING, - popUpClassName: classNames({ 'card-popup_text_link': projectName }) + popUpClassName: classNames({ 'card-popup_text_link': projectName }), + tooltip: RUNNING }, { counter: data.failed || 0, @@ -235,7 +236,8 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { link: () => navigateToTab(projectName, MONITORING_APP_PAGE), statusClass: 'failed', label: FAILED, - popUpClassName: classNames({ 'card-popup_text_link': projectName }) + popUpClassName: classNames({ 'card-popup_text_link': projectName }), + tooltip: 'Failed, Error, Unhealthy' } ] } From 86718a9582d82f50de6bef2e3cfdbf989f357246 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:54:59 +0300 Subject: [PATCH 162/228] Fix [Model Endpoints] Align "No data" message with common application message (#3443) --- src/utils/getNoDataMessage.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/utils/getNoDataMessage.js b/src/utils/getNoDataMessage.js index f6eb6af3b3..123c431f73 100644 --- a/src/utils/getNoDataMessage.js +++ b/src/utils/getNoDataMessage.js @@ -66,7 +66,8 @@ import { PROJECTS_FILTER_ALL_ITEMS, LLM_PROMPTS_PAGE, MODEL_NAME_FILTER, - MODEL_TAG_FILTER + MODEL_TAG_FILTER, + ME_MODE_FILTER } from '../constants' const messageNamesList = { @@ -227,6 +228,7 @@ const getVisibleFilterTypes = (filtersConfig, filters, filtersStore) => { (type === DATES_FILTER && !isEqual(filters[DATES_FILTER]?.value, DATE_FILTER_ANY_TIME)) const isShowUntaggedVisible = type === SHOW_UNTAGGED_FILTER && !filters[SHOW_UNTAGGED_FILTER] const isGroupByVisible = type === GROUP_BY_FILTER && filtersStore.groupBy !== GROUP_BY_NONE + const isMEModeVisible = type === ME_MODE_FILTER && filters[ME_MODE_FILTER] !== FILTER_ALL_ITEMS return ( isDateVisible || @@ -240,7 +242,8 @@ const getVisibleFilterTypes = (filtersConfig, filters, filtersStore) => { isShowUntaggedVisible || isStatusVisible || isTagVisible || - isTypeVisible + isTypeVisible || + isMEModeVisible ) }) } From 86028c43357553787a134512e85486c9d4262c25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:06:31 +0300 Subject: [PATCH 163/228] Bump axios in the npm_and_yarn group across 1 directory (#3429) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3c73efda4d..bcb3f65e1c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "dependencies": { "@monaco-editor/react": "^4.7.0", "@reduxjs/toolkit": "^1.9.5", - "axios": "1.8.2", + "axios": "1.12.0", "bfj": "^7.0.2", "camelcase": "^6.3.0", "chart.js": "^4.4.2", From 4a15dfe4240090a63f06cae08da9ecb5fe96342d Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Sun, 28 Sep 2025 17:54:18 +0300 Subject: [PATCH 164/228] Fix [UI] Adjust 'Monitoring app' css (#3445) --- src/components/ApplicationMetrics/ApplicationMetrics.scss | 3 +-- .../ProjectsMonitoringCounters/projectsMonitoringCounters.scss | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ApplicationMetrics/ApplicationMetrics.scss b/src/components/ApplicationMetrics/ApplicationMetrics.scss index b95c5e6980..9d2340155b 100644 --- a/src/components/ApplicationMetrics/ApplicationMetrics.scss +++ b/src/components/ApplicationMetrics/ApplicationMetrics.scss @@ -76,14 +76,13 @@ $searchHeight: 75px; li { padding: 0 8px; - border-radius: 8px; cursor: pointer; user-select: none; div { height: $listItemHeight; line-height: $listItemHeight; - border-bottom: borders.$primaryBorder; + border-bottom: borders.$tableRowBorder; } &:hover, diff --git a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss index d17333a1c3..c50bd386c4 100644 --- a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss +++ b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss @@ -75,6 +75,7 @@ position: relative; display: flex; justify-content: space-between; + align-items: center; width: 100%; padding-bottom: 0.5rem; } From d3ee9affbc3f2f199a38d09ab0bced4c8d373953 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Tue, 30 Sep 2025 12:52:26 +0300 Subject: [PATCH 165/228] Fix [UI] css (#3447) --- .../monitoringApplicationCounters.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss index 7f1f0857df..4676f27132 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss @@ -33,6 +33,9 @@ } .stats__counter { + display: flex; + align-items: center; + justify-content: center; color: colors.$primary; font-weight: 500; font-size: 28px; @@ -42,7 +45,7 @@ margin-bottom: 10px; } - [class^="state"] { + [class^='state'] { margin-left: 5px; } } From d6b83ef2845adbc6114c3cd99753b09d05221ca3 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:38:09 +0300 Subject: [PATCH 166/228] Fix [LLM Prompt] Change `model_configuration` to be named `invocation_config` (#3446) --- .../DetailsGenerationConfiguration.jsx | 8 ++++---- tests/mockServer/data/artifacts.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx b/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx index 51335215cc..a95293080a 100644 --- a/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx +++ b/src/components/Details/DetailsGenerationConfiguration/DetailsGenerationConfiguration.jsx @@ -26,17 +26,17 @@ import './detailsGenerationConfiguration.scss' const DetailsGenerationConfiguration = ({ selectedItem }) => { return (
      - {!isEmpty(selectedItem.model_configuration) && ( + {!isEmpty(selectedItem.invocation_config) && ( <>
      - {Object.entries(selectedItem.model_configuration || {}).length} modifications made to + {Object.entries(selectedItem.invocation_config || {}).length} modifications made to the default configuration:
      Key
      Value
      - {Object.entries(selectedItem.model_configuration || {}).map(([key, value]) => { + {Object.entries(selectedItem.invocation_config || {}).map(([key, value]) => { return (
      {key}
      @@ -46,7 +46,7 @@ const DetailsGenerationConfiguration = ({ selectedItem }) => { })} )} - {isEmpty(selectedItem.model_configuration) && Default configuration is used.} + {isEmpty(selectedItem.invocation_config) && Default configuration is used.}
      ) } diff --git a/tests/mockServer/data/artifacts.json b/tests/mockServer/data/artifacts.json index c2c780ffeb..252810c342 100644 --- a/tests/mockServer/data/artifacts.json +++ b/tests/mockServer/data/artifacts.json @@ -40051,7 +40051,7 @@ "target_path": "v3io:///projects/llmdeploy332/artifacts/my_llm", "size": 262, "license": "", - "model_configuration": { + "invocation_config": { "temperature": 0.5 }, "producer": { @@ -40168,7 +40168,7 @@ "tag": "9dea0dcc-8251-4f4e-94a8-c76b9a64db45", "owner": "normal-user" }, - "model_configuration": { + "invocation_config": { "temperature": 0.5 }, "db_key": "my_llm", From 196324dac8e1d460ecf422440bcf7678560d135b Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:38:25 +0300 Subject: [PATCH 167/228] Fix [Counters] Failed counter numbers are not displayed in red (#3448) --- src/common/StatsCard/StatsCard.jsx | 11 +++++++---- src/common/StatsCard/statsCard.scss | 4 ++-- .../ProjectsMonitoringCounters/RunsCounters.jsx | 4 ++-- .../projectsMonitoringCounters.scss | 10 +++++----- src/utils/generateMonitoringData.js | 16 ++++++---------- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/common/StatsCard/StatsCard.jsx b/src/common/StatsCard/StatsCard.jsx index efb8bfcab2..4eeaa4868b 100644 --- a/src/common/StatsCard/StatsCard.jsx +++ b/src/common/StatsCard/StatsCard.jsx @@ -67,7 +67,7 @@ StatsCard.Col = ({ children }) => { StatsCard.Col.displayName = 'StatsCard.Col' StatsCard.MainCounter = ({ children, className = '', id = '', onClick = () => { } }) => { - const mainCounterClass = classNames('stats__counter_main', className) + const mainCounterClass = classNames('stats__counter-main', className) return (
      @@ -79,9 +79,11 @@ StatsCard.MainCounter = ({ children, className = '', id = '', onClick = () => { } StatsCard.MainCounter.displayName = 'StatsCard.MainCounter' -StatsCard.SecondaryCounter = ({ children }) => { +StatsCard.SecondaryCounter = ({ children, className }) => { + const secondaryCounterClass = classNames('stats__counter-secondary', className) + return ( -
      +
      {children}
      @@ -121,7 +123,8 @@ StatsCard.MainCounter.propTypes = { } StatsCard.SecondaryCounter.propTypes = { - children: PropTypes.node.isRequired + children: PropTypes.node.isRequired, + className: PropTypes.string } export default StatsCard diff --git a/src/common/StatsCard/statsCard.scss b/src/common/StatsCard/statsCard.scss index 63158190fe..6f34f01682 100644 --- a/src/common/StatsCard/statsCard.scss +++ b/src/common/StatsCard/statsCard.scss @@ -98,11 +98,11 @@ color: colors.$primary; font-weight: 500; - &_main { + &-main { font-size: 26px; } - &_secondary { + &-secondary { font-size: 15px; } } diff --git a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx index fd158b6480..a68815bc7a 100644 --- a/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/RunsCounters.jsx @@ -80,7 +80,7 @@ const RunCounter = () => {
      {jobStats?.counters?.map( - ({ counter, className, label, link, statusClass, tooltip }) => { + ({ counter, className, counterClassName, label, link, statusClass, tooltip }) => { return (
      {
      - + {projectStore?.projectsSummary?.loading ? ( ) : ( diff --git a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss index c50bd386c4..884d0b2352 100644 --- a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss +++ b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss @@ -43,7 +43,7 @@ } .stats { - &__failed { + &__failed > .stats__counter { color: colors.$amaranth; } @@ -95,7 +95,7 @@ } } - .stats__counter_main { + .stats__counter-main { padding-bottom: 0; } @@ -120,11 +120,11 @@ cursor: pointer; &:hover { - *:not(.stats__failed) { + *:not(.stats__failed > .stats__counter) { @include counterLinkHover; } - .stats__failed { + .stats__failed > .stats__counter { color: colors.$amaranth; text-decoration: underline; text-underline-offset: 1px; @@ -192,8 +192,8 @@ } &__details { - margin: 0; display: none; + margin: 0; @media (min-width: 1250px) { display: block; diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index 9b13bbf62b..82cd342d4d 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -84,8 +84,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }), statusClass: 'running', tooltip: 'Aborting, Pending, Pending retry, Running', - label: IN_PROCESS, - counterClassName: 'stats__counter' + label: IN_PROCESS }, { counter: data.failed || 0, @@ -98,7 +97,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { statusClass: 'failed', tooltip: 'Aborted, Error', label: FAILED, - counterClassName: classNames('stats__counter', { + counterClassName: classNames({ stats__failed: data.failed > 0 }) }, @@ -112,8 +111,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }), statusClass: 'completed', tooltip: 'Completed', - label: SUCCEEDED, - counterClassName: 'stats__counter' + label: SUCCEEDED } ] } @@ -138,8 +136,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { className: classNames('stats__link', 'stats__line'), statusClass: 'running', tooltip: 'Running, Terminating', - label: IN_PROCESS, - counterClassName: 'stats__counter' + label: IN_PROCESS }, { counter: data.failed || 0, @@ -152,7 +149,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { statusClass: 'failed', tooltip: 'Error, Failed', label: FAILED, - counterClassName: classNames('stats__counter', { + counterClassName: classNames({ stats__failed: data.failed > 0 }) }, @@ -166,8 +163,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }), statusClass: 'completed', tooltip: 'Completed', - label: SUCCEEDED, - counterClassName: 'stats__counter' + label: SUCCEEDED } ] } From 6df4bcff6d082a27aa6b8c936b2b63ea6226d3d0 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:38:40 +0300 Subject: [PATCH 168/228] Fix [Model endpoints] Update mock for model endpoint filtering by mode (#3449) --- tests/mockServer/data/modelEndpoints.json | 4 ++++ tests/mockServer/mock.js | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/tests/mockServer/data/modelEndpoints.json b/tests/mockServer/data/modelEndpoints.json index 1f3dbb8fe9..ed9bc50487 100644 --- a/tests/mockServer/data/modelEndpoints.json +++ b/tests/mockServer/data/modelEndpoints.json @@ -10,6 +10,7 @@ "v3io_user": "admin" }, "endpoint_type": 3, + "mode": 0, "name": "RandomForestClassifier", "created": "2024-11-03T09:18:59.079000", "updated": "2024-11-03T09:40:58.317000", @@ -272,6 +273,7 @@ "v3io_user": "admin" }, "endpoint_type": 3, + "mode": 1, "name": "RandomForestClassifier2", "created": "2024-11-03T09:18:59.079000", "updated": "2024-11-03T09:40:58.317000", @@ -530,6 +532,7 @@ "project": "default", "labels": {}, "endpoint_type": 3, + "mode": 0, "name": "GradientBoostingClassifier", "created": "2024-12-03T09:18:59.079000", "updated": "2024-12-03T09:40:58.317000", @@ -788,6 +791,7 @@ "project": "default", "labels": {}, "endpoint_type": 3, + "mode": 1, "name": "GradientBoostingClassifier2", "created": "2024-12-03T09:18:59.079000", "updated": "2024-12-03T09:40:58.317000", diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index ea8bb29c00..5eb453cd07 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -2589,6 +2589,12 @@ function getModelEndpoints(req, res) { ) } + if (req.query['mode']) { + collectedEndpoints = collectedEndpoints.filter(endpoint => + Number(endpoint.metadata.mode) === Number(req.query['mode']) + ) + } + if (req.query['endpoint_id']) { const modelEndpoint = collectedEndpoints.find( endpoint => endpoint.metadata.uid === req.query.endpoint_id From 3172417cec978d17b89a622ff1bb55c9143fd21c Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:38:52 +0300 Subject: [PATCH 169/228] Fix [Scheduled job] Missing loader on deletion (#3451) --- src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx | 1 - src/reducers/jobReducer.js | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx b/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx index 871639105c..6be2b8c3e8 100644 --- a/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx +++ b/src/elements/ScheduledJobsTable/ScheduledJobsTable.jsx @@ -90,7 +90,6 @@ const ScheduledJobsTable = ({ return createTableContent() }, [createTableContent]) - const refreshJobsWithFilters = useCallback( (useInitialFilter, isSchedule) => { if (isSchedule) { diff --git a/src/reducers/jobReducer.js b/src/reducers/jobReducer.js index b2b5e11fed..4d0a98bccb 100644 --- a/src/reducers/jobReducer.js +++ b/src/reducers/jobReducer.js @@ -19,7 +19,7 @@ such restriction. */ import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' import jobsApi from '../api/jobs-api' -import { hideLoading, showLoading } from './redux.util' +import { defaultRejectedHandler, hideLoading, showLoading } from './redux.util' import { get } from 'lodash' import { DATES_FILTER, @@ -415,9 +415,9 @@ const jobsSlice = createSlice({ state.scheduled = [] state.loading = false }) - builder.addCase(removeScheduledJob.rejected, (state, action) => { - state.error = action.payload - }) + builder.addCase(removeScheduledJob.pending, showLoading) + builder.addCase(removeScheduledJob.fulfilled, hideLoading) + builder.addCase(removeScheduledJob.rejected, defaultRejectedHandler) builder.addCase(runNewJob.pending, showLoading) builder.addCase(runNewJob.fulfilled, state => { state.error = null From 5cb7f36a8960e39e8502528ae8c04590bde33545 Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:39:36 +0200 Subject: [PATCH 170/228] Tests [QA] v1.10.0-rc28 (#3450) --- package.json | 2 +- tests/features/MLFunction.feature | 4 +- tests/features/alerts.feature | 52 +++++----- tests/features/alertsMonitoring.feature | 29 ++++-- tests/features/common-tools/common-consts.js | 25 ++++- .../page-objects/interactive-popup.po.js | 11 ++- tests/features/jobsAndWorkflows.feature | 27 +++--- tests/features/models.feature | 4 + tests/features/monitoringApp.feature | 97 +++++++++++++++++++ tests/features/projectMonitoring.feature | 4 +- tests/features/projectsPage.feature | 6 +- tests/mockServer/data/alerts.json | 46 +++++++-- tests/mockServer/data/funcs.json | 94 +++++++++++++++++- tests/mockServer/data/logs.json | 19 ++++ tests/mockServer/data/run.json | 54 ++++++++++- tests/mockServer/data/runs.json | 54 ++++++++++- tests/mockServer/mock.js | 2 +- 17 files changed, 455 insertions(+), 75 deletions(-) diff --git a/package.json b/package.json index bcb3f65e1c..6545c0e419 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "react-dev-utils": "^12.0.1", "sass": "^1.72.0", "sass-loader": "^12.3.2", - "selenium-webdriver": "^4.0.0-beta.2", + "selenium-webdriver": "^4.35.0", "source-map-loader": "^5.0.0", "stylelint": "^13.3.3", "stylelint-config-rational-order": "^0.1.2", diff --git a/tests/features/MLFunction.feature b/tests/features/MLFunction.feature index 24213c32f7..ff3a114412 100644 --- a/tests/features/MLFunction.feature +++ b/tests/features/MLFunction.feature @@ -109,7 +109,7 @@ Feature: ML Functions Then verify "Date_Picker_Filter_Dropdown" dropdown element on "ML_Functions" wizard should contains "Dropdown_Options"."Date_Picker_Filter_Options" When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "ML_Functions" wizard And wait load page - When click on cell with row index 2 in "name" column in "Functions_Table" table on "ML_Functions" wizard + When click on cell with row index 3 in "name" column in "Functions_Table" table on "ML_Functions" wizard And wait load page Then verify "Header" element visibility on "ML_Function_Info_Pane" wizard Then verify "Updated" element visibility on "ML_Function_Info_Pane" wizard @@ -119,7 +119,7 @@ Feature: ML Functions Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "ML_Function_Info_Pane" wizard Then verify "Overview_Headers" on "ML_Function_Info_Pane" wizard should contains "ML_Function_Info_Pane"."Overview_Headers" Then click on "Cross_Close_Button" element on "ML_Function_Info_Pane" wizard - When click on cell with row index 1 in "name" column in "Functions_Table" table on "ML_Functions" wizard + When click on cell with row index 2 in "name" column in "Functions_Table" table on "ML_Functions" wizard And wait load page Then verify "Header" element visibility on "ML_Function_Info_Pane" wizard Then verify "Updated" element visibility on "ML_Function_Info_Pane" wizard diff --git a/tests/features/alerts.feature b/tests/features/alerts.feature index 62ffa2eb23..31dc72b71b 100644 --- a/tests/features/alerts.feature +++ b/tests/features/alerts.feature @@ -53,11 +53,10 @@ Feature: Alerts Page @MLAlert @smoke - # TODO: Add data to the mock to check the following elements (existing alerts with endpoint type) Scenario: MLAlert002 - Check filtering by Endpoint entity type on Alerts page Given open url And wait load page - And click on row root with value "auto-generated-data" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page And select "tab" with "Alerts" value in breadcrumbs menu And wait load page @@ -72,7 +71,6 @@ Feature: Alerts Page When select "Endpoint" option in "Entity_Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page - # Add data to the mock to check the following elements Then verify "Alerts_Table" element visibility on "Alerts" wizard Then value in "entityType" column with "tooltip" in "Alerts_Table" on "Alerts" wizard should contains "Endpoint" Then verify "Table_FilterBy_Button" element on "Alerts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" @@ -154,14 +152,13 @@ Feature: Alerts Page @MLAlert @smoke - # TODO: Add data to the mock to check the following elements (existing alerts with application type) Scenario: MLAlert004 - Check filtering by Application entity type on Alerts page Given open url And wait load page - And click on row root with value "cat-vs-dog-classification" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page Then verify breadcrumbs "tab" label should be equal "Project monitoring" value - Then verify breadcrumbs "project" label should be equal "cat-vs-dog-classification" value + Then verify breadcrumbs "project" label should be equal "default" value And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard Then click on "Alerts_Button" element on "commonPagesHeader" wizard And wait load page @@ -172,7 +169,6 @@ Feature: Alerts Page Then verify "Date_Picker_Filter_Dropdown" dropdown on "Alerts" wizard selected option value "Past 24 hours" When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Alerts" wizard And wait load page - # Add data to the mock to check the following elements Then verify "Alerts_Table" element visibility on "Alerts" wizard Then click on "Table_FilterBy_Button" element on "Alerts" wizard When select "Application" option in "Entity_Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard @@ -267,11 +263,10 @@ Feature: Alerts Page @MLAlert @smoke - # TODO: Add data to the mock to check the following elements (existing job data for details popup) Scenario: MLAlert006 - Check components in Job detail pop-up on Job alert detail pane on Alerts page Given open url And wait load page - And click on row root with value "auto-generated-data" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page And select "tab" with "Alerts" value in breadcrumbs menu And wait load page @@ -285,28 +280,32 @@ Feature: Alerts Page When select "Job" option in "Entity_Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page - Then type value "alertd478b0739b" to "Search_By_Name_Filter_Input" field on "Alerts" wizard + Then value in "entityType" column with "tooltip" in "Alerts_Table" on "Alerts" wizard should contains "Job" + Then click on "Table_FilterBy_Button" element on "Alerts" wizard + When select "All" option in "Entity_Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then type value "obryv-default" to "Search_By_Name_Filter_Input" field on "Alerts" wizard Then click on "Refresh_Button" element on "Alerts" wizard And wait load page - Then value in "alertName" column with "text" in "Alerts_Table" on "Alerts" wizard should contains "alertd478b0739b" + Then value in "alertName" column with "text" in "Alerts_Table" on "Alerts" wizard should contains "alert-name-obryv-default" And wait load page Then verify "Alerts_Table" element visibility on "Alerts" wizard Then value in "entityType" column with "tooltip" in "Alerts_Table" on "Alerts" wizard should contains "Job" When click on cell with row index 1 in "alertName" column in "Alerts_Table" table on "Alerts" wizard And wait load page Then verify "Header" element visibility on "Alerts_Jobs_Info_Pane" wizard - Then "Header" element on "Alerts_Jobs_Info_Pane" should contains "alertd478b0739b" value + Then "Header" element on "Alerts_Jobs_Info_Pane" should contains "alert-name-obryv-default" value Then verify "Overview_General_Headers" element visibility on "Alerts_Jobs_Info_Pane" wizard Then verify "Overview_General_Headers" on "Alerts_Jobs_Info_Pane" wizard should contains "Alerts_Jobs_Info_Pane"."Overview_General_Headers_PerProject" Then verify "Job_Detail_PopUp_Link" element visibility on "Alerts_Jobs_Info_Pane" wizard Then click on "Job_Detail_PopUp_Link" element on "Alerts_Jobs_Info_Pane" wizard - # Add data to the mock to check the following elements Then verify if "Modal_Transition_Popup" popup dialog appears Then verify "Title" element visibility on "Modal_Transition_Popup" wizard - Then "Title" element on "Modal_Transition_Popup" should contains "erann-test" value + Then "Title" element on "Modal_Transition_Popup" should contains "test-func-oyn-handler" value Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard Then verify "State_Icon" element visibility on "Modal_Transition_Popup" wizard - Then verify "State_Icon" element on "Modal_Transition_Popup" wizard should display hover tooltip "Jobs_Monitor_Tab_Info_Pane"."Error_State" + Then verify "State_Icon" element on "Modal_Transition_Popup" wizard should display hover tooltip "Jobs_Monitor_Tab_Info_Pane"."Error_State_With_Message" Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard Then verify "Refresh_Button" element on "Modal_Transition_Popup" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" Then click on "Refresh_Button" element on "Modal_Transition_Popup" wizard @@ -349,21 +348,21 @@ Feature: Alerts Page Then verify "Logs" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard Then verify "Logs_Text_container" element visibility on "Modal_Transition_Popup" wizard Then verify "Logs_Refresh_Button" element visibility on "Modal_Transition_Popup" wizard - And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard - Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Data" + Then click on "Logs_Refresh_Button" element on "Modal_Transition_Popup" wizard + And wait load page + Then verify "Logs_Text_container" element visibility on "Modal_Transition_Popup" wizard And select "Pods" tab in "Tab_Selector" on "Modal_Transition_Popup" wizard And wait load page Then verify "Pods" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard - Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Pods_data" + Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Pods_data_Completion" @MLAlert @smoke - # TODO: Add data to the mock to check the following elements (existing alerts with endpoint type) Scenario: MLAlert007 - Check components on Endpoints alert detail pane on Alerts page Given open url And wait load page - And click on row root with value "cat-vs-dog-classification" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page And select "tab" with "Alerts" value in breadcrumbs menu And wait load page @@ -374,7 +373,6 @@ Feature: Alerts Page Then verify "Date_Picker_Filter_Dropdown" dropdown on "Alerts" wizard selected option value "Past 24 hours" When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Alerts" wizard And wait load page - # Add data to the mock to check the following elements Then verify "Alerts_Table" element visibility on "Alerts" wizard Then click on "Table_FilterBy_Button" element on "Alerts" wizard When select "Endpoint" option in "Entity_Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard @@ -385,7 +383,7 @@ Feature: Alerts Page When click on cell with row index 1 in "alertName" column in "Alerts_Table" table on "Alerts" wizard And wait load page Then verify "Header" element visibility on "Alerts_Endpoint_Info_Pane" wizard - Then "Header" element on "Alerts_Endpoint_Info_Pane" should contains "data-drift" value + Then "Header" element on "Alerts_Endpoint_Info_Pane" should contains "alert-name-uqbxb-proj-default" value Then verify "Cross_Close_Button" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then click on "Cross_Close_Button" element on "Alerts_Endpoint_Info_Pane" wizard Then verify "Header" element not exists on "Alerts_Endpoint_Info_Pane" wizard @@ -393,14 +391,14 @@ Feature: Alerts Page And wait load page Then verify "Header" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then verify "Overview_General_Headers" element visibility on "Alerts_Endpoint_Info_Pane" wizard - Then verify "Overview_General_Headers" on "Alerts_Endpoint_Info_Pane" wizard should contains "Alerts_Endpoint_Info_Pane"."Overview_General_Headers" + Then verify "Overview_General_Headers" on "Alerts_Endpoint_Info_Pane" wizard should contains "Alerts_Endpoint_Info_Pane"."Overview_General_Headers_Per_Project" Then verify "Overview_Trigger_Criteria" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then verify "Overview_Trigger_Criteria" on "Alerts_Endpoint_Info_Pane" wizard should contains "Alerts_Jobs_Info_Pane"."Overview_Trigger_Criteria_Headers" Then verify "Notifications_Header" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then verify "Notifications_Item" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then verify "Date_Picker_Filter_Dropdown" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then verify "Date_Picker_Filter_Dropdown" dropdown on "Alerts_Endpoint_Info_Pane" wizard selected option value "Past 24 hours" - Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Alerts_Endpoint_Info_Pane" wizard should contains "Dropdown_Options"."Date_Picker_Filter_Options" + Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Alerts_Endpoint_Info_Pane" wizard should contains "Dropdown_Options"."Date_Picker_Filter_Options_Endpoint" Then verify "Metrics_App_Name" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then verify "Metrics_Stats_Card" element visibility on "Alerts_Endpoint_Info_Pane" wizard Then click on "Cross_Close_Button" element on "Alerts_Endpoint_Info_Pane" wizard @@ -411,11 +409,10 @@ Feature: Alerts Page @MLAlert @smoke - # TODO: Add data to the mock to check the following elements (existing alerts with application type) Scenario: MLAlert008 - Check components on Application alert detail pane on Alerts page Given open url And wait load page - And click on row root with value "cat-vs-dog-classification" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page And select "tab" with "Alerts" value in breadcrumbs menu And wait load page @@ -426,7 +423,6 @@ Feature: Alerts Page Then verify "Date_Picker_Filter_Dropdown" dropdown on "Alerts" wizard selected option value "Past 24 hours" When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Alerts" wizard And wait load page - # Add data to the mock to check the following elements Then verify "Alerts_Table" element visibility on "Alerts" wizard Then click on "Table_FilterBy_Button" element on "Alerts" wizard When select "Application" option in "Entity_Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard @@ -445,7 +441,7 @@ Feature: Alerts Page And wait load page Then verify "Header" element visibility on "Alerts_Application_Info_Pane" wizard Then verify "Overview_General_Headers" element visibility on "Alerts_Application_Info_Pane" wizard - Then verify "Overview_General_Headers" on "Alerts_Application_Info_Pane" wizard should contains "Alerts_Application_Info_Pane"."Overview_General_Headers" + Then verify "Overview_General_Headers" on "Alerts_Application_Info_Pane" wizard should contains "Alerts_Application_Info_Pane"."Overview_General_Headers_Per_Project" Then verify "Overview_Trigger_Criteria" element visibility on "Alerts_Application_Info_Pane" wizard Then verify "Overview_Trigger_Criteria" on "Alerts_Application_Info_Pane" wizard should contains "Alerts_Jobs_Info_Pane"."Overview_Trigger_Criteria_Headers" Then verify "Notifications_Header" element visibility on "Alerts_Application_Info_Pane" wizard diff --git a/tests/features/alertsMonitoring.feature b/tests/features/alertsMonitoring.feature index 049ff554bc..10e1f89a38 100644 --- a/tests/features/alertsMonitoring.feature +++ b/tests/features/alertsMonitoring.feature @@ -256,7 +256,6 @@ Feature: Alerts Monitoring Page @MLAM @smoke - # TODO: Add data to the mock to check the following elements (existing job data for details popup) Scenario: MLAM006 - Check components in Job detail pop-up on Job alert detail pane Given open url And wait load page @@ -282,14 +281,29 @@ Feature: Alerts Monitoring Page Then verify "Overview_General_Headers" element visibility on "Alerts_Jobs_Info_Pane" wizard Then verify "Overview_General_Headers" on "Alerts_Jobs_Info_Pane" wizard should contains "Alerts_Jobs_Info_Pane"."Overview_General_Headers" Then verify "Job_Detail_PopUp_Link" element visibility on "Alerts_Jobs_Info_Pane" wizard + When select "Any time" option in "Date_Picker_Filter_Dropdown" filter dropdown on "Alerts_Monitoring" wizard + And wait load page + Then type value "obryv-default" to "Search_By_Name_Filter_Input" field on "Alerts_Monitoring" wizard + Then click on "Refresh_Button" element on "Alerts_Monitoring" wizard + And wait load page + Then value in "alertName" column with "text" in "Alerts_Table" on "Alerts_Monitoring" wizard should contains "alert-name-obryv-default" + And wait load page + Then verify "Alerts_Table" element visibility on "Alerts_Monitoring" wizard + Then value in "entityType" column with "tooltip" in "Alerts_Table" on "Alerts_Monitoring" wizard should contains "Job" + When click on cell with row index 1 in "alertName" column in "Alerts_Table" table on "Alerts_Monitoring" wizard + And wait load page + Then verify "Header" element visibility on "Alerts_Jobs_Info_Pane" wizard + Then "Header" element on "Alerts_Jobs_Info_Pane" should contains "alert-name-obryv-default" value + Then verify "Overview_General_Headers" element visibility on "Alerts_Jobs_Info_Pane" wizard + Then verify "Overview_General_Headers" on "Alerts_Jobs_Info_Pane" wizard should contains "Alerts_Jobs_Info_Pane"."Overview_General_Headers" + Then verify "Job_Detail_PopUp_Link" element visibility on "Alerts_Jobs_Info_Pane" wizard Then click on "Job_Detail_PopUp_Link" element on "Alerts_Jobs_Info_Pane" wizard - # Add data to the mock to check the following elements Then verify if "Modal_Transition_Popup" popup dialog appears Then verify "Title" element visibility on "Modal_Transition_Popup" wizard - Then "Title" element on "Modal_Transition_Popup" should contains "erann-test" value + Then "Title" element on "Modal_Transition_Popup" should contains "test-func-oyn-handler" value Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard Then verify "State_Icon" element visibility on "Modal_Transition_Popup" wizard - Then verify "State_Icon" element on "Modal_Transition_Popup" wizard should display hover tooltip "Jobs_Monitor_Tab_Info_Pane"."Error_State" + Then verify "State_Icon" element on "Modal_Transition_Popup" wizard should display hover tooltip "Jobs_Monitor_Tab_Info_Pane"."Error_State_With_Message" Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard Then verify "Refresh_Button" element on "Modal_Transition_Popup" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" Then click on "Refresh_Button" element on "Modal_Transition_Popup" wizard @@ -332,13 +346,14 @@ Feature: Alerts Monitoring Page Then verify "Logs" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard Then verify "Logs_Text_container" element visibility on "Modal_Transition_Popup" wizard Then verify "Logs_Refresh_Button" element visibility on "Modal_Transition_Popup" wizard - And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard - Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Data" + Then click on "Logs_Refresh_Button" element on "Modal_Transition_Popup" wizard + And wait load page + Then verify "Logs_Text_container" element visibility on "Modal_Transition_Popup" wizard And select "Pods" tab in "Tab_Selector" on "Modal_Transition_Popup" wizard And wait load page Then verify "Pods" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard - Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Pods_data" + Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Pods_data_Completion" @MLAM @smoke diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index d0b1c0809a..f81eca0ac9 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -182,6 +182,14 @@ export default { 'Timestamp:', 'Severity:' ], + Overview_General_Headers_Per_Project: [ + 'Endpoint ID:', + 'Application Name:', + 'Result Name:', + 'Type:', + 'Timestamp:', + 'Severity:' + ], Overview_Trigger_Criteria_Headers: ['Trigger criteria count:', 'Trigger criteria time period:'] }, Alerts_Application_Info_Pane: { @@ -192,6 +200,12 @@ export default { 'Timestamp:', 'Severity:' ], + Overview_General_Headers_Per_Project: [ + 'Application Name:', + 'Type:', + 'Timestamp:', + 'Severity:' + ], Overview_Trigger_Criteria_Headers: ['Trigger criteria count:', 'Trigger criteria time period:'] }, ML_Functions_Tab: { @@ -222,14 +236,14 @@ export default { 'Kind:', 'Code entry point:', 'Internal URL:', - 'Image:', + //'Image:', hidden due to ML-7988, ML-8014 'Application image:', 'Version tag:', 'Hash:', 'Internal port:', - 'Code origin:', + // 'Code origin:', hidden due to ML-7988, ML-8014 'Updated:', - 'Default handler:', + // 'Default handler:', hidden due to ML-7988, ML-8014 'Description:' ] }, @@ -589,6 +603,7 @@ export default { Jobs_Monitor_Tab_Info_Pane: { Pending_State: 'Pending', Error_State: 'Error', + Error_State_With_Message: 'Error. This function intentionally fails', Tab_List: ['Overview', 'Inputs', 'Artifacts', 'Results', 'Logs', 'Pods'], Overview_Headers: [ 'UID:', @@ -643,6 +658,7 @@ export default { Event_Type_Endpoint_Filter_Options: ['All', 'Data drift detected', 'Data drift suspected', 'Conc drift detected', 'Conc drift suspected', 'MM performance detected', 'MM performance suspected', 'System performance detected', 'System performance suspected', 'MM app anomaly detected', 'MM app anomaly suspected'], Event_Type_Job_Filter_Options: ['All', 'Job failed'], Event_Type_Application_Filter_Options: ['All', 'MM app failed'], + Endpoint_Mode_Filter_Options: ['All', 'Real-time', 'Batch'], Jobs_Status_Filter_Options: [ 'All', 'Aborted', @@ -779,7 +795,8 @@ export default { No_Documents_data: 'No data matches the filter: "Version tag: latest, Show best iteration only: true"', No_Files_data: 'No data matches the filter: "Version tag: latest, Labels: v3io_user=123, Show best iteration only: true"', No_Models_data: 'No data matches the filter: "Version tag: latest, Labels: MY-KEY, Show best iteration only: true"', - No_Pods_data: 'Pods not found, it is likely because Kubernetes removed these pods listing' + No_Pods_data: 'Pods not found, it is likely because Kubernetes removed these pods listing', + No_Pods_data_Completion: 'Pods not found, it is likely because Kubernetes removed these pods listing after their completion' }, Preview_Pop_Up: { Table_Header: ['Name', 'Path', 'Size', 'Updated'] diff --git a/tests/features/common/page-objects/interactive-popup.po.js b/tests/features/common/page-objects/interactive-popup.po.js index 888df3cb86..417d550bb6 100644 --- a/tests/features/common/page-objects/interactive-popup.po.js +++ b/tests/features/common/page-objects/interactive-popup.po.js @@ -818,8 +818,8 @@ export default { Content_Application_Log_Info: By.css('.item-info .table__item-logs:nth-of-type(1)'), Title_Function_Log_Info: By.css('.item-info > div > h3:nth-of-type(2)'), Content_Function_Log_Info: By.css('.item-info .table__item-logs:nth-of-type(2)'), - Logs_Text_container: By.css('.table__item .table__item-logs-content'), - Logs_Refresh_Button: By.css('.table__item .logs-refresh') + Logs_Text_container: By.css('#overlay_container .table__item .table__item-logs-content'), + Logs_Refresh_Button: By.css('#overlay_container .table__item .logs-refresh') }, modalWizardForm: { Title: By.css('.modal .modal__header-title'), @@ -1663,6 +1663,13 @@ export default { '.options-list [data-testid="select-option"]' ) ), + Mode_Filter_Dropdown: dropdownComponent( + generateDropdownGroup( + '#overlay_container [data-testid="me-mode-form-field-select"] [data-testid="select-header"]', + '.form-field__control', + '.options-list [data-testid="select-option"]' + ) + ), Entity_Type_Filter_Dropdown: dropdownComponent( generateDropdownGroup( '#overlay_container [data-testid="pop-up-dialog"] [data-testid="entity-type-form-field-select"]', diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index 08cdfb15ab..322ce07ea0 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -753,7 +753,7 @@ Feature: Jobs and workflows Then verify "Title" element visibility on "Modal_Transition_Popup" wizard Then "Title" element on "Modal_Transition_Popup" should contains "aggregate" value Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard - Then "Data_Status" element on "Modal_Transition_Popup" should contains "Nov 25, 2021, 05:20:00 PM" value + Then "Data_Status" element on "Modal_Transition_Popup" should contains "Nov 25, 2021, 03:20:00 PM" value Then verify "State_Icon" element visibility on "Modal_Transition_Popup" wizard Then verify "State_Icon" element on "Modal_Transition_Popup" wizard should display hover tooltip "ML_Function_Info_Pane"."Initialized_State" Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard @@ -1010,22 +1010,7 @@ Feature: Jobs and workflows Then verify if "Confirm_Popup" popup dialog appears Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard When click on "Cross_Cancel_Button" element on "Confirm_Popup" wizard - Then click on "Terminate_Button" element on "Workflows_Monitor_Tab" wizard And wait load page - Then verify if "Confirm_Popup" popup dialog appears - Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard - When click on "Delete_Button" element on "Confirm_Popup" wizard - And wait load page - Then verify if "Notification_Popup" popup dialog appears - Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" - Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard - Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard - Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is disabled - Then verify "Workflow_List_View_Table" element visibility on "Workflows_Monitor_Tab" wizard - Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard - Then "Terminate_Button" element on "Workflows_Monitor_Tab" should contains "Terminate" value - Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is enabled When click on cell with row index 1 in "name" column in "Workflow_List_View_Table" table on "Workflows_Monitor_Tab" wizard And wait load page Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard @@ -1046,6 +1031,8 @@ Feature: Jobs and workflows Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard Then "Delete_Button" element on "Confirm_Popup" should contains "Terminate" value When click on "Cancel_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is enabled Then click on "Terminate_Button" element on "Workflows_Monitor_Tab" wizard And wait load page Then verify if "Confirm_Popup" popup dialog appears @@ -1057,6 +1044,14 @@ Feature: Jobs and workflows Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + And wait load page + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is disabled + Then click on "Cross_Close_Button" element on "Jobs_Monitor_Tab_Info_Pane" wizard + And wait load page + Then verify "Workflow_List_View_Table" element visibility on "Workflows_Monitor_Tab" wizard + Then verify "Terminate_Button" element visibility on "Workflows_Monitor_Tab" wizard + Then "Terminate_Button" element on "Workflows_Monitor_Tab" should contains "Terminate" value + Then verify "Terminate_Button" element on "Workflows_Monitor_Tab" wizard is disabled @MLJW @passive diff --git a/tests/features/models.feature b/tests/features/models.feature index b431dc3374..5aff9bd407 100644 --- a/tests/features/models.feature +++ b/tests/features/models.feature @@ -74,6 +74,10 @@ Feature: Models Page Then verify "Table_FilterBy_Button" element on "Model_Endpoints" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" Then click on "Table_FilterBy_Button" element on "Model_Endpoints" wizard Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Mode_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Mode_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Mode_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Endpoint_Mode_Filter_Options" + And wait load page Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard Then verify "Apply_Button" element on "FilterBy_Popup" wizard is disabled Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard diff --git a/tests/features/monitoringApp.feature b/tests/features/monitoringApp.feature index e7be622978..5f0888de04 100644 --- a/tests/features/monitoringApp.feature +++ b/tests/features/monitoringApp.feature @@ -457,3 +457,100 @@ Feature: Monitoring app Page Then type value "qwe" to "Search_By_Endpoint_Filter_Input" field on "Application_Metrics" wizard And wait load page Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "0 endpoints found" value + + @MLMA + @smoke + Scenario: MLMA013 - Check redirection to Model Endpoints filtering by mode list + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When turn on demo mode with query params "false" + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Monitoring app" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And wait load page + Then verify "All_Applications_Title" element visibility on "Monitoring_App" wizard + Then "All_Applications_Title" element on "Monitoring_App" should contains "All Applications" value + Then verify "Endpoints_Stats_Title" element visibility on "Monitoring_App" wizard + Then "Endpoints_Stats_Title" element on "Monitoring_App" should contains "Endpoints" value + Then verify "Endpoints_Batch_SubTitle" element visibility on "Monitoring_App" wizard + Then "Endpoints_Batch_SubTitle" element on "Monitoring_App" should contains "Batch" value + Then verify "Endpoints_Batch_Counter" element visibility on "Monitoring_App" wizard + Then verify "Endpoints_RealTime_SubTitle" element visibility on "Monitoring_App" wizard + Then "Endpoints_RealTime_SubTitle" element on "Monitoring_App" should contains "Real-time" value + Then verify "Endpoints_RealTime_Counter" element visibility on "Monitoring_App" wizard + And wait load page + Then click on "Endpoints_Batch_Counter" element on "Monitoring_App" wizard + And wait load page + Then verify redirection to "projects/default/models/model-endpoints?me-mode=batch" + Then verify breadcrumbs "tab" label should be equal "Models" value + Then verify "Models_Tab_Selector" on "Models" wizard should contains "Models"."Tab_List" + Then verify "Model Endpoints" tab is active in "Models_Tab_Selector" on "Models" wizard + Then verify "Table_FilterBy_Button" element visibility on "Model_Endpoints" wizard + Then verify "Table_FilterBy_Button" element on "Model_Endpoints" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" + Then click on "Table_FilterBy_Button" element on "Model_Endpoints" wizard + Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Mode_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Mode_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Batch" + Then verify "Mode_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Endpoint_Mode_Filter_Options" + And wait load page + Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Apply_Button" element on "FilterBy_Popup" wizard is disabled + Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Clear_Button" element on "FilterBy_Popup" wizard is enabled + Then navigate back + And wait load page + Then verify redirection to "projects/default/monitoring-app" + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + Then verify "Endpoints_Stats_Title" element visibility on "Monitoring_App" wizard + Then verify "Endpoints_RealTime_SubTitle" element visibility on "Monitoring_App" wizard + Then "Endpoints_RealTime_SubTitle" element on "Monitoring_App" should contains "Real-time" value + Then verify "Endpoints_RealTime_Counter" element visibility on "Monitoring_App" wizard + And wait load page + Then click on "Endpoints_RealTime_Counter" element on "Monitoring_App" wizard + And wait load page + Then verify redirection to "projects/default/models/model-endpoints?me-mode=realTime" + Then verify breadcrumbs "tab" label should be equal "Models" value + Then verify "Models_Tab_Selector" on "Models" wizard should contains "Models"."Tab_List" + Then verify "Model Endpoints" tab is active in "Models_Tab_Selector" on "Models" wizard + Then verify "Table_FilterBy_Button" element visibility on "Model_Endpoints" wizard + Then verify "Table_FilterBy_Button" element on "Model_Endpoints" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" + Then click on "Table_FilterBy_Button" element on "Model_Endpoints" wizard + Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Mode_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Mode_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Real-time" + Then verify "Mode_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Endpoint_Mode_Filter_Options" + And wait load page + Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Apply_Button" element on "FilterBy_Popup" wizard is disabled + Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Clear_Button" element on "FilterBy_Popup" wizard is enabled + Then navigate back + And wait load page + Then verify redirection to "projects/default/monitoring-app" + Then verify breadcrumbs "tab" label should be equal "Monitoring app" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Models" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Models" value + And wait load page + And select "Model Endpoints" tab in "Models_Tab_Selector" on "Models" wizard + And wait load page + Then verify "Model Endpoints" tab is active in "Models_Tab_Selector" on "Models" wizard + Then verify "Table_FilterBy_Button" element visibility on "Model_Endpoints" wizard + Then verify "Table_FilterBy_Button" element on "Model_Endpoints" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" + Then click on "Table_FilterBy_Button" element on "Model_Endpoints" wizard + Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Mode_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Mode_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Mode_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Endpoint_Mode_Filter_Options" + And wait load page + Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Apply_Button" element on "FilterBy_Popup" wizard is disabled + Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard + Then verify "Clear_Button" element on "FilterBy_Popup" wizard is disabled diff --git a/tests/features/projectMonitoring.feature b/tests/features/projectMonitoring.feature index 63bbf4da9d..331739397d 100644 --- a/tests/features/projectMonitoring.feature +++ b/tests/features/projectMonitoring.feature @@ -15,7 +15,7 @@ Feature: Project Monitoring Page Then verify "Project_Name" element visibility on "Project" wizard Then "Project_Name" element on "Project" should contains "default" value Then verify "Created_Details" element visibility on "Project" wizard - Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 17:21:14 PM" value + Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 15:21:14 PM" value Then verify "Owner_Details" element visibility on "Project" wizard Then "Owner_Details" element on "Project" should contains "Owner: igz_nobody" value Then verify "Info_Baner_Icon" element visibility on "Project" wizard @@ -114,7 +114,7 @@ Feature: Project Monitoring Page Then verify "Project_Name" element visibility on "Project" wizard Then "Project_Name" element on "Project" should contains "default" value Then verify "Created_Details" element visibility on "Project" wizard - Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 17:21:14 PM" value + Then "Created_Details" element on "Project" should contains "Created: 08/29/2021, 15:21:14 PM" value Then verify "Owner_Details" element visibility on "Project" wizard Then "Owner_Details" element on "Project" should contains "Owner: igz_nobody" value Then verify "Info_Baner_Icon" element visibility on "Project" wizard diff --git a/tests/features/projectsPage.feature b/tests/features/projectsPage.feature index c91c72e097..046c4ef928 100644 --- a/tests/features/projectsPage.feature +++ b/tests/features/projectsPage.feature @@ -403,8 +403,8 @@ Feature: Projects Page Then verify "Counter_Running_Status_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Running_Status_Subtitle" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then "Counter_Running_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "In process" value - Then verify "Counter_In_Process_Status_Icon" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then verify "Counter_In_Process_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" + Then verify "Counter_Running_Status_Icon" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard + Then verify "Counter_Running_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" Then verify "Counter_Failed_Status_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then verify "Counter_Failed_Status_Subtitle" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then "Counter_Failed_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "Failed" value @@ -414,7 +414,7 @@ Feature: Projects Page Then verify "Counter_Completed_Status_Subtitle" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then "Counter_Completed_Status_Subtitle" element in "Monitoring_Jobs_Box" on "Projects" should contains "Succeeded" value Then verify "Counter_Completed_Status_Icon" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard - Then verify "Counter_In_Process_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" + Then verify "Counter_Running_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."In_Process_Jobs" Then verify "Counter_Completed_Status_Icon" element in "Monitoring_Jobs_Box" on "Projects" wizard should display hover tooltip "Common_Tooltips"."Succeeded" Then "Counter_Completed_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" should contains "1" value When click on "Counter_Running_Status_Number" element in "Monitoring_Jobs_Box" on "Projects" wizard diff --git a/tests/mockServer/data/alerts.json b/tests/mockServer/data/alerts.json index c59b57c0c8..370caa6124 100644 --- a/tests/mockServer/data/alerts.json +++ b/tests/mockServer/data/alerts.json @@ -55,10 +55,10 @@ { "id": 10, "name": "mm-app-failure", - "project": "kate-project-mm", + "project": "default", "severity": "medium", "activation_time": "2024-12-17T09:52:19.580000+00:00", - "entity_id": "kate-project-mm_myApp", + "entity_id": "default-mm_myApp", "entity_kind": "model-monitoring-application", "criteria": { "count": 1, @@ -317,7 +317,7 @@ "name": "alert-name-uqbxb-proj-default", "project": "default", "severity": "high", - "activation_time": "2025-05-31T15:50:55.190000+00:00", + "activation_time": "2025-09-22T15:50:55.190000+00:00", "entity_id": "a7c95783e6a726a1a233e581ea898ba33fa7e342.rujmfi.result.data_drift_test", "entity_kind": "model-endpoint-result", "criteria": { @@ -343,7 +343,7 @@ "name": "alert-name-jukmn-proj-default", "project": "default", "severity": "high", - "activation_time": "2025-05-31T15:50:54.207000+00:00", + "activation_time": "2025-09-22T15:50:54.207000+00:00", "entity_id": "a7c95783e6a726a1a233e581ea898ba33fa7e342.hskoyl.result.data_drift_test", "entity_kind": "model-endpoint-result", "criteria": { @@ -369,7 +369,7 @@ "name": "alert-name-uqbxb-proj-default", "project": "default", "severity": "high", - "activation_time": "2025-05-31T15:48:57.907000+00:00", + "activation_time": "2025-09-22T15:48:57.907000+00:00", "entity_id": "a7c95783e6a726a1a233e581ea898ba33fa7e342.rujmfi.result.data_drift_test", "entity_kind": "model-endpoint-result", "criteria": { @@ -395,7 +395,7 @@ "name": "alert-name-jukmn-proj-default", "project": "default", "severity": "high", - "activation_time": "2025-05-31T15:48:56.440000+00:00", + "activation_time": "2025-09-22T15:48:56.440000+00:00", "entity_id": "a7c95783e6a726a1a233e581ea898ba33fa7e342.hskoyl.result.data_drift_test", "entity_kind": "model-endpoint-result", "criteria": { @@ -415,6 +415,40 @@ } ], "reset_time": "2025-03-05T15:48:56.440000+00:00" + }, + { + "id": 3395, + "name": "alert-name-obryv-default", + "project": "default", + "severity": "low", + "activation_time": "2025-09-04T12:46:17.816000+00:00", + "entity_id": "test-func-oyn-handler.98418b756c4b4307be9a3e7c39e66f21", + "entity_kind": "job", + "criteria": { + "count": 1, + "period": null + }, + "event_kind": "failed", + "number_of_events": 1, + "notifications": [ + { + "kind": "git", + "err": "All git notifications failed. Errors: Failed commenting on PR: {\r\n \"message\": \"Not Found\",\r\n \"documentation_url\": \"https://docs.github.com/rest\",\r\n \"status\": \"404\"\r\n}", + "summary": { + "failed": 1, + "succeeded": 0 + } + }, + { + "kind": "webhook", + "err": "All webhook notifications failed. Errors: 404, message='Not Found', url='https://webhook.site/57696af5-3edc-447f-a714-628275f2ed89'", + "summary": { + "failed": 1, + "succeeded": 0 + } + } + ], + "reset_time": "2025-09-04T12:46:17.816000+00:00" } ], "pagination": { diff --git a/tests/mockServer/data/funcs.json b/tests/mockServer/data/funcs.json index 1763514d87..39f903838e 100644 --- a/tests/mockServer/data/funcs.json +++ b/tests/mockServer/data/funcs.json @@ -30309,6 +30309,98 @@ "updated": "2024-10-08T14:06:44.563424+00:00" }, "status": {} - } + }, + { + "metadata": { + "hash": "93124a9c66fcefbe27b24109a729691f8dbea5c0", + "credentials": { + "access_key": "$ref:mlrun-auth-secrets.b262111796186bb2718523bd3377fc4871b1e6c702992140099210de" + }, + "updated": "2025-09-04T12:45:44.659000+00:00", + "project": "default", + "tag": "latest", + "name": "test-func-oyn", + "uid": "93124a9c66fcefbe27b24109a729691f8dbea5c0" + }, + "verbose": false, + "spec": { + "build": { + "code_origin": "https://github.com/mlrun/test-notebooks-ui#77469ce3b66b43562f6dfff0be3f620fd1f231bd:fnxot.py", + "origin_filename": "fnxot.py", + "functionSourceCode": "ZGVmIGhhbmRsZXIoKToKICAgIHJhaXNlIEV4Y2VwdGlvbigiVGhpcyBmdW5jdGlvbiBpbnRlbnRpb25hbGx5IGZhaWxzIikKICAgICAgICAgICAgCg==" + }, + "state_thresholds": { + "pending_scheduled": "1h", + "pending_not_scheduled": "-1", + "image_pull_backoff": "1h", + "executing": "24h" + }, + "default_handler": "handler", + "entry_points": { + "handler": { + "has_kwargs": false, + "has_varargs": false, + "doc": "", + "lineno": 1, + "name": "handler" + } + }, + "image": "mlrun/mlrun", + "preemption_mode": "prevent", + "description": "", + "command": "", + "disable_auto_mount": true, + "priority_class_name": "igz-workload-medium", + "tolerations": null, + "env": [ + { + "name": "V3IO_API", + "value": "v3io-webapi.default-tenant.svc:8081" + }, + { + "name": "V3IO_USERNAME", + "value": "normal-user" + }, + { + "name": "V3IO_ACCESS_KEY", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.9a60a83c83d08d712a722becb0d2c7bc308be38d59c4a904c6d89696" + } + } + }, + { + "name": "V3IO_FRAMESD", + "value": "framesd:8081" + }, + { + "name": "MLRUN_AUTH_SESSION", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.b262111796186bb2718523bd3377fc4871b1e6c702992140099210de" + } + } + } + ], + "affinity": null, + "node_selector": {}, + "resources": { + "requests": { + "memory": "1Mi", + "cpu": "25m" + }, + "limits": { + "memory": "20Gi", + "cpu": "2" + } + } + }, + "status": { + "state": null + }, + "kind": "job" + } ] } diff --git a/tests/mockServer/data/logs.json b/tests/mockServer/data/logs.json index 90dd701a6e..59e688a76a 100644 --- a/tests/mockServer/data/logs.json +++ b/tests/mockServer/data/logs.json @@ -2074,5 +2074,24 @@ { "uid": "c236200fde53460784065bdf65e4ede8", "log": "Traceback (most recent call last):\n File \"/usr/local/bin/mlrun\", line 8, in \n sys.exit(main())\n File \"/usr/local/lib/python3.7/site-packages/click/core.py\", line 829, in __call__\n return self.main(*args, **kwargs)\n File \"/usr/local/lib/python3.7/site-packages/click/core.py\", line 782, in main\n rv = self.invoke(ctx)\n File \"/usr/local/lib/python3.7/site-packages/click/core.py\", line 1259, in invoke\n return _process_result(sub_ctx.command.invoke(sub_ctx))\n File \"/usr/local/lib/python3.7/site-packages/click/core.py\", line 1066, in invoke\n return ctx.invoke(self.callback, **ctx.params)\n File \"/usr/local/lib/python3.7/site-packages/click/core.py\", line 610, in invoke\n return callback(*args, **kwargs)\n File \"/usr/local/lib/python3.7/site-packages/mlrun/__main__.py\", line 333, in run\n resp = fn.run(runobj, watch=watch, schedule=schedule, local=local)\n File \"/usr/local/lib/python3.7/site-packages/mlrun/runtimes/base.py\", line 483, in run\n resp = self._run(runspec, execution)\n File \"/usr/local/lib/python3.7/site-packages/mlrun/runtimes/local.py\", line 232, in _run\n mod, fn = self._get_handler(handler)\n File \"/usr/local/lib/python3.7/site-packages/mlrun/runtimes/local.py\", line 185, in _get_handler\n return load_module(self.spec.command, handler)\n File \"/usr/local/lib/python3.7/site-packages/mlrun/runtimes/local.py\", line 308, in load_module\n spec.loader.exec_module(mod)\n File \"\", line 728, in exec_module\n File \"\", line 219, in _call_with_frames_removed\n File \"main.py\", line 4, in \n import pyhive\nModuleNotFoundError: No module named 'pyhive'\n" + }, + { + "uid": "98418b756c4b4307be9a3e7c39e66f21", + "log": [ + "> 2025-09-04 12:45:48,842 [error] Execution error, Traceback (most recent call last):", + " File \"/opt/conda/lib/python3.9/site-packages/mlrun/runtimes/local.py\", line 501, in exec_from_params", + " val = mlrun.handler(", + " File \"/opt/conda/lib/python3.9/site-packages/mlrun/package/__init__.py\", line 137, in wrapper", + " func_outputs = func(*args, **kwargs)", + " File \"fnxot.py\", line 2, in handler", + " raise Exception(\"This function intentionally fails\")", + "Exception: This function intentionally fails", + "> 2025-09-04 12:45:48,886 [error] Exec error - This function intentionally fails", + "This function intentionally fails", + "> 2025-09-04 12:45:48,933 [info] To track results use the CLI: {\"info_cmd\":\"mlrun get run 98418b756c4b4307be9a3e7c39e66f21 -p mm-alerts-proj\",\"logs_cmd\":\"mlrun logs 98418b756c4b4307be9a3e7c39e66f21 -p mm-alerts-proj\"}", + "> 2025-09-04 12:45:48,933 [info] Or click for UI: {\"ui_url\":\"https://dashboard.default-tenant.app.vmdev82.lab.iguazeng.com/mlprojects/mm-alerts-proj/jobs/monitor-jobs/test-func-oyn-handler/98418b756c4b4307be9a3e7c39e66f21/overview\"}", + "> 2025-09-04 12:45:48,934 [info] Run execution finished: {\"name\":\"test-func-oyn-handler\",\"status\":\"error\"}", + "Runtime error: This function intentionally fails" + ] } ] diff --git a/tests/mockServer/data/run.json b/tests/mockServer/data/run.json index d4f2b453da..c20282b9e3 100644 --- a/tests/mockServer/data/run.json +++ b/tests/mockServer/data/run.json @@ -71547,6 +71547,58 @@ "status_text": "aborted", "retry_count": 0 } + }, + { + "kind": "run", + "metadata": { + "name": "test-func-oyn-handler", + "uid": "98418b756c4b4307be9a3e7c39e66f21", + "iteration": 0, + "project": "default", + "labels": { + "v3io_user": "normal-user", + "kind": "job", + "owner": "normal-user", + "mlrun/client_version": "1.10.0-rc23", + "mlrun/client_python_version": "3.9.18", + "host": "test-func-oyn-handler-h9xjm" + }, + "annotations": {} + }, + "spec": { + "function": "default/test-func-oyn@93124a9c66fcefbe27b24109a729691f8dbea5c0", + "log_level": "info", + "parameters": {}, + "handler": "handler", + "outputs": [], + "output_path": "v3io:///projects/mm-alerts-proj/artifacts", + "inputs": {}, + "notifications": [], + "state_thresholds": { + "pending_scheduled": "1h", + "pending_not_scheduled": "-1", + "image_pull_backoff": "1h", + "executing": "24h" + }, + "node_selector": {}, + "tolerations": {}, + "affinity": {}, + "retry": {}, + "hyperparams": {}, + "hyper_param_options": {}, + "data_stores": [] + }, + "status": { + "results": {}, + "start_time": "2025-09-04T12:45:48.586000+00:00", + "last_update": "2025-09-04T12:45:48.925000+00:00", + "retry_count": null, + "retries": [], + "state": "error", + "artifact_uris": {}, + "error": "This function intentionally fails", + "end_time": "2025-09-04T12:45:48.870872+00:00" + } } ] -} \ No newline at end of file +} diff --git a/tests/mockServer/data/runs.json b/tests/mockServer/data/runs.json index 2f89e038f7..c88fcb93b7 100644 --- a/tests/mockServer/data/runs.json +++ b/tests/mockServer/data/runs.json @@ -71462,6 +71462,58 @@ "status_text": "aborted", "retry_count": 2 } + }, + { + "kind": "run", + "metadata": { + "name": "test-func-oyn-handler", + "uid": "98418b756c4b4307be9a3e7c39e66f21", + "iteration": 0, + "project": "default", + "labels": { + "v3io_user": "normal-user", + "kind": "job", + "owner": "normal-user", + "mlrun/client_version": "1.10.0-rc23", + "mlrun/client_python_version": "3.9.18", + "host": "test-func-oyn-handler-h9xjm" + }, + "annotations": {} + }, + "spec": { + "function": "default/test-func-oyn@93124a9c66fcefbe27b24109a729691f8dbea5c0", + "log_level": "info", + "parameters": {}, + "handler": "handler", + "outputs": [], + "output_path": "v3io:///projects/mm-alerts-proj/artifacts", + "inputs": {}, + "notifications": [], + "state_thresholds": { + "pending_scheduled": "1h", + "pending_not_scheduled": "-1", + "image_pull_backoff": "1h", + "executing": "24h" + }, + "node_selector": {}, + "tolerations": {}, + "affinity": {}, + "retry": {}, + "hyperparams": {}, + "hyper_param_options": {}, + "data_stores": [] + }, + "status": { + "results": {}, + "start_time": "2025-09-04T12:45:48.586000+00:00", + "last_update": "2025-09-04T12:45:48.925000+00:00", + "retry_count": null, + "retries": [], + "state": "error", + "artifact_uris": {}, + "error": "This function intentionally fails", + "end_time": "2025-09-04T12:45:48.870872+00:00" + } } ] -} \ No newline at end of file +} diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 5eb453cd07..9c3e8d1b30 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -2959,7 +2959,7 @@ app.get( getMonitoringApplicationData ) app.get( - `${mlrunAPIIngress}/projects/:project/model-endpoints/drift-over-time`, + `${mlrunAPIIngress}/projects/:project/model-monitoring/drift-over-time`, getMonitoringApplicationDrift ) From af5256d54cef8e587dc70ea92e0f4c06929a19ea Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 6 Oct 2025 22:34:57 +0300 Subject: [PATCH 171/228] Fix [LLM Prompts] Dot in the search highlights each letter (#3454) --- src/common/SearchNavigator/SearchNavigator.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/SearchNavigator/SearchNavigator.jsx b/src/common/SearchNavigator/SearchNavigator.jsx index b2cde57004..b0107f0f68 100644 --- a/src/common/SearchNavigator/SearchNavigator.jsx +++ b/src/common/SearchNavigator/SearchNavigator.jsx @@ -56,7 +56,7 @@ const SearchNavigator = ({ promptTemplate, setSearchResult, searchOnChange = nul return clearResults() } - const regex = new RegExp(`(${value})`, 'gi') + const regex = new RegExp(`(${value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi') const highlighted = highlightMatches(promptTemplate, regex, 0) const jsxMatchCount = countMatchesInTemplate(highlighted, regex) From 90b017ed25df99b551d5d835780177b683c89eb3 Mon Sep 17 00:00:00 2001 From: "Taras.Hlukhovetskyi" Date: Thu, 4 Sep 2025 17:50:30 +0300 Subject: [PATCH 172/228] WIP --- .stylelintrc.json | 29 +++++++++++++++++++++++++++-- package.json | 10 ++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/.stylelintrc.json b/.stylelintrc.json index ddee2a574c..6062967378 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,10 +1,35 @@ { - "extends": ["stylelint-config-standard", "stylelint-config-rational-order"], + "extends": ["stylelint-config-standard", "stylelint-config-standard-scss", "stylelint-config-rational-order"], "plugins": [ "stylelint-scss" ], "rules": { "at-rule-no-unknown": null, - "scss/at-rule-no-unknown": true + "scss/at-rule-no-unknown": true, + "selector-class-pattern": [ + "^[a-z0-9]+(?:-[a-z0-9]+)*(?:__(?:[a-z0-9]+(?:-[a-z0-9]+)*))*(?:_(?:[a-z0-9]+(?:-[a-z0-9]+)*)(?:_[a-z0-9]+(?:-[a-z0-9]+)*)?)?$", + { + "resolveNestedSelectors": true, + "message": "Expected kebab-case or BEM: block-name, block-name__elem-name(__sub-elem…), block-name_mod-name[_mod-val], block-name__elem-name_mod-name[_mod-val]" + } + ], + "scss/at-mixin-pattern": [ + "^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*|[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*)$", + { + "message": "Expected mixin name to be kebab-case (my-mixin) or camelCase (myMixin)" + } + ], + "custom-property-pattern": [ + "^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*|[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*)$", + { + "message": "Expected variable name to be kebab-case (my-variable) or camelCase (myVariable)" + } + ], + "scss/dollar-variable-pattern": [ + "^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*|[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*)$", + { + "message": "Expected variable name to be kebab-case (my-variable) or camelCase (myVariable)" + } + ] } } diff --git a/package.json b/package.json index 6545c0e419..996d09ea57 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "start": "vite", "build": "vite build", "lint": "eslint .", + "stylelint": "stylelint '**/*.{css,scss}'", "preview": "vite preview", "preinstall": "npx force-resolutions", "test:coverage": "npm run test -- --coverage --watchAll=false", @@ -140,11 +141,12 @@ "sass-loader": "^12.3.2", "selenium-webdriver": "^4.35.0", "source-map-loader": "^5.0.0", - "stylelint": "^13.3.3", + "stylelint": "^16.21.0", "stylelint-config-rational-order": "^0.1.2", - "stylelint-config-standard": "^20.0.0", - "stylelint-order": "^4.0.0", - "stylelint-scss": "^3.17.2", + "stylelint-config-standard": "^38.0.0", + "stylelint-config-standard-scss": "^15.0.1", + "stylelint-order": "^7.0.0", + "stylelint-scss": "^6.12.1", "url-loader": "4.1.1", "vite": "^6.2.0", "vite-plugin-commonjs": "^0.10.4", From 693bb2f7c8869a08c073515e93b6c56f17c82ff4 Mon Sep 17 00:00:00 2001 From: "Taras.Hlukhovetskyi" Date: Fri, 5 Sep 2025 13:06:06 +0300 Subject: [PATCH 173/228] Impl [UI] update "stylelint' libraries --- .stylelintrc.json | 5 ++++ package.json | 2 +- src/common/ChipInput/chipInput.scss | 4 +-- src/common/CodeBlock/codeBlock.scss | 2 +- src/common/Combobox/combobox.scss | 10 +++---- src/common/Input/input.scss | 4 +-- src/common/NoData/noData.scss | 2 +- src/common/Notifications/notifications.scss | 2 +- src/common/Pagination/pagination.scss | 26 +++++++++---------- src/common/ReactFlow/mlReactFlow.scss | 16 ++++++------ src/common/Search/search.scss | 3 ++- .../SearchNavigator/searchNavigator.scss | 8 +++--- src/common/SplitButton/splitButton.scss | 2 +- .../artifactInfoSources.scss | 2 +- .../ArtifactsPreview/artifactsPreview.scss | 2 +- .../artifactsPreviewController.scss | 8 +++--- src/components/DetailsInfo/detailsInfo.scss | 4 +-- .../DetailsMetrics/DetailsMetrics.scss | 2 +- .../detailsRequestedFeatures.scss | 2 +- .../DetailsResults/detailsResults.scss | 2 +- .../DetailsStatistics/detailsStatistics.scss | 2 +- .../FeatureSetsPanel/featureSetsPanel.scss | 1 - .../FilterMenuModal/filterMenuModal.scss | 14 +++++----- .../FunctionsPanel/functionsPanel.scss | 1 - .../JobWizardAdvanced/jobWizardAdvanced.scss | 2 +- .../jobWizardFunctionSelection.scss | 2 +- .../jobWizardHyperparametersStrategy.scss | 10 +++---- src/components/ModelsPage/modelsPage.scss | 4 +-- .../monitoringApplication.scss | 2 +- src/components/Pipeline/pipeline.scss | 2 +- .../Project/ProjectAction/ProjectAction.scss | 10 +++---- .../ProjectOverview/ProjectOverview.scss | 18 ++++++------- .../ProjectSettings/projectSettings.scss | 2 +- src/components/Workflow/workflow.scss | 10 ++++--- .../AlertsTableRow/AlertsTableRow.scss | 2 +- .../breadcrumbsDropdown.scss | 4 +-- .../createJobCardTemplate.scss | 2 +- .../enviromnetVariables.scss | 2 +- .../formResourcesUnits.scss | 2 +- .../FormVolumesRow/formVolumeRow.scss | 2 +- .../functionCardTemplate.scss | 16 ++++++------ .../functionsPanelCode.scss | 2 +- .../jobsMonitoringStatsCard.scss | 4 +-- src/elements/MembersPopUp/membersPopUp.scss | 4 +-- .../MethodDescription/methodDescription.scss | 2 +- src/elements/NavbarLink/NavbarLink.scss | 6 ++--- .../projectSettingsGeneral.scss | 2 +- src/elements/TableTop/tableTop.scss | 2 +- src/layout/Header/header.scss | 11 ++++---- src/layout/Navbar/Navbar.scss | 16 ++++++------ src/layout/Page/Page.scss | 3 ++- src/scss/main.scss | 2 +- 52 files changed, 139 insertions(+), 133 deletions(-) diff --git a/.stylelintrc.json b/.stylelintrc.json index 6062967378..6b6282220c 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -5,7 +5,12 @@ ], "rules": { "at-rule-no-unknown": null, + "selector-no-vendor-prefix": null, + "scss/at-mixin-argumentless-call-parentheses": null, + "scss/dollar-variable-empty-line-before": null, "scss/at-rule-no-unknown": true, + "media-feature-range-notation": null, + "property-no-vendor-prefix": null, "selector-class-pattern": [ "^[a-z0-9]+(?:-[a-z0-9]+)*(?:__(?:[a-z0-9]+(?:-[a-z0-9]+)*))*(?:_(?:[a-z0-9]+(?:-[a-z0-9]+)*)(?:_[a-z0-9]+(?:-[a-z0-9]+)*)?)?$", { diff --git a/package.json b/package.json index 996d09ea57..0d0d8435e7 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "start": "vite", "build": "vite build", "lint": "eslint .", - "stylelint": "stylelint '**/*.{css,scss}'", + "stylelint": "stylelint '**/*.scss' --fix", "preview": "vite preview", "preinstall": "npx force-resolutions", "test:coverage": "npm run test -- --coverage --watchAll=false", diff --git a/src/common/ChipInput/chipInput.scss b/src/common/ChipInput/chipInput.scss index 564960b6b2..b467c79301 100644 --- a/src/common/ChipInput/chipInput.scss +++ b/src/common/ChipInput/chipInput.scss @@ -19,11 +19,11 @@ left: 0; z-index: 5; width: 100%; + max-height: 200px; + overflow-y: auto; background-color: colors.$white; border: borders.$primaryBorder; border-radius: variables.$mainBorderRadius; - max-height: 200px; - overflow-y: auto; .suggestion-row { display: flex; diff --git a/src/common/CodeBlock/codeBlock.scss b/src/common/CodeBlock/codeBlock.scss index 20f43fb612..2595b8e4d3 100644 --- a/src/common/CodeBlock/codeBlock.scss +++ b/src/common/CodeBlock/codeBlock.scss @@ -5,10 +5,10 @@ .code-block { width: 100%; height: 200px; + padding: 18px 16px; overflow: auto; border: borders.$primaryBorder; border-radius: variables.$mainBorderRadius; - padding: 18px 16px; &__label { margin-bottom: 5px; diff --git a/src/common/Combobox/combobox.scss b/src/common/Combobox/combobox.scss index c5540b2cc9..48622ec1c2 100644 --- a/src/common/Combobox/combobox.scss +++ b/src/common/Combobox/combobox.scss @@ -12,8 +12,8 @@ border-radius: 4px; &_disabled { - cursor: not-allowed; border-color: colors.$spunPearl; + cursor: not-allowed; } &_invalid { @@ -22,10 +22,10 @@ &-list { min-width: 140px; - margin: 0; - list-style-type: none; max-height: 300px; + margin: 0; overflow: auto; + list-style-type: none; &__option { padding: 8px 15px; @@ -90,8 +90,8 @@ top: 100%; z-index: 5; display: none; - margin-top: 5px; max-width: 220px; + margin-top: 5px; background-color: colors.$white; box-shadow: shadows.$previewBoxShadow; @@ -167,8 +167,8 @@ } &:disabled { - background-color: transparent; color: colors.$spunPearl; + background-color: transparent; } } diff --git a/src/common/Input/input.scss b/src/common/Input/input.scss index b167982abf..85380f874e 100644 --- a/src/common/Input/input.scss +++ b/src/common/Input/input.scss @@ -50,10 +50,10 @@ } &__warning { - z-index: 2; position: absolute; top: 50%; right: 10px; + z-index: 2; display: block; transform: translateY(-45%); cursor: pointer; @@ -139,8 +139,8 @@ } &-mandatory { - color: colors.$amaranth; margin-left: 2px; + color: colors.$amaranth; &_disabled { color: colors.$spunPearl; diff --git a/src/common/NoData/noData.scss b/src/common/NoData/noData.scss index 489c58fafc..27c8a6623e 100644 --- a/src/common/NoData/noData.scss +++ b/src/common/NoData/noData.scss @@ -6,6 +6,6 @@ width: 100%; height: 100%; min-height: 150px; - word-break: break-word; text-align: center; + word-break: break-word; } diff --git a/src/common/Notifications/notifications.scss b/src/common/Notifications/notifications.scss index 33858b5642..592ea52400 100644 --- a/src/common/Notifications/notifications.scss +++ b/src/common/Notifications/notifications.scss @@ -1,10 +1,10 @@ .notifications-wrapper { position: absolute; right: 1.5em; - margin-left: 1.5em; bottom: 1em; display: flex; flex: 1 1; flex-direction: column; max-height: 90vh; + margin-left: 1.5em; } diff --git a/src/common/Pagination/pagination.scss b/src/common/Pagination/pagination.scss index 69966f57cb..dfbf2e1a40 100644 --- a/src/common/Pagination/pagination.scss +++ b/src/common/Pagination/pagination.scss @@ -2,11 +2,11 @@ @use 'igz-controls/scss/variables'; .pagination { + z-index: 1; display: flex; - justify-content: space-between; align-items: center; + justify-content: space-between; padding: 10px 4px 4px; - z-index: 1; .pagination-items-count, .pagination-items-selector { @@ -19,8 +19,8 @@ } .pagination-navigation { - flex-grow: 1; display: flex; + flex-grow: 1; justify-content: center; } @@ -30,18 +30,18 @@ } .pagination-btn { - color: colors.$primary; - cursor: default; - box-sizing: border-box; display: flex; justify-content: center; - border: none; - padding: 4px 5px; + box-sizing: border-box; margin: 0 2px; - font-size: 14px; + padding: 4px 5px; + color: colors.$primary; font-weight: normal; + font-size: 14px; + border: none; + cursor: default; - &:hover:not(.pagination-btn_active):not(:disabled) { + &:hover:not(.pagination-btn_active, :disabled) { cursor: pointer; } @@ -56,10 +56,10 @@ } .pagination-page-number { - padding: 2px 3px; box-sizing: content-box; - border-bottom: 2px solid transparent; + padding: 2px 3px; border-top: 2px solid transparent; + border-bottom: 2px solid transparent; } &.pagination-page-btn { @@ -71,8 +71,8 @@ } &.pagination-dots { - cursor: default; display: inline-flex; + cursor: default; } } diff --git a/src/common/ReactFlow/mlReactFlow.scss b/src/common/ReactFlow/mlReactFlow.scss index 3d344c919d..356ac7ef42 100644 --- a/src/common/ReactFlow/mlReactFlow.scss +++ b/src/common/ReactFlow/mlReactFlow.scss @@ -4,19 +4,19 @@ @mixin inputNode { color: colors.$white; background-color: colors.$hotPink; - fill: colors.$hotPink; border-color: colors.$hotPink; - stroke: colors.$hotPink; box-shadow: 0 3px 14px rgba(colors.$hotPink, 0.34); + fill: colors.$hotPink; + stroke: colors.$hotPink; } @mixin outputNode { color: colors.$white; background-color: colors.$malibu; - fill: colors.$malibu; border-color: colors.$malibu; - stroke: colors.$malibu; box-shadow: 0 3px 14px rgba(colors.$malibu, 0.5); + fill: colors.$malibu; + stroke: colors.$malibu; } @mixin primaryNode { @@ -80,20 +80,20 @@ @mixin selectedNode { &.selected { border-color: colors.$brightTurquoise; - stroke: colors.$brightTurquoise; box-shadow: 0 4px 20px rgba(colors.$brightTurquoise, 0.5); + stroke: colors.$brightTurquoise; &.status-error, &.status-failed { border-color: colors.$burntSienna; - stroke: colors.$burntSienna; box-shadow: 0 4px 20px rgba(colors.$burntSienna, 0.5); + stroke: colors.$burntSienna; } &.status-running { border-color: colors.$pictonBlue; - stroke: colors.$pictonBlue; box-shadow: 0 4px 20px rgba(colors.$pictonBlue, 0.5); + stroke: colors.$pictonBlue; } } } @@ -123,9 +123,9 @@ .react-flow__node-label { position: relative; width: 100%; + overflow: hidden; font-size: 1.5rem; text-align: center; - overflow: hidden; } .react-flow__node-sub-label { diff --git a/src/common/Search/search.scss b/src/common/Search/search.scss index 377b71fd9c..6d537e1384 100644 --- a/src/common/Search/search.scss +++ b/src/common/Search/search.scss @@ -19,6 +19,7 @@ &-input { z-index: 2; width: 100%; + // todo: delete `!important` after replacing `Input` with `FormInput` padding: 10px 20px 10px 35px !important; color: colors.$topaz; @@ -41,9 +42,9 @@ } &-matches { + max-height: 250px; margin: 0; padding: 0; - max-height: 250px; &__item { padding: 7px 15px; diff --git a/src/common/SearchNavigator/searchNavigator.scss b/src/common/SearchNavigator/searchNavigator.scss index 020ed961fd..b8a810408c 100644 --- a/src/common/SearchNavigator/searchNavigator.scss +++ b/src/common/SearchNavigator/searchNavigator.scss @@ -10,20 +10,20 @@ &__counter { display: flex; - font-size: 13px; color: colors.$topaz; + font-size: 13px; - &:after { + &::after { display: none; - content: ''; width: 5px; height: 15px; margin: 0 5px 0 8px; border-right: borders.$primaryBorder; + content: ''; } &_with-divider { - &:after { + &::after { display: block; } } diff --git a/src/common/SplitButton/splitButton.scss b/src/common/SplitButton/splitButton.scss index 75f34a941a..6c37a5b517 100644 --- a/src/common/SplitButton/splitButton.scss +++ b/src/common/SplitButton/splitButton.scss @@ -27,7 +27,7 @@ svg { & > * { - fill: currentColor; + fill: currentcolor; } } } diff --git a/src/components/ArtifactInfoSources/artifactInfoSources.scss b/src/components/ArtifactInfoSources/artifactInfoSources.scss index 60e988a157..9ccc5bf3cd 100644 --- a/src/components/ArtifactInfoSources/artifactInfoSources.scss +++ b/src/components/ArtifactInfoSources/artifactInfoSources.scss @@ -39,8 +39,8 @@ display: inline-block; flex: 1 1; min-width: 110px; - word-break: break-word; color: colors.$topaz; + word-break: break-word; &__copy-to-clipboard { display: flex; diff --git a/src/components/ArtifactsPreview/artifactsPreview.scss b/src/components/ArtifactsPreview/artifactsPreview.scss index 9c8feb71c2..bbcc290cba 100644 --- a/src/components/ArtifactsPreview/artifactsPreview.scss +++ b/src/components/ArtifactsPreview/artifactsPreview.scss @@ -20,7 +20,7 @@ &-title { display: flex; align-items: center; - margin: 0 0 15px 0; + margin: 0 0 15px; color: colors.$topaz; font-weight: 500; font-size: 20px; diff --git a/src/components/ArtifactsPreview/artifactsPreviewController.scss b/src/components/ArtifactsPreview/artifactsPreviewController.scss index 9a9f12a7f3..94573d135a 100644 --- a/src/components/ArtifactsPreview/artifactsPreviewController.scss +++ b/src/components/ArtifactsPreview/artifactsPreviewController.scss @@ -10,11 +10,11 @@ } .icon-popout { - text-align: end; - cursor: pointer; - min-height: 40px; width: 100%; height: auto; - padding: 0; + min-height: 40px; margin-bottom: 10px; + padding: 0; + text-align: end; + cursor: pointer; } diff --git a/src/components/DetailsInfo/detailsInfo.scss b/src/components/DetailsInfo/detailsInfo.scss index fc4741f8e8..cfc2613c68 100644 --- a/src/components/DetailsInfo/detailsInfo.scss +++ b/src/components/DetailsInfo/detailsInfo.scss @@ -26,13 +26,13 @@ $itemInfoWithoutPadding: item-info-without-padding; &__header { margin: 0; - padding: 10px 0 7.5px 0; + padding: 10px 0 7.5px; font-size: 18px; } &__details { margin: 0 0 21px; - padding: 0 0 0 0; + padding: 0; list-style-type: none; &-wrapper { diff --git a/src/components/DetailsMetrics/DetailsMetrics.scss b/src/components/DetailsMetrics/DetailsMetrics.scss index a36bdcd10d..1d9bc2d2dd 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.scss +++ b/src/components/DetailsMetrics/DetailsMetrics.scss @@ -21,7 +21,7 @@ $stickyHeaderHeight: 55px; background-color: colors.$white; > * { - margin: 0 0 15px 0; + margin: 0 0 15px; } .details-date-picker { diff --git a/src/components/DetailsRequestedFeatures/detailsRequestedFeatures.scss b/src/components/DetailsRequestedFeatures/detailsRequestedFeatures.scss index fc59156a0b..bcd718a217 100644 --- a/src/components/DetailsRequestedFeatures/detailsRequestedFeatures.scss +++ b/src/components/DetailsRequestedFeatures/detailsRequestedFeatures.scss @@ -10,6 +10,7 @@ &-header { position: sticky; top: 0; + z-index: 3; display: flex; flex-direction: row; align-items: center; @@ -20,7 +21,6 @@ line-height: 24px; background-color: colors.$white; border-bottom: borders.$secondaryBorder; - z-index: 3; } &-cell { diff --git a/src/components/DetailsResults/detailsResults.scss b/src/components/DetailsResults/detailsResults.scss index 1b5d47ebf3..3f74e999a7 100644 --- a/src/components/DetailsResults/detailsResults.scss +++ b/src/components/DetailsResults/detailsResults.scss @@ -3,8 +3,8 @@ @use 'igz-controls/scss/mixins'; .table__item-results { - display: flex; position: relative; + display: flex; .table { i { diff --git a/src/components/DetailsStatistics/detailsStatistics.scss b/src/components/DetailsStatistics/detailsStatistics.scss index 75601d6efb..d24b6f49f5 100644 --- a/src/components/DetailsStatistics/detailsStatistics.scss +++ b/src/components/DetailsStatistics/detailsStatistics.scss @@ -21,7 +21,7 @@ $detailsStatisticsHeaderRowHeight: 49px; &-wrapper { width: 100%; - padding: 0 0 20px 0; + padding: 0 0 20px; } &-header { diff --git a/src/components/FeatureSetsPanel/featureSetsPanel.scss b/src/components/FeatureSetsPanel/featureSetsPanel.scss index 1be3c5c236..580e8202bb 100644 --- a/src/components/FeatureSetsPanel/featureSetsPanel.scss +++ b/src/components/FeatureSetsPanel/featureSetsPanel.scss @@ -1,7 +1,6 @@ @use 'igz-controls/scss/colors'; @use 'igz-controls/scss/borders'; @use 'igz-controls/scss/mixins'; - @include mixins.newItemSidePanel; .feature-set-panel { diff --git a/src/components/FilterMenuModal/filterMenuModal.scss b/src/components/FilterMenuModal/filterMenuModal.scss index 54ce1aab92..a0f5e0dfd8 100644 --- a/src/components/FilterMenuModal/filterMenuModal.scss +++ b/src/components/FilterMenuModal/filterMenuModal.scss @@ -13,16 +13,16 @@ top: 0; margin: 0; padding: 0 0 16px; - background: colors.$white; + color: colors.$mulledWine; font-weight: 500; font-size: 20px; line-height: 23.44px; - color: colors.$mulledWine; + background: colors.$white; } &__list { - padding-right: 15px; margin: 0 -15px 0 0; + padding-right: 15px; overflow-y: auto; } @@ -44,16 +44,16 @@ position: relative; &::after { - content: ''; position: absolute; top: 4px; right: 4px; - height: 10px; + z-index: 2; width: 10px; + height: 10px; + background: colors.$brightTurquoise; border: 2px solid colors.$white; border-radius: 50%; - background: colors.$brightTurquoise; - z-index: 2; + content: ''; } } } diff --git a/src/components/FunctionsPanel/functionsPanel.scss b/src/components/FunctionsPanel/functionsPanel.scss index be5b458e08..0cd25a6647 100644 --- a/src/components/FunctionsPanel/functionsPanel.scss +++ b/src/components/FunctionsPanel/functionsPanel.scss @@ -1,7 +1,6 @@ @use 'igz-controls/scss/colors'; @use 'igz-controls/scss/borders'; @use 'igz-controls/scss/mixins'; - @include mixins.newItemSidePanel; .functions-panel { diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/jobWizardAdvanced.scss b/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/jobWizardAdvanced.scss index d4dbe92516..be91e46cc2 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/jobWizardAdvanced.scss +++ b/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/jobWizardAdvanced.scss @@ -1,5 +1,5 @@ .job-wizard__advanced { .access-key-checkbox { - margin: 30px 10px 0 10px; + margin: 30px 10px 0; } } diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.scss b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.scss index ea94067e61..c6b6037317 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.scss +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.scss @@ -24,8 +24,8 @@ } .content-menu { - margin-bottom: 15px; min-width: unset; + margin-bottom: 15px; } .form-row__project-name { diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardHyperparameterStrategy/jobWizardHyperparametersStrategy.scss b/src/components/JobWizard/JobWizardSteps/JobWizardHyperparameterStrategy/jobWizardHyperparametersStrategy.scss index 0c25490871..e13f0163f0 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardHyperparameterStrategy/jobWizardHyperparametersStrategy.scss +++ b/src/components/JobWizard/JobWizardSteps/JobWizardHyperparameterStrategy/jobWizardHyperparametersStrategy.scss @@ -1,9 +1,6 @@ .job-wizard__hyperparameter-strategy { .grid-container { display: grid; - gap: 15px; - align-items: center; - grid-template-columns: 20% 20% 20% 20%; grid-template-areas: 'strategy-grid-item strategy-grid-item . .' 'max-iterations-grid-item max-errors-grid-item . .' @@ -13,19 +10,22 @@ 'stop-condition-grid-item stop-condition-grid-item . .' 'parallelism-title-grid-item parallelism-title-grid-item . .' 'parallel-runs-grid-item dask-cluster-uri-grid-item dask-cluster-uri-grid-item teardown-dask-grid-item'; + grid-template-columns: 20% 20% 20% 20%; + gap: 15px; + align-items: center; .strategy-grid-item { grid-area: strategy-grid-item; } .max-iterations-grid-item { - min-width: 100px; grid-area: max-iterations-grid-item; + min-width: 100px; } .max-errors-grid-item { - min-width: 100px; grid-area: max-errors-grid-item; + min-width: 100px; } .ranking-title-grid-item { diff --git a/src/components/ModelsPage/modelsPage.scss b/src/components/ModelsPage/modelsPage.scss index 42aec12289..c61d799516 100644 --- a/src/components/ModelsPage/modelsPage.scss +++ b/src/components/ModelsPage/modelsPage.scss @@ -24,9 +24,9 @@ pre { width: 800px; - overflow-x: scroll; - padding: 20px 0; margin: 0; + padding: 20px 0; + overflow-x: scroll; } } } diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/monitoringApplication.scss b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/monitoringApplication.scss index c5776e65fa..0b78609868 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/monitoringApplication.scss +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/monitoringApplication.scss @@ -4,6 +4,6 @@ } .monitoring-app__see-all-link { - text-align: right; margin-top: 8px; + text-align: right; } diff --git a/src/components/Pipeline/pipeline.scss b/src/components/Pipeline/pipeline.scss index 6ae61b1ad7..c21e6ffabe 100644 --- a/src/components/Pipeline/pipeline.scss +++ b/src/components/Pipeline/pipeline.scss @@ -24,9 +24,9 @@ &__title { margin: 0 5px; - font-size: 24px; overflow: hidden; font-weight: bold; + font-size: 24px; } } } diff --git a/src/components/Project/ProjectAction/ProjectAction.scss b/src/components/Project/ProjectAction/ProjectAction.scss index b4f4153484..2f154cb00b 100644 --- a/src/components/Project/ProjectAction/ProjectAction.scss +++ b/src/components/Project/ProjectAction/ProjectAction.scss @@ -5,27 +5,27 @@ flex-flow: row wrap; align-items: flex-start; justify-content: flex-start; + width: 100%; margin: 0; padding: 0; list-style-type: none; - width: 100%; transition: height 0.5s ease-in-out; &__item { display: flex; - justify-content: center; flex: 1 0 auto; + justify-content: center; max-width: 33%; margin: 0 0 1.5em; text-align: center; &-wrapper { + position: relative; display: flex; flex-flow: column nowrap; align-items: center; - position: relative; - margin: 0 1.2em; min-width: 105px; + margin: 0 1.2em; cursor: pointer; &:hover, @@ -53,8 +53,8 @@ justify-content: center; width: 68px; height: 68px; - margin-bottom: 0.5rem; margin-right: 0; + margin-bottom: 0.5rem; background-color: colors.$selago; border-radius: 50%; transition: background-color 0.3s ease-in-out; diff --git a/src/components/Project/ProjectOverview/ProjectOverview.scss b/src/components/Project/ProjectOverview/ProjectOverview.scss index 3acf081c68..d2b0df7539 100644 --- a/src/components/Project/ProjectOverview/ProjectOverview.scss +++ b/src/components/Project/ProjectOverview/ProjectOverview.scss @@ -39,6 +39,7 @@ &-card { flex: 0 0 100%; min-width: 350px; + // min-height: 635px; margin: 0 15px 2em; transform: translateY(-60px); @@ -51,7 +52,6 @@ &__top { position: relative; display: flex; - flex-flow: column; } @@ -65,16 +65,16 @@ &__bottom { display: flex; - flex-flow: column nowrap; flex: 1; + flex-flow: column nowrap; justify-content: space-between; - text-align: center; min-height: 66px; + text-align: center; .label { - font-size: 1.2em; - margin: 0 0 10px 0; + margin: 0 0 10px; padding: 0; + font-size: 1.2em; } } @@ -94,8 +94,8 @@ & > * { display: inline-flex; align-items: flex-end; - font-size: 14px; padding: 5px 10px; + font-size: 14px; text-transform: capitalize; cursor: pointer; @@ -106,8 +106,8 @@ } &__actions { - padding: 0 1.6em; min-height: 270px; + padding: 0 1.6em; } } } @@ -122,7 +122,7 @@ background-color: colors.$white; border: 1px solid colors.$mercury; border-radius: 12px; - box-shadow: 7px 8px 25px rgba(0, 0, 0, 0.04); + box-shadow: 7px 8px 25px rgb(0 0 0 / 4%); &__top { background-color: colors.$zircon; @@ -149,8 +149,8 @@ &-subtitle { margin: 0; - font-size: 1em; font-weight: 300; + font-size: 1em; line-height: 1.3; @media screen and (min-width: 1600px) { diff --git a/src/components/ProjectSettings/projectSettings.scss b/src/components/ProjectSettings/projectSettings.scss index a5a09d8df4..3d98856cd6 100644 --- a/src/components/ProjectSettings/projectSettings.scss +++ b/src/components/ProjectSettings/projectSettings.scss @@ -17,10 +17,10 @@ margin: 0 -15px; &-col { - padding: 0 15px; flex: 0 0 auto; width: 50%; min-width: 650px; + padding: 0 15px; &:not(:last-child) { border-right: borders.$dividerBorder; diff --git a/src/components/Workflow/workflow.scss b/src/components/Workflow/workflow.scss index 3985ad0e26..085e7c0b14 100644 --- a/src/components/Workflow/workflow.scss +++ b/src/components/Workflow/workflow.scss @@ -8,17 +8,19 @@ .workflow__actions { &-container { - align-items: center; + display: flex; flex-direction: row; gap: 2px; - display: flex; + align-items: center; } + svg { - padding: 0; - height: 14px; width: 14px; + height: 14px; + padding: 0; } } + .workflow-content { flex-direction: column; diff --git a/src/elements/AlertsTableRow/AlertsTableRow.scss b/src/elements/AlertsTableRow/AlertsTableRow.scss index ae9ebd21c9..d619fbba00 100644 --- a/src/elements/AlertsTableRow/AlertsTableRow.scss +++ b/src/elements/AlertsTableRow/AlertsTableRow.scss @@ -73,7 +73,7 @@ flex-direction: row; gap: 10px; align-items: center; - margin: 12px 0 12px 0; + margin: 12px 0; padding-right: 12px; &:not(:last-child) { diff --git a/src/elements/BreadcrumbsDropdown/breadcrumbsDropdown.scss b/src/elements/BreadcrumbsDropdown/breadcrumbsDropdown.scss index dad7cf67ec..ed988c3819 100644 --- a/src/elements/BreadcrumbsDropdown/breadcrumbsDropdown.scss +++ b/src/elements/BreadcrumbsDropdown/breadcrumbsDropdown.scss @@ -3,8 +3,8 @@ @use 'igz-controls/scss/borders'; .breadcrumbs__dropdown { - max-height: 384px; min-width: 220px; + max-height: 384px; overflow-y: auto; &-wrapper { @@ -37,8 +37,8 @@ font-weight: bold; &:hover { - cursor: default; background: white; + cursor: default; } } diff --git a/src/elements/CreateJobCardTemplate/createJobCardTemplate.scss b/src/elements/CreateJobCardTemplate/createJobCardTemplate.scss index 707b83085e..15dae091e6 100644 --- a/src/elements/CreateJobCardTemplate/createJobCardTemplate.scss +++ b/src/elements/CreateJobCardTemplate/createJobCardTemplate.scss @@ -31,10 +31,10 @@ } &__description { + height: 42px; color: colors.$topaz; font-size: 13px; line-height: 21px; - height: 42px; } &.small { diff --git a/src/elements/EnvironmentVariables/enviromnetVariables.scss b/src/elements/EnvironmentVariables/enviromnetVariables.scss index b8a2133ad7..620b9f128f 100644 --- a/src/elements/EnvironmentVariables/enviromnetVariables.scss +++ b/src/elements/EnvironmentVariables/enviromnetVariables.scss @@ -48,7 +48,7 @@ &__row { .active-input { - padding: 25px 16px 11px 16px; + padding: 25px 16px 11px; } .table-cell { diff --git a/src/elements/FormResourcesUnits/formResourcesUnits.scss b/src/elements/FormResourcesUnits/formResourcesUnits.scss index 74cb92e6af..40355a42cb 100644 --- a/src/elements/FormResourcesUnits/formResourcesUnits.scss +++ b/src/elements/FormResourcesUnits/formResourcesUnits.scss @@ -16,8 +16,8 @@ } .resources-card { - min-width: 280px; width: 100%; + min-width: 280px; padding: 16px; border: borders.$primaryBorder; border-radius: 8px; diff --git a/src/elements/FormVolumesTable/FormVolumesRow/formVolumeRow.scss b/src/elements/FormVolumesTable/FormVolumesRow/formVolumeRow.scss index ec31b3d8f0..ccabe0b1cf 100644 --- a/src/elements/FormVolumesTable/FormVolumesRow/formVolumeRow.scss +++ b/src/elements/FormVolumesTable/FormVolumesRow/formVolumeRow.scss @@ -1,4 +1,4 @@ -@use 'igz-controls/scss/colors.scss'; +@use 'igz-controls/scss/colors'; .form-table__row { &.form-table__volume-row { diff --git a/src/elements/FunctionCardTemplate/functionCardTemplate.scss b/src/elements/FunctionCardTemplate/functionCardTemplate.scss index 419a7ff21e..f9aeaeac69 100644 --- a/src/elements/FunctionCardTemplate/functionCardTemplate.scss +++ b/src/elements/FunctionCardTemplate/functionCardTemplate.scss @@ -3,11 +3,11 @@ @use 'igz-controls/scss/shadows'; .job-card-template { + position: relative; display: flex; flex-flow: column nowrap; justify-content: space-between; min-height: 165px; - position: relative; padding: 15px; background-color: colors.$white; border: borders.$primaryBorder; @@ -30,15 +30,15 @@ } &__header { - font-size: 18px; - font-weight: bold; margin-bottom: 8px; padding-right: 50px; + font-weight: bold; + font-size: 18px; } &__sub-header { - font-size: 15px; font-weight: 500; + font-size: 15px; } &__side-tag { @@ -46,15 +46,15 @@ top: 15px; right: 0; display: flex; - justify-content: center; align-items: center; + justify-content: center; margin: 0; padding: 6px; - border-radius: 4px 0 0 4px; color: colors.$amethyst; - background-color: colors.$frenchLilac; - font-size: 10px; font-weight: bold; + font-size: 10px; + background-color: colors.$frenchLilac; + border-radius: 4px 0 0 4px; } &__description { diff --git a/src/elements/FunctionsPanelCode/functionsPanelCode.scss b/src/elements/FunctionsPanelCode/functionsPanelCode.scss index 65570b0c51..c85b8fd73a 100644 --- a/src/elements/FunctionsPanelCode/functionsPanelCode.scss +++ b/src/elements/FunctionsPanelCode/functionsPanelCode.scss @@ -55,7 +55,7 @@ width: 200px; div:not(:last-child) { - margin: 10px 0 43px 0; + margin: 10px 0 43px; } } } diff --git a/src/elements/JobsMonitoringStatsCard/jobsMonitoringStatsCard.scss b/src/elements/JobsMonitoringStatsCard/jobsMonitoringStatsCard.scss index 039d4bcb44..80169d7747 100644 --- a/src/elements/JobsMonitoringStatsCard/jobsMonitoringStatsCard.scss +++ b/src/elements/JobsMonitoringStatsCard/jobsMonitoringStatsCard.scss @@ -13,9 +13,9 @@ @include mixins.stats(); &-card { - cursor: pointer; - border: 2px solid transparent; min-height: 144px; + border: 2px solid transparent; + cursor: pointer; } &__counter { diff --git a/src/elements/MembersPopUp/membersPopUp.scss b/src/elements/MembersPopUp/membersPopUp.scss index 4e223b2fb8..7d97d7baac 100644 --- a/src/elements/MembersPopUp/membersPopUp.scss +++ b/src/elements/MembersPopUp/membersPopUp.scss @@ -84,8 +84,8 @@ .new-member-name { width: 70%; - padding-left: 10px; padding-right: 10px; + padding-left: 10px; } .new-member-role { @@ -150,8 +150,8 @@ background-color: colors.$white; .member-info { - margin-right: 5%; width: 65%; + margin-right: 5%; border-bottom: borders.$primaryBorder; } } diff --git a/src/elements/MethodDescription/methodDescription.scss b/src/elements/MethodDescription/methodDescription.scss index db052a6485..2b6cd81fed 100644 --- a/src/elements/MethodDescription/methodDescription.scss +++ b/src/elements/MethodDescription/methodDescription.scss @@ -23,7 +23,7 @@ align-items: center; height: 17px; margin-left: 5px; - padding: 0 5px 12px 5px; + padding: 0 5px 12px; color: colors.$topaz; font-weight: bold; font-size: 20px; diff --git a/src/elements/NavbarLink/NavbarLink.scss b/src/elements/NavbarLink/NavbarLink.scss index 72c95ec3a9..55bb0347e2 100644 --- a/src/elements/NavbarLink/NavbarLink.scss +++ b/src/elements/NavbarLink/NavbarLink.scss @@ -12,15 +12,15 @@ flex-flow: row nowrap; justify-content: flex-start; width: 100%; - min-height: 48px; min-width: 48px; + min-height: 48px; padding: 0 16px 0 13px; color: colors.$poloBlue; font-weight: normal; + white-space: nowrap; background-color: transparent; border: 2px solid transparent; border-radius: 8px; - white-space: nowrap; cursor: pointer; transition: border-color 0.3s ease-in-out; @@ -50,7 +50,7 @@ &:hover, &:focus-visible { &.btn { - &:not(:disabled):not([class*='active']) { + &:not(:disabled, [class*='active']) { color: colors.$poloBlue; background-color: transparent; border-color: colors.$poloBlue; diff --git a/src/elements/ProjectSettingsGeneral/projectSettingsGeneral.scss b/src/elements/ProjectSettingsGeneral/projectSettingsGeneral.scss index 4b031abebe..7c9bd5f6e1 100644 --- a/src/elements/ProjectSettingsGeneral/projectSettingsGeneral.scss +++ b/src/elements/ProjectSettingsGeneral/projectSettingsGeneral.scss @@ -17,8 +17,8 @@ &-link { display: block; margin-top: 5px; - font-weight: 400; color: colors.$topaz; + font-weight: 400; font-size: 0.75rem; .link { diff --git a/src/elements/TableTop/tableTop.scss b/src/elements/TableTop/tableTop.scss index 14b76c803c..1c4eeb503c 100644 --- a/src/elements/TableTop/tableTop.scss +++ b/src/elements/TableTop/tableTop.scss @@ -17,9 +17,9 @@ &__title { margin: 0 5px; - font-size: 24px; overflow: hidden; font-weight: bold; + font-size: 24px; } } } diff --git a/src/layout/Header/header.scss b/src/layout/Header/header.scss index f89ceade06..b95e95f579 100644 --- a/src/layout/Header/header.scss +++ b/src/layout/Header/header.scss @@ -5,10 +5,6 @@ @use 'igz-controls/scss/borders'; .header { - line-height: 1.5; - - @include mixins.fixed; - z-index: 12; display: flex; align-items: center; @@ -16,9 +12,12 @@ min-height: 64px; padding: 0 24px; color: colors.$white; + line-height: 1.5; background-color: colors.$ebonyClay; box-shadow: shadows.$mainHeaderShadow; + @include mixins.fixed; + &__brand { display: flex; align-items: flex-end; @@ -60,10 +59,10 @@ display: flex; align-items: center; justify-content: center; + padding: 8px; + color: colors.$white; background-color: colors.$cerulean; border-radius: 50%; - color: colors.$white; - padding: 8px; transition: background-color 0.2s ease-in-out; & > * { diff --git a/src/layout/Navbar/Navbar.scss b/src/layout/Navbar/Navbar.scss index 8d63e91673..1c6da5e17d 100644 --- a/src/layout/Navbar/Navbar.scss +++ b/src/layout/Navbar/Navbar.scss @@ -3,14 +3,14 @@ @use 'igz-controls/scss/borders'; .navbar { - display: flex; - flex-grow: 1; - flex-shrink: 0; - flex-flow: column nowrap; position: absolute; top: 0; left: 0; z-index: 11; + display: flex; + flex-flow: column nowrap; + flex-grow: 1; + flex-shrink: 0; height: 100%; background-color: colors.$wildSand; border-right: borders.$tertiaryBorder; @@ -27,8 +27,8 @@ } .navbar__pin-icon { - opacity: 1; visibility: visible; + opacity: 1; } } @@ -53,12 +53,12 @@ margin-bottom: 20px; &::before { - content: ''; display: block; width: 100%; height: 1px; - border-top: borders.$primaryBorder; margin-bottom: 10px; + border-top: borders.$primaryBorder; + content: ''; } } } @@ -76,8 +76,8 @@ display: flex; justify-content: flex-end; padding: 0.5rem; - opacity: 0; visibility: hidden; + opacity: 0; transition: all 0.3s ease-in-out; button { diff --git a/src/layout/Page/Page.scss b/src/layout/Page/Page.scss index 2222511699..390dc777d3 100644 --- a/src/layout/Page/Page.scss +++ b/src/layout/Page/Page.scss @@ -7,6 +7,7 @@ display: flex; justify-content: flex-end; width: 100%; + // transform: translateX(variables.$navbarTogglerWidth); transition: all 0.3s ease-in-out; } @@ -17,6 +18,6 @@ flex: 1; flex-flow: column nowrap; align-items: flex-start; - overflow: auto; width: 100%; + overflow: auto; } diff --git a/src/scss/main.scss b/src/scss/main.scss index daee56e3ac..4bee51d198 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -87,7 +87,7 @@ main { .page-actions { display: flex; justify-content: flex-end; - margin: 0 0 20px 0; + margin: 0 0 20px; .search-container { flex: unset; From 04ab18284513e20ce1f1121bd650b9d70dc0b03b Mon Sep 17 00:00:00 2001 From: "Taras.Hlukhovetskyi" Date: Fri, 5 Sep 2025 13:20:57 +0300 Subject: [PATCH 174/228] fix after rebase --- package.json | 2 +- src/common/ExpandableText/expandableText.scss | 26 +++++++++---------- src/common/StatsCard/statsCard.scss | 2 +- src/components/Project/project.scss | 8 +++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 0d0d8435e7..996d09ea57 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "start": "vite", "build": "vite build", "lint": "eslint .", - "stylelint": "stylelint '**/*.scss' --fix", + "stylelint": "stylelint '**/*.{css,scss}'", "preview": "vite preview", "preinstall": "npx force-resolutions", "test:coverage": "npm run test -- --coverage --watchAll=false", diff --git a/src/common/ExpandableText/expandableText.scss b/src/common/ExpandableText/expandableText.scss index 5f5a1672ad..4b29b9fb39 100644 --- a/src/common/ExpandableText/expandableText.scss +++ b/src/common/ExpandableText/expandableText.scss @@ -5,47 +5,47 @@ } .expandable-text { - display: block; - transition: max-height 0.3s ease; position: relative; + display: block; overflow: hidden; + transition: max-height 0.3s ease; } .fade-overlay { - content: ''; position: absolute; + right: 0; bottom: 0; left: 0; - right: 0; height: 40px; - background: linear-gradient(to bottom, rgba(255, 255, 255, 0), #fff); + background: linear-gradient(to bottom, rgb(255 255 255 / 0%), #fff); + content: ''; pointer-events: none; } .see-more-button-overlay { position: absolute; - bottom: 4px; right: 0; - background: white; - padding-left: 8px; + bottom: 4px; display: flex; - align-items: center; gap: 4px; + align-items: center; + padding-left: 8px; + background: white; } .dots { - font-weight: bold; color: colors.$doveGrayTwo; + font-weight: bold; } .see-more-button, .see-less-button { - background: none; - border: none; + padding: 0; color: colors.$cornflowerBlue; font-size: 14px; + background: none; + border: none; cursor: pointer; - padding: 0; } .see-less-container { diff --git a/src/common/StatsCard/statsCard.scss b/src/common/StatsCard/statsCard.scss index 6f34f01682..2deaed945a 100644 --- a/src/common/StatsCard/statsCard.scss +++ b/src/common/StatsCard/statsCard.scss @@ -69,9 +69,9 @@ transition: all 0.3s ease-in-out; @media screen and (min-width: 1600px) { + top: -2px; width: 20px; height: 20px; - top: -2px; } svg { diff --git a/src/components/Project/project.scss b/src/components/Project/project.scss index 51ce3a66e1..9298ee7af6 100644 --- a/src/components/Project/project.scss +++ b/src/components/Project/project.scss @@ -146,8 +146,8 @@ justify-content: space-between; margin-bottom: 16px; color: colors.$primary; - font-size: 1em; font-weight: 500; + font-size: 1em; line-height: 23px; } @@ -155,8 +155,8 @@ display: flex; align-items: center; color: colors.$topaz; - font-size: 12px; font-weight: 400; + font-size: 12px; &-icon { flex: 0 1 12px; @@ -202,9 +202,9 @@ display: flex; align-items: center; min-height: 40px; - margin: 0 0 5px 0; - font-size: 14px; + margin: 0 0 5px; font-weight: 500; + font-size: 14px; .text-sm { margin-left: 5px; From 114245defb3b191a52da779d2f1bead31782b589 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Thu, 2 Oct 2025 14:21:00 +0300 Subject: [PATCH 175/228] update dev deps that do not require node.js update --- config/paths.js | 1 - package.json | 83 ++++++++----------- src/components/Artifacts/artifacts.scss | 2 +- .../FeatureStore/FeatureSets/featureSets.scss | 2 +- .../FeatureVectors/featureVectors.scss | 2 +- .../FeatureStore/Features/features.scss | 2 +- src/components/FunctionsPage/functions.scss | 2 +- .../ModelEndpoints/modelEndpoints.scss | 2 +- .../RealTimePipelines/realTimePipelines.scss | 2 +- .../monitoringApplicationsPage.scss | 2 +- .../scheduledJobsTable.scss | 2 +- src/setupProxy.js | 76 ----------------- tests/mockServer/mock.js | 5 +- vite.config.mjs | 3 +- 14 files changed, 46 insertions(+), 140 deletions(-) delete mode 100644 src/setupProxy.js diff --git a/config/paths.js b/config/paths.js index b17443273e..ea07637455 100644 --- a/config/paths.js +++ b/config/paths.js @@ -83,7 +83,6 @@ module.exports = { appJsConfig: resolveApp('jsconfig.json'), yarnLockFile: resolveApp('yarn.lock'), testsSetup: resolveModule(resolveApp, 'src/setupTests'), - proxySetup: resolveApp('src/setupProxy.js'), appNodeModules: resolveApp('node_modules'), appWebpackCache: resolveApp('node_modules/.cache'), appTsBuildInfoFile: resolveApp('node_modules/.cache/tsconfig.tsbuildinfo'), diff --git a/package.json b/package.json index 996d09ea57..d619d5881f 100644 --- a/package.json +++ b/package.json @@ -76,86 +76,71 @@ "nui": "npm unlink iguazio.dashboard-react-controls" }, "devDependencies": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.24.1", - "@babel/node": "^7.14.9", - "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", + "@babel/core": "^7.28.4", + "@babel/node": "^7.28.0", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", "@babel/polyfill": "^7.12.1", - "@babel/preset-env": "^7.13.12", - "@babel/register": "^7.13.14", + "@babel/preset-env": "^7.28.3", + "@babel/register": "^7.28.3", "@cucumber/cucumber": "^10.3.1", "@d4c/numjs": "^0.17.34", - "@eslint/js": "^9.19.0", + "@eslint/js": "^9.36.0", "@storybook/addon-actions": "^8.0.1", "@storybook/addon-essentials": "^8.0.1", "@storybook/addon-links": "^8.0.1", "@storybook/preset-scss": "^1.0.3", "@storybook/react": "^8.0.1", - "@testing-library/react": "^11.0.2", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.0", "@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react-swc": "^3.8.0", - "acorn": "^7.4.1", - "babel-jest": "^29.7.0", - "babel-loader": "^8.2.3", + "acorn": "^8.15.0", + "babel-jest": "^30.2.0", "babel-node": "0.0.1-security", - "babel-plugin-inline-react-svg": "^2.0.1", - "babel-plugin-jest-hoist": "^26.2.0", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-plugin-prismjs": "^2.1.0", - "babel-plugin-react-remove-properties": "^0.3.0", - "babel-preset-react-app": "^10.0.1", + "babel-plugin-inline-react-svg": "^2.0.2", + "babel-plugin-jest-hoist": "^30.0.1", "babel-runtime": "^6.26.0", - "body-parser": "^1.19.0", + "body-parser": "^2.2.0", "chai": "^4.3.4", - "chromedriver": "^140.0.0", - "cross-env": "^7.0.3", - "css-loader": "^6.5.1", - "cucumber-html-reporter": "^5.3.0", - "eslint": "^9.13.0", - "eslint-config-prettier": "^9.1.0", + "chromedriver": "^140.0.4", + "cross-env": "^10.0.0", + "cucumber-html-reporter": "^7.2.0", + "eslint": "^9.36.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-babel": "^5.3.1", "eslint-plugin-import": "^2.32.0", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-hooks": "^5.1.0", - "eslint-plugin-react-refresh": "^0.4.14", - "express": "^4.17.1", - "file-loader": "^6.2.0", - "geckodriver": "^3.0.1", - "globals": "^15.14.0", - "http-proxy-middleware": "^2.0.3", - "mime-types": "^2.1.35", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "express": "^5.1.0", + "geckodriver": "^6.0.1", + "globals": "^16.4.0", + "mime-types": "^3.0.1", "node": "^21.6.2", - "nodemon": "^3.1.2", + "nodemon": "^3.1.10", "pandas-js": "^0.2.4", - "postcss": "^8.4.36", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^9.5.2", - "postcss-safe-parser": "7.0.0", - "prettier": "^3.3.3", + "prettier": "^3.6.2", "randexp": "^0.5.3", "react-app-polyfill": "^3.0.0", "react-dev-utils": "^12.0.1", - "sass": "^1.72.0", - "sass-loader": "^12.3.2", + "sass": "^1.93.2", "selenium-webdriver": "^4.35.0", - "source-map-loader": "^5.0.0", - "stylelint": "^16.21.0", + "stylelint": "^16.24.0", "stylelint-config-rational-order": "^0.1.2", - "stylelint-config-standard": "^38.0.0", - "stylelint-config-standard-scss": "^15.0.1", + "stylelint-config-standard": "^39.0.0", + "stylelint-config-standard-scss": "^16.0.0", "stylelint-order": "^7.0.0", "stylelint-scss": "^6.12.1", "url-loader": "4.1.1", "vite": "^6.2.0", "vite-plugin-commonjs": "^0.10.4", "vite-plugin-eslint": "^1.8.1", - "vite-plugin-svgr": "^4.3.0" + "vite-plugin-svgr": "^4.5.0" }, "babel": { "plugins": [ - "@babel/plugin-proposal-logical-assignment-operators" + "@babel/plugin-transform-logical-assignment-operators" ], "presets": [ [ diff --git a/src/components/Artifacts/artifacts.scss b/src/components/Artifacts/artifacts.scss index 9a5c65d1db..b26b375d43 100644 --- a/src/components/Artifacts/artifacts.scss +++ b/src/components/Artifacts/artifacts.scss @@ -1,5 +1,5 @@ @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $artifactsRowHeight: variables.$rowHeight; $artifactsHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/components/FeatureStore/FeatureSets/featureSets.scss b/src/components/FeatureStore/FeatureSets/featureSets.scss index d09344b5ee..c381eceea0 100644 --- a/src/components/FeatureStore/FeatureSets/featureSets.scss +++ b/src/components/FeatureStore/FeatureSets/featureSets.scss @@ -1,5 +1,5 @@ @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $featureSetsRowHeight: variables.$rowHeight; $featureSetsHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/components/FeatureStore/FeatureVectors/featureVectors.scss b/src/components/FeatureStore/FeatureVectors/featureVectors.scss index 3a160dabb8..eb5c63e963 100644 --- a/src/components/FeatureStore/FeatureVectors/featureVectors.scss +++ b/src/components/FeatureStore/FeatureVectors/featureVectors.scss @@ -1,5 +1,5 @@ @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $featureVectorsRowHeight: variables.$rowHeight; $featureVectorsHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/components/FeatureStore/Features/features.scss b/src/components/FeatureStore/Features/features.scss index 17bef53e51..b0ce7abcdb 100644 --- a/src/components/FeatureStore/Features/features.scss +++ b/src/components/FeatureStore/Features/features.scss @@ -1,5 +1,5 @@ @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $featuresRowHeight: variables.$rowHeightSmall; $featuresHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/components/FunctionsPage/functions.scss b/src/components/FunctionsPage/functions.scss index bacdf5ce64..50d3a180c3 100644 --- a/src/components/FunctionsPage/functions.scss +++ b/src/components/FunctionsPage/functions.scss @@ -1,5 +1,5 @@ @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $functionsRowHeight: variables.$rowHeight; $functionsHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.scss b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.scss index 6f09983739..2305dbbc80 100644 --- a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.scss +++ b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.scss @@ -1,5 +1,5 @@ @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $modelEndpointsRowHeight: variables.$rowHeightSmall; $modelEndpointsHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/components/ModelsPage/RealTimePipelines/realTimePipelines.scss b/src/components/ModelsPage/RealTimePipelines/realTimePipelines.scss index 29665dc152..0a1c0739cb 100644 --- a/src/components/ModelsPage/RealTimePipelines/realTimePipelines.scss +++ b/src/components/ModelsPage/RealTimePipelines/realTimePipelines.scss @@ -1,5 +1,5 @@ @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $pipelinesRowHeight: variables.$rowHeight; $pipelinesHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss index db6aeb07b6..6eea95bfa7 100644 --- a/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss +++ b/src/components/MonitoringApplicationsPage/monitoringApplicationsPage.scss @@ -1,7 +1,7 @@ @use 'igz-controls/scss/colors'; @use 'igz-controls/scss/shadows'; @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $applicationRowHeight: variables.$rowHeight; $applicationHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/elements/ScheduledJobsTable/scheduledJobsTable.scss b/src/elements/ScheduledJobsTable/scheduledJobsTable.scss index 96c95ebb21..09b049dd4e 100644 --- a/src/elements/ScheduledJobsTable/scheduledJobsTable.scss +++ b/src/elements/ScheduledJobsTable/scheduledJobsTable.scss @@ -1,5 +1,5 @@ @use 'igz-controls/scss/variables'; -@use '/src/scss/mixins'; +@use '@/scss/mixins'; $scheduledJobsRowHeight: variables.$rowHeightSmall; $scheduledJobsHeaderRowHeight: variables.$headerRowHeight; diff --git a/src/setupProxy.js b/src/setupProxy.js deleted file mode 100644 index 571c9c827d..0000000000 --- a/src/setupProxy.js +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -const { createProxyMiddleware } = require('http-proxy-middleware') - -module.exports = function (app) { - app.use( - '/api', - createProxyMiddleware({ - target: import.meta.env.VITE_MLRUN_API_URL, - changeOrigin: true, - headers: { - Connection: 'keep-alive' - }, - onProxyReq: function (proxyReq, req, res) { - proxyReq.setHeader('x-v3io-session-key', import.meta.env.VITE_MLRUN_V3IO_ACCESS_KEY) - proxyReq.setHeader('x-remote-user', 'admin') - } - }) - ) - - if (import.meta.env.VITE_NUCLIO_API_URL) { - app.use( - '/nuclio', - createProxyMiddleware({ - target: import.meta.env.VITE_NUCLIO_API_URL, - pathRewrite: { - '^/nuclio': '' - }, - changeOrigin: true - }) - ) - } - - if (import.meta.env.VITE_IGUAZIO_API_URL) { - app.use( - '/iguazio', - createProxyMiddleware({ - target: import.meta.env.VITE_IGUAZIO_API_URL, - pathRewrite: { - '^/iguazio': '' - }, - changeOrigin: true - }) - ) - } - - if (import.meta.env.VITE_FUNCTION_CATALOG_URL) { - app.use( - '/function-catalog', - createProxyMiddleware({ - target: import.meta.env.VITE_FUNCTION_CATALOG_URL, - pathRewrite: { - '^/function-catalog': '' - }, - changeOrigin: true - }) - ) - } -} diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 9c3e8d1b30..4308b0f5b8 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -2964,7 +2964,6 @@ app.get( ) app.get(`${mlrunAPIIngress}/projects/:project/runs`, getRuns) -app.get(`${mlrunAPIIngress}/projects/*/runs`, getRuns) app.get(`${mlrunAPIIngress}/projects/:project/alert-activations`, getAlerts) app.get(`${mlrunAPIIngress}/projects/:project/alert-activations/:id`, getAlert) app.get(`${mlrunAPIIngress}/projects/:project/runs/:uid`, getRun) @@ -2980,14 +2979,12 @@ app.get(`${mlrunAPIIngress}/hub/sources/:project/item-object`, getFunctionObject app.get(`${mlrunIngress}/:function/function.yaml`, getFunctionTemplate) app.get(`${mlrunAPIIngress}/projects/:project/schedules`, getProjectsSchedules) -app.get(`${mlrunAPIIngress}/projects/*/schedules`, getProjectsSchedules) app.get(`${mlrunAPIIngress}/projects/:project/schedules/:schedule`, getProjectsSchedule) app.delete(`${mlrunAPIIngress}/projects/:project/schedules/:schedule`, deleteSchedule) app.post(`${mlrunAPIIngress}/projects/:project/schedules/:schedule/invoke`, invokeSchedule) app.put(`${mlrunAPIIngress}/projects/:project/schedules/:schedule/`, updateSchedule) app.get(`${mlrunAPIIngress}/projects/:project/pipelines`, getPipelines) -app.get(`${mlrunAPIIngress}/projects/*/pipelines`, getPipelines) app.get(`${mlrunAPIIngress}/projects/:project/pipelines/:pipelineID`, getPipeline) app.post(`${mlrunAPIIngress}/projects/:project/pipelines/:pipelineID/retry`, pipelineRetry) app.post(`${mlrunAPIIngress}/projects/:project/pipelines/:pipelineID/terminate`, pipelineTerminate) @@ -3035,7 +3032,7 @@ app.get(`${mlrunAPIIngress}/projects/:project/functions/:func`, getFunc) app.post(`${mlrunAPIIngress}/projects/:project/functions/:func`, postFunc) app.get( - `${mlrunAPIIngress}/projects/:project/:featureArtifact/*/tags`, + `${mlrunAPIIngress}/projects/:project/:featureArtifact/:name/tags`, getProjectsFeatureArtifactTags ) diff --git a/vite.config.mjs b/vite.config.mjs index 20b71de28d..0a9b9907c3 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -59,7 +59,8 @@ export default defineConfig(({ mode }) => { 'igz-controls': path.resolve( __dirname, 'node_modules/iguazio.dashboard-react-controls/dist' - ) + ), + '@': path.resolve(__dirname, 'src') }, dedupe: [ 'react', From ae6e0570e0909e5b0dc7883601072130f59bb7bc Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Mon, 6 Oct 2025 14:55:56 +0300 Subject: [PATCH 176/228] migrated storybook --- .storybook/{main.js => main.mjs} | 20 +++--- eslint.config.mjs | 70 +++++++++---------- package.json | 18 +++-- .../{Button.stories.js => Button.stories.jsx} | 0 ...cker.stories.js => DatePicker.stories.jsx} | 0 .../{Input.stories.js => Input.stories.jsx} | 0 ...nput.stories.js => RangeInput.stories.jsx} | 0 .../{Select.stories.js => Select.stories.jsx} | 0 ...ton.stories.js => SplitButton.stories.jsx} | 0 .../{Link.stories.js => Link.stories.jsx} | 0 10 files changed, 55 insertions(+), 53 deletions(-) rename .storybook/{main.js => main.mjs} (77%) rename src/common/CodeBlock/{Button.stories.js => Button.stories.jsx} (100%) rename src/common/DatePicker/{DatePicker.stories.js => DatePicker.stories.jsx} (100%) rename src/common/Input/{Input.stories.js => Input.stories.jsx} (100%) rename src/common/RangeInput/{RangeInput.stories.js => RangeInput.stories.jsx} (100%) rename src/common/Select/{Select.stories.js => Select.stories.jsx} (100%) rename src/common/SplitButton/{SplitButton.stories.js => SplitButton.stories.jsx} (100%) rename src/stories/{Link.stories.js => Link.stories.jsx} (100%) diff --git a/.storybook/main.js b/.storybook/main.mjs similarity index 77% rename from .storybook/main.js rename to .storybook/main.mjs index e37d482385..c90b1ac53b 100644 --- a/.storybook/main.js +++ b/.storybook/main.mjs @@ -17,17 +17,17 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -const path = require('path') -module.exports = { - babel: async options => { - options.plugins.push('babel-plugin-inline-react-svg') - return options +const config = { + framework: { + name: '@storybook/react-vite', + options: {} }, stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: [ - '@storybook/addon-links', - '@storybook/addon-essentials', - '@storybook/preset-scss' - ] + addons: ['@storybook/addon-links', '@storybook/preset-scss', '@storybook/addon-docs'], + core: { + builder: '@storybook/builder-vite' + } } + +export default config diff --git a/eslint.config.mjs b/eslint.config.mjs index 6ec622e15d..ae533aa351 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,3 +1,4 @@ +import storybook from "eslint-plugin-storybook"; import eslintConfigPrettier from 'eslint-config-prettier' import globals from 'globals' import js from '@eslint/js' @@ -5,43 +6,38 @@ import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' import eslintPluginImport from 'eslint-plugin-import' -export default [ - { ignores: ['dist'] }, - js.configs.recommended, - eslintConfigPrettier, - { - files: ['**/*.{js,jsx,ts,tsx}'], - languageOptions: { - ecmaVersion: 2021, - globals: globals.browser, - parserOptions: { - ecmaFeatures: { - jsx: true - } +export default [{ ignores: ['dist'] }, js.configs.recommended, eslintConfigPrettier, { + files: ['**/*.{js,jsx,ts,tsx}'], + languageOptions: { + ecmaVersion: 2021, + globals: globals.browser, + parserOptions: { + ecmaFeatures: { + jsx: true } - }, - plugins: { - react: react, - 'react-hooks': reactHooks, - import: eslintPluginImport - }, - settings: { - react: { - version: 'detect' - } - }, - rules: { - ...reactHooks.configs.recommended.rules, - ...react.configs.recommended.rules, - 'react/react-in-jsx-scope': 'off', - 'react/no-unescaped-entities': 'off', - 'import/no-anonymous-default-export': 'off', - 'import/named': process.env.NODE_ENV === 'production' ? 2 : 1, - 'no-unused-vars': process.env.NODE_ENV === 'production' ? 2 : 1, - 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 1, - 'no-console': process.env.NODE_ENV === 'production' ? 2 : 1, - quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }], - semi: ['error', 'never'] } + }, + plugins: { + react: react, + 'react-hooks': reactHooks, + import: eslintPluginImport + }, + settings: { + react: { + version: 'detect' + } + }, + rules: { + ...reactHooks.configs.recommended.rules, + ...react.configs.recommended.rules, + 'react/react-in-jsx-scope': 'off', + 'react/no-unescaped-entities': 'off', + 'import/no-anonymous-default-export': 'off', + 'import/named': process.env.NODE_ENV === 'production' ? 2 : 1, + 'no-unused-vars': process.env.NODE_ENV === 'production' ? 2 : 1, + 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 1, + 'no-console': process.env.NODE_ENV === 'production' ? 2 : 1, + quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }], + semi: ['error', 'never'] } -] +}, ...storybook.configs["flat/recommended"]]; diff --git a/package.json b/package.json index d619d5881f..a8f3273b26 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "test:coverage": "npm run test -- --coverage --watchAll=false", "docker": "docker build -t ${MLRUN_DOCKER_REGISTRY}${MLRUN_DOCKER_REPO:-mlrun}/mlrun-ui:${MLRUN_DOCKER_TAG:-latest} --build-arg COMMIT_HASH=\"`git rev-parse --short HEAD`\" --build-arg DATE=\"`date -u`\" -f Dockerfile .", "generate-rn": "./generate-release-notes.js ${MLRUN_OLD_VERSION} ${MLRUN_VERSION} ${MLRUN_RELEASE_BRANCH} ${MLRUN_RELEASE_TYPE}", - "storybook": "start-storybook -p 6006", + "storybook": "storybook dev -p 6006", "build-storybook": "build-storybook", "mock-server": "node scripts/mockServer.js", "mock-server:dev": "nodemon --watch tests/mockServer scripts/mockServer.js", @@ -81,15 +81,16 @@ "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.28.3", + "@babel/preset-react": "^7.27.1", "@babel/register": "^7.28.3", "@cucumber/cucumber": "^10.3.1", "@d4c/numjs": "^0.17.34", "@eslint/js": "^9.36.0", - "@storybook/addon-actions": "^8.0.1", - "@storybook/addon-essentials": "^8.0.1", - "@storybook/addon-links": "^8.0.1", + "@storybook/addon-docs": "9.1.10", + "@storybook/addon-links": "^9.1.10", + "@storybook/builder-vite": "^9.1.10", "@storybook/preset-scss": "^1.0.3", - "@storybook/react": "^8.0.1", + "@storybook/react-vite": "^9.1.10", "@testing-library/dom": "^10.4.1", "@testing-library/react": "^16.3.0", "@vitejs/plugin-react": "^4.3.4", @@ -113,6 +114,7 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.22", + "eslint-plugin-storybook": "9.1.10", "express": "^5.1.0", "geckodriver": "^6.0.1", "globals": "^16.4.0", @@ -133,7 +135,7 @@ "stylelint-order": "^7.0.0", "stylelint-scss": "^6.12.1", "url-loader": "4.1.1", - "vite": "^6.2.0", + "vite": "^6.3.6", "vite-plugin-commonjs": "^0.10.4", "vite-plugin-eslint": "^1.8.1", "vite-plugin-svgr": "^4.5.0" @@ -149,6 +151,10 @@ "useBuiltIns": "usage", "corejs": "^3.23.3" } + ], + [ + "@babel/preset-react", + {} ] ] } diff --git a/src/common/CodeBlock/Button.stories.js b/src/common/CodeBlock/Button.stories.jsx similarity index 100% rename from src/common/CodeBlock/Button.stories.js rename to src/common/CodeBlock/Button.stories.jsx diff --git a/src/common/DatePicker/DatePicker.stories.js b/src/common/DatePicker/DatePicker.stories.jsx similarity index 100% rename from src/common/DatePicker/DatePicker.stories.js rename to src/common/DatePicker/DatePicker.stories.jsx diff --git a/src/common/Input/Input.stories.js b/src/common/Input/Input.stories.jsx similarity index 100% rename from src/common/Input/Input.stories.js rename to src/common/Input/Input.stories.jsx diff --git a/src/common/RangeInput/RangeInput.stories.js b/src/common/RangeInput/RangeInput.stories.jsx similarity index 100% rename from src/common/RangeInput/RangeInput.stories.js rename to src/common/RangeInput/RangeInput.stories.jsx diff --git a/src/common/Select/Select.stories.js b/src/common/Select/Select.stories.jsx similarity index 100% rename from src/common/Select/Select.stories.js rename to src/common/Select/Select.stories.jsx diff --git a/src/common/SplitButton/SplitButton.stories.js b/src/common/SplitButton/SplitButton.stories.jsx similarity index 100% rename from src/common/SplitButton/SplitButton.stories.js rename to src/common/SplitButton/SplitButton.stories.jsx diff --git a/src/stories/Link.stories.js b/src/stories/Link.stories.jsx similarity index 100% rename from src/stories/Link.stories.js rename to src/stories/Link.stories.jsx From 8f6bb42ff6c98fcd090fd1f2975c54d063ef8ad8 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Tue, 7 Oct 2025 13:49:26 +0300 Subject: [PATCH 177/228] fix some stories --- .../{Button.stories.jsx => CodeBlock.stories.jsx} | 2 ++ src/common/Input/Input.stories.jsx | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) rename src/common/CodeBlock/{Button.stories.jsx => CodeBlock.stories.jsx} (96%) diff --git a/src/common/CodeBlock/Button.stories.jsx b/src/common/CodeBlock/CodeBlock.stories.jsx similarity index 96% rename from src/common/CodeBlock/Button.stories.jsx rename to src/common/CodeBlock/CodeBlock.stories.jsx index b976ff22e6..586dd32928 100644 --- a/src/common/CodeBlock/Button.stories.jsx +++ b/src/common/CodeBlock/CodeBlock.stories.jsx @@ -21,6 +21,8 @@ import React from 'react' import CodeBlock from './CodeBlock' +import 'prismjs/components/prism-json' + export default { title: 'Example/CodeBlock', component: CodeBlock diff --git a/src/common/Input/Input.stories.jsx b/src/common/Input/Input.stories.jsx index 081e5ce056..8fdcc35de3 100644 --- a/src/common/Input/Input.stories.jsx +++ b/src/common/Input/Input.stories.jsx @@ -98,8 +98,8 @@ ChunkyMandatory.args = { requiredText: 'Field is required' } -export const withValidationRules = Template.bind({}) -withValidationRules.args = { +export const WithValidationRules = Template.bind({}) +WithValidationRules.args = { ...commonArgs, density: 'chunky', invalid: true, @@ -110,8 +110,8 @@ withValidationRules.args = { value: ' test#2!' } -export const withStaticLink = Template.bind({}) -withStaticLink.args = { +export const WithStaticLink = Template.bind({}) +WithStaticLink.args = { ...commonArgs, label: 'label with static link', link: { @@ -121,9 +121,9 @@ withStaticLink.args = { value: 'test' } -export const withDynamicLink = Template.bind({}) +export const WithDynamicLink = Template.bind({}) const value = 'some text' -withDynamicLink.args = { +WithDynamicLink.args = { ...commonArgs, label: 'label with dynamic link', link: { From 3ddc08573fc98e694cc63d86b41ef6ab949aa670 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Wed, 8 Oct 2025 12:05:41 +0300 Subject: [PATCH 178/228] Fix [LLM Prompts] Update mock for LLM prompts (#3457) --- tests/mockServer/data/artifacts.json | 39 ++++++ tests/mockServer/data/funcs.json | 176 +++++++++++++++++++++++++++ tests/mockServer/mock.js | 46 ++++++- 3 files changed, 257 insertions(+), 4 deletions(-) diff --git a/tests/mockServer/data/artifacts.json b/tests/mockServer/data/artifacts.json index 252810c342..164488df06 100644 --- a/tests/mockServer/data/artifacts.json +++ b/tests/mockServer/data/artifacts.json @@ -40132,6 +40132,45 @@ }, "project": "llmdeploy332" }, + { + "kind": "model", + "metadata": { + "key": "model_art1", + "project": "llmdeploy332", + "iter": 0, + "tree": "418c1ad0-ab41-45df-afb9-722d48d5d65a", + "hash": "dae3b5936acdb82b153b8a17d7d71ba7a66b6b60", + "uid": "bff98dcfd64bd3db006488b7808e9d2dcf37b56f", + "updated": "2025-08-11 11:56:12.178000+00:00", + "created": "2025-08-11 11:56:12.178000+00:00", + "tag": "v1" + }, + "spec": { + "target_path": "llmdeploy332/model_art1/", + "size": 4370, + "license": "", + "framework": "", + "producer": { + "kind": "project", + "name": "llmdeploy332", + "tag": "418c1ad0-ab41-45df-afb9-722d48d5d65a", + "owner": "normal-user" + }, + "model_file": "RandomForestClassifier_file1.pkl", + "has_children": true, + "db_key": "model_art1", + "parameters": { + "default_config": { + "model_version": "4" + } + }, + "parent_uri": null + }, + "status": { + "state": "created" + }, + "project": "llmdeploy332" + }, { "kind": "llm-prompt", "metadata": { diff --git a/tests/mockServer/data/funcs.json b/tests/mockServer/data/funcs.json index 39f903838e..5fc69eb92f 100644 --- a/tests/mockServer/data/funcs.json +++ b/tests/mockServer/data/funcs.json @@ -30401,6 +30401,182 @@ "state": null }, "kind": "job" + }, + { + "status": { + "nuclio_name": "llmdeploy332-function-with-llm", + "internal_invocation_urls": [ + "nuclio-llmdeploy332-function-with-llm.default-tenant.svc.cluster.local:8080" + ], + "address": "llmdeploy332-function-with-llm.default-tenant.app.vmdev36.lab.iguazeng.com/", + "container_image": "docker-registry.default-tenant.app.vmdev36.lab.iguazeng.com:80/nuclio/llmdeploy332-llmdeploy332-function-with-llm-processor:latest", + "external_invocation_urls": [ + "llmdeploy332-function-with-llm.default-tenant.app.vmdev36.lab.iguazeng.com/" + ], + "state": "ready" + }, + "metadata": { + "credentials": { + "access_key": "$ref:mlrun-auth-secrets.5d8a1734cc89d6337fde8ee93c9a2649613519b15ed817fb3e8ecc47" + }, + "project": "llmdeploy332", + "name": "function-with-llm", + "tag": "latest", + "hash": "fc40337727c37256a3d81cb6114515bf3239fb17", + "updated": "2025-08-11T11:58:14.322000+00:00", + "uid": "unversioned-latest" + }, + "spec": { + "function_kind": "serving_v2", + "min_replicas": 1, + "image": "mlrun/mlrun", + "base_image_pull": false, + "command": "http://llmdeploy332-function-with-llm.default-tenant.app.vmdev36.lab.iguazeng.com/", + "disable_auto_mount": true, + "function_handler": "function-with-llm-nuclio:handler", + "default_handler": "", + "description": "", + "max_replicas": 4, + "preemption_mode": "prevent", + "priority_class_name": "igz-workload-medium", + "build": { + "code_origin": "./function_with_llm.py", + "secret": "", + "functionSourceCode": "IyBDb3B5cmlnaHQgMjAyNSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAojCiMgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQojIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiMgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAojIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgoKZnJvbSBtbHJ1bi5zZXJ2aW5nIGltcG9ydCBMTE1vZGVsCmltcG9ydCBtbHJ1biAKZnJvbSBtbHJ1bi51dGlscyBpbXBvcnQgbG9nZ2VyCmZyb20gbWxydW4uc2VydmluZy5zdGF0ZXMgaW1wb3J0IE1vZGVsLCBNb2RlbFJ1bm5lclN0ZXAsIE1vZGVsU2VsZWN0b3IKZnJvbSB0eXBpbmcgaW1wb3J0IE9wdGlvbmFsCgpjbGFzcyBNeU1vZGVsU2VsZWN0b3IoTW9kZWxTZWxlY3Rvcik6CiAgICBkZWYgc2VsZWN0KHNlbGYsIGV2ZW50LCBhdmFpbGFibGVfbW9kZWxzOiBsaXN0W01vZGVsXSkgLT4gT3B0aW9uYWxbbGlzdFtzdHJdXToKICAgICAgICByZXR1cm4gZXZlbnQuYm9keS5nZXQoIm1vZGVscyIpCgpjbGFzcyBNeUxMTShMTE1vZGVsKToKICAgIGRlZiBwcmVkaWN0KHNlbGYsIGJvZHksIG1lc3NhZ2VzLCBtb2RlbF9jb25maWd1cmF0aW9uKToKICAgICAgICBib2R5WyJ1cmwiXSA9IHNlbGYubW9kZWxfYXJ0aWZhY3QubW9kZWxfdXJsCiAgICAgICAgYm9keVsiZGVmYXVsdF9jb25maWciXSA9IHNlbGYubW9kZWxfYXJ0aWZhY3QuZGVmYXVsdF9jb25maWcKICAgICAgICBib2R5WyJwcm9tcHQiXSA9IG1lc3NhZ2VzCiAgICAgICAgcmV0dXJuIGJvZHkKICAgIAojZnJvbSBtbHJ1bi5zZXJ2aW5nIGltcG9ydCBMTE1vZGVsCgpjbGFzcyBNeUxMTUNvbmZpZyhMTE1vZGVsKTogICAgICAgIAogICAgZGVmIHByZWRpY3Qoc2VsZiwgYm9keSwgbWVzc2FnZXMsIG1vZGVsX2NvbmZpZ3VyYXRpb24pOgogICAgICAgIHByb21wdF9hcnRpZmFjdCA9IGdldGF0dHIoc2VsZiwgImludm9jYXRpb25fYXJ0aWZhY3QiLCBOb25lKQogICAgICAgIG1vZGVsX2FydGlmYWN0ID0gZ2V0YXR0cihzZWxmLCAibW9kZWxfYXJ0aWZhY3QiLCBOb25lKQoKICAgICAgICByZXR1cm4gewogICAgICAgICAgICAiaW5wdXRzIjogYm9keSwKICAgICAgICAgICAgInByb21wdCI6IG1lc3NhZ2VzLAogICAgICAgICAgICAibW9kZWxfY29uZmlnIjogbW9kZWxfY29uZmlndXJhdGlvbiwKICAgICAgICAgICAgImRlZmF1bHRfY29uZmlnIjogZ2V0YXR0cihtb2RlbF9hcnRpZmFjdCwgImRlZmF1bHRfY29uZmlnIiwge30pLAogICAgICAgICAgICAibGFiZWxzIjogZ2V0YXR0cihwcm9tcHRfYXJ0aWZhY3QsICJsYWJlbHMiLCB7fSksCiAgICAgICAgICAgICJ0ZW1wbGF0ZV9wYXJhbXMiOiBnZXRhdHRyKHByb21wdF9hcnRpZmFjdCwgInRlbXBsYXRlX3BhcmFtcyIsIHt9KSwKICAgICAgICB9CiAgICAKY2xhc3MgTXlMTE1Db25maWcxKExMTW9kZWwpOgogICAgZGVmIGxvYWQoc2VsZik6CiAgICAgICAgcGFzcwogICAgICAgIAogICAgZGVmIHByZWRpY3Qoc2VsZiwgYm9keSwgbWVzc2FnZXMsIG1vZGVsX2NvbmZpZ3VyYXRpb24pOgogICAgICAgIHByb21wdF9hcnRpZmFjdCA9IGdldGF0dHIoc2VsZiwgImludm9jYXRpb25fYXJ0aWZhY3QiLCBOb25lKQogICAgICAgIG1vZGVsX2FydGlmYWN0ID0gZ2V0YXR0cihzZWxmLCAibW9kZWxfYXJ0aWZhY3QiLCBOb25lKQoKICAgICAgICByZXR1cm4gewogICAgICAgICAgICAiaW5wdXRzIjogYm9keSwKICAgICAgICAgICAgInByb21wdCI6IG1lc3NhZ2VzLAogICAgICAgICAgICAibW9kZWxfY29uZmlnIjogbW9kZWxfY29uZmlndXJhdGlvbiwKICAgICAgICAgICAgImRlZmF1bHRfY29uZmlnIjogZ2V0YXR0cihtb2RlbF9hcnRpZmFjdCwgImRlZmF1bHRfY29uZmlnIiwge30pLAogICAgICAgICAgICAibGFiZWxzIjogZ2V0YXR0cihwcm9tcHRfYXJ0aWZhY3QsICJsYWJlbHMiLCB7fSksCiAgICAgICAgICAgICJ0ZW1wbGF0ZV9wYXJhbXMiOiBnZXRhdHRyKHByb21wdF9hcnRpZmFjdCwgInRlbXBsYXRlX3BhcmFtcyIsIHt9KSwKICAgICAgICB9CmZyb20gbWxydW4ucnVudGltZXMgaW1wb3J0IG51Y2xpb19pbml0X2hvb2sKZGVmIGluaXRfY29udGV4dChjb250ZXh0KToKICAgIG51Y2xpb19pbml0X2hvb2soY29udGV4dCwgZ2xvYmFscygpLCAnc2VydmluZ192MicpCgpkZWYgaGFuZGxlcihjb250ZXh0LCBldmVudCk6CiAgICByZXR1cm4gY29udGV4dC5tbHJ1bl9oYW5kbGVyKGNvbnRleHQsIGV2ZW50KQo=", + "origin_filename": "./function_with_llm.py" + }, + "source": "", + "graph": { + "engine": "async", + "shared_models_mechanism": { + "model-deployment": "naive" + }, + "shared_models": { + "model-deployment": [ + "MyLLM", + { + "name": "model-deployment", + "artifact_uri": "store://models/llmdeploy332/model_art1#0@418c1ad0-ab41-45df-afb9-722d48d5d65a^bff98dcfd64bd3db006488b7808e9d2dcf37b56f" + } + ] + }, + "track_models": false, + "model_endpoints_names": [ + "my-endpoint" + ], + "steps": { + "model-runner": { + "class_args": { + "model_selector": null, + "execution_mechanism_by_model_name": { + "my-endpoint": "shared_executor" + }, + "models": { + "my-endpoint": [ + "mlrun.serving.Model", + { + "name": "my-endpoint", + "shared_runnable_name": "model-deployment", + "artifact_uri": "store://llm-prompts/llmdeploy332/my_llm#0@c00325f6-c2cb-4c62-ad93-8d5de6d0d10d^1d459c52a1102adcbbe242e6bb36e99129f2a8b9" + } + ] + }, + "monitoring_data": { + "my-endpoint": { + "inputs": null, + "outputs": [], + "input_path": null, + "result_path": null, + "creation_strategy": "inplace", + "labels": null, + "model_path": "store://llm-prompts/llmdeploy332/my_llm#0@c00325f6-c2cb-4c62-ad93-8d5de6d0d10d^1d459c52a1102adcbbe242e6bb36e99129f2a8b9", + "model_class": "mlrun.serving.Model", + "model_endpoint_uid": "b2a773fdd4a94719850102cfffb25601" + } + } + }, + "class_name": "mlrun.serving.ModelRunner", + "responder": true, + "endpoint_type": 1, + "shape": "folder", + "model_endpoint_creation_strategy": "skip", + "raise_exception": true, + "kind": "model_runner", + "_shared_proxy_mapping": { + "model-deployment": { + "my-endpoint": "store://llm-prompts/llmdeploy332/my_llm#0@c00325f6-c2cb-4c62-ad93-8d5de6d0d10d^1d459c52a1102adcbbe242e6bb36e99129f2a8b9" + } + } + } + } + }, + "affinity": null, + "volumes": [ + { + "name": "serving-conf", + "configMap": { + "name": "serving-conf-llmdeploy332-function-with-llm" + } + } + ], + "resources": { + "requests": { + "memory": "1Mi", + "cpu": "25m" + }, + "limits": { + "memory": "20Gi", + "cpu": "2" + } + }, + "tolerations": null, + "env": [ + { + "name": "MLRUN_HTTPDB__NUCLIO__EXPLICIT_ACK", + "value": "enabled" + }, + { + "name": "V3IO_API", + "value": "v3io-webapi.default-tenant.svc:8081" + }, + { + "name": "V3IO_USERNAME", + "value": "normal-user" + }, + { + "name": "V3IO_FRAMESD", + "value": "framesd:8081" + }, + { + "name": "V3IO_ACCESS_KEY", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.bd42717290ba28bb58f058523ca25adff9762c83ad2a60157d7478db" + } + } + }, + { + "name": "MLRUN_AUTH_SESSION", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.5d8a1734cc89d6337fde8ee93c9a2649613519b15ed817fb3e8ecc47" + } + } + } + ], + "volume_mounts": [ + { + "name": "serving-conf", + "mountPath": "/tmp/mlrun/serving-conf", + "readOnly": true + } + ], + "node_selector": {} + }, + "verbose": false, + "kind": "serving" } ] } diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 9c3e8d1b30..beee93cf01 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -1486,6 +1486,7 @@ function getArtifacts(req, res) { collectedArtifacts = collectedArtifacts.filter(artifact => { if (req.query['name'].includes('~')) { const value = artifact.spec?.db_key ?? artifact.db_key + if (req.query['name'].includes('~')) { return value.includes(req.query['name'].slice(1)) } else { @@ -1515,9 +1516,44 @@ function getArtifacts(req, res) { } } + if (req.query['tree']) { + collectedArtifacts = collectedArtifacts.filter( + artifact => artifact.metadata?.tree === req.query['tree'] + ) + } + + if (req.query['parent']) { + if (req.query['parent'].includes(':')) { + const [key, tag] = req.query['parent'].split(':') + + collectedArtifacts = collectedArtifacts.filter(artifact => { + const match = artifact.spec.parent_uri.match( + /^store:\/\/(?.+?)\/(?.+?)\/(?.+?)(#(?.+?))?(:(?.+?))?(@(?[^^]+))?(\^(?.+))?$/ + ) + + return match && match.groups.key.startsWith(key) && match.groups.tag === tag + }) + } else { + collectedArtifacts = collectedArtifacts.filter(artifact => + artifact.spec?.parent_uri + ?.match(/^store:\/\/[^/]+\/[^/]+\/([^#/]+)/)?.[1] + ?.startsWith(req.query['parent']) + ) + } + } + if (req.query['format'] === 'minimal') { collectedArtifacts = collectedArtifacts.map(func => { - const fieldsToPick = ['db_key', 'producer', 'size', 'target_path', 'framework', 'metrics'] + const fieldsToPick = [ + 'db_key', + 'producer', + 'size', + 'target_path', + 'framework', + 'metrics', + 'has_children', + 'parent_uri' + ] const specFieldsToPick = fieldsToPick.map(fieldName => `spec.${fieldName}`) return pick(func, [ @@ -1944,7 +1980,9 @@ function getFunc(req, res) { let collectedFuncs = funcs.funcs .filter(func => func.metadata.project === req.params['project']) .filter(func => func.metadata.name === req.params['func']) - .filter(func => func.metadata.hash === req.query.hash_key) + .filter( + func => func.metadata.hash === req.query.hash_key || func.metadata.uid === req.query.hash_key + ) if (req.query.tag) { collectedFuncs = collectedFuncs.filter(func => func.metadata.tag === req.query.tag) @@ -2590,8 +2628,8 @@ function getModelEndpoints(req, res) { } if (req.query['mode']) { - collectedEndpoints = collectedEndpoints.filter(endpoint => - Number(endpoint.metadata.mode) === Number(req.query['mode']) + collectedEndpoints = collectedEndpoints.filter( + endpoint => Number(endpoint.metadata.mode) === Number(req.query['mode']) ) } From 6b7b839c25437f853a04879e19c75eaff51ca488 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Wed, 8 Oct 2025 12:06:35 +0300 Subject: [PATCH 179/228] =?UTF-8?q?Impl=20[UI]=20=E2=80=9CMonitoring=20app?= =?UTF-8?q?s=E2=80=9D=20counter=20mismatch=20(#3456)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoringApplicationCounters.util.jsx | 15 ++--- src/reducers/projectReducer.js | 23 +++++-- src/utils/applications.utils.js | 61 ++++++++++++++----- 3 files changed, 70 insertions(+), 29 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index 77cdf96acd..b0db895f48 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -19,16 +19,14 @@ such restriction. */ import { capitalize } from 'lodash' +import { aggregateApplicationStatuses } from '../../../../utils/applications.utils' import { formatMinutesToString } from '../../../../utils/measureTime' import { BATCH_FILTER, - ERROR_STATE, - FUNCTION_READY_STATE, ME_MODE_FILTER, MODEL_ENDPOINTS_TAB, MODELS_PAGE, - REAL_TIME_FILTER, - UNHEALTHY_STATE + REAL_TIME_FILTER } from '../../../../constants' export const generateCountersContent = (params, monitoringApplicationsStore) => { @@ -39,13 +37,8 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => loading: monitoringApplicationIsLoading, error: monitoringApplicationError } = monitoringApplicationsStore - - const { ready: appReady, error: appError } = monitoringApplications.applications.reduce( - (acc, { status }) => ({ - ready: acc.ready + (status === FUNCTION_READY_STATE ? 1 : 0), - error: acc.error + ([ERROR_STATE, UNHEALTHY_STATE].includes(status) ? 1 : 0) - }), - { ready: 0, error: 0 } + const { ready: appReady, error: appError } = aggregateApplicationStatuses( + monitoringApplications.applications ) const applicationsCountersContent = [ diff --git a/src/reducers/projectReducer.js b/src/reducers/projectReducer.js index 05ce577d1e..c596a74153 100644 --- a/src/reducers/projectReducer.js +++ b/src/reducers/projectReducer.js @@ -19,6 +19,7 @@ such restriction. */ import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' +import nuclioApi from '../api/nuclio' import projectsApi from '../api/projects-api' import { hideLoading, showLoading } from './redux.util' import { @@ -31,6 +32,7 @@ import { parseProjects } from '../utils/parseProjects' import { showErrorNotification } from 'igz-controls/utils/notification.util' import { parseSummaryData } from '../utils/parseSummaryData' import { mlrunUnhealthyErrors } from '../components/ProjectsPage/projects.util' +import { aggregateApplicationStatuses, splitApplicationsContent } from '../utils/applications.utils' const initialState = { deletingProjects: {}, @@ -248,10 +250,23 @@ export const fetchProjectSecrets = createAsyncThunk( export const fetchProjectSummary = createAsyncThunk( 'fetchProjectSummary', ({ project, signal }, thunkAPI) => { - return projectsApi - .getProjectSummary(project, signal) - .then(({ data }) => { - return parseSummaryData(data) + return Promise.all([ + projectsApi.getProjectSummary(project, signal), + nuclioApi.getFunctions(project) + ]) + .then(([projectSummary, nuclioFunctions]) => { + const parsedProjectSummary = parseSummaryData(projectSummary.data) + const { ready: runningAppsNumber, error: failedAppsNumber } = aggregateApplicationStatuses( + splitApplicationsContent(nuclioFunctions.data).applications + ) + + return { + ...parsedProjectSummary, + running_model_monitoring_functions: + runningAppsNumber ?? parsedProjectSummary.running_model_monitoring_functions, + failed_model_monitoring_functions: + failedAppsNumber ?? parsedProjectSummary.failed_model_monitoring_functions + } }) .catch(error => { if (![REQUEST_CANCELED, DEFAULT_ABORT_MSG].includes(error.message)) { diff --git a/src/utils/applications.utils.js b/src/utils/applications.utils.js index 9df80994a1..1216600cc8 100644 --- a/src/utils/applications.utils.js +++ b/src/utils/applications.utils.js @@ -17,25 +17,58 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import { isArray, clone } from 'lodash' + +import { ERROR_STATE, FUNCTION_READY_STATE, UNHEALTHY_STATE } from '../constants' + const OPERATING_FUNCTIONS_NAMES_LIST = [ - 'model-monitoring-controller', - 'model-monitoring-stream', - 'model-monitoring-writer' + 'model-monitoring-controller', + 'model-monitoring-stream', + 'model-monitoring-writer' +] +const NUCLIO_FUNCTIONS_MLRUN_TYPES = [ + 'mlrun__model-monitoring-application', + 'mlrun__model-monitoring-infra' ] export const splitApplicationsContent = (functions = []) => { - const monitoringApplicationsData = { - operatingFunctions: [], - applications: [] - } + const monitoringApplicationsData = { + operatingFunctions: [], + applications: [] + } + let workingFunctions = clone(functions) - functions.forEach(func => { - if (OPERATING_FUNCTIONS_NAMES_LIST.includes(func.name)) { - monitoringApplicationsData.operatingFunctions.push(func) - } else { - monitoringApplicationsData.applications.push(func) - } + if (!isArray(functions)) { + workingFunctions = Object.values(functions).filter(app => { + return NUCLIO_FUNCTIONS_MLRUN_TYPES.includes(app.metadata.labels['mlrun__type']) }) + } + + workingFunctions.forEach(func => { + const funcName = func.name + ? func.name + : func.metadata.name.replace(`${func.metadata.labels['nuclio.io/project-name']}-`, '') + + if (OPERATING_FUNCTIONS_NAMES_LIST.includes(funcName)) { + monitoringApplicationsData.operatingFunctions.push(func) + } else { + monitoringApplicationsData.applications.push(func) + } + }) + + return monitoringApplicationsData +} + +export const aggregateApplicationStatuses = monitoringApplications => { + return monitoringApplications.reduce( + (acc, application) => { + const status = application.status.state ? application.status.state : application.status - return monitoringApplicationsData + return { + ready: acc.ready + (status === FUNCTION_READY_STATE ? 1 : 0), + error: acc.error + ([ERROR_STATE, UNHEALTHY_STATE].includes(status) ? 1 : 0) + } + }, + { ready: 0, error: 0 } + ) } From 4cf7fa5bf8a8843cb126944e4fc2ab972a1d7aac Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:51:44 +0300 Subject: [PATCH 180/228] Fix [UI] Unexpected 'jobs' presentation for scheduled jobs link (#3453) --- .../MultiSelectFilter.jsx} | 38 +++++++++---------- src/components/Alerts/AlertsFilters.jsx | 24 ++++++------ .../Jobs/MonitorJobs/JobsFilters.jsx | 8 ++-- .../MonitorWorkflows/WorkflowsFilters.jsx | 4 +- .../ScheduledJobs/ScheduledJobsFilters.jsx | 11 ++---- .../JobsMonitoring/JobsMonitoringFilters.jsx | 4 +- .../ScheduledMonitoring.jsx | 4 +- .../ScheduledMonitoringFilters.jsx | 10 ++--- .../WorkflowsMonitoringFilters.jsx | 4 +- src/hooks/useJobsPageData.js | 2 +- src/types.js | 10 +++-- src/utils/generateMonitoringData.js | 6 ++- src/utils/jobs.util.jsx | 13 +++++-- 13 files changed, 71 insertions(+), 67 deletions(-) rename src/common/{StatusFilter/StatusFilter.jsx => MultiSelectFilter/MultiSelectFilter.jsx} (66%) diff --git a/src/common/StatusFilter/StatusFilter.jsx b/src/common/MultiSelectFilter/MultiSelectFilter.jsx similarity index 66% rename from src/common/StatusFilter/StatusFilter.jsx rename to src/common/MultiSelectFilter/MultiSelectFilter.jsx index 9ad186e76b..00adc99e08 100644 --- a/src/common/StatusFilter/StatusFilter.jsx +++ b/src/common/MultiSelectFilter/MultiSelectFilter.jsx @@ -21,23 +21,23 @@ import { isEmpty, capitalize } from 'lodash' import { FormOnChange, FormSelect } from 'igz-controls/components' import { FILTER_ALL_ITEMS } from '../../constants' -import { STATUS_LIST } from '../../types' +import { OPTIONS_LIST } from '../../types' -// TODO: Rename component from StatusFilter to a more generic name -const StatusFilter = ({ statusList, name }) => { +// TODO: Rename component from MultiSelectFilter to a more generic name +const MultiSelectFilter = ({ optionsList, name }) => { const { input } = useField(name) const { change } = useForm() - const mappedStatusList = useMemo(() => { - const isAllStatusSelected = input.value?.includes?.(FILTER_ALL_ITEMS) - return isAllStatusSelected - ? statusList.map(status => - status.id === FILTER_ALL_ITEMS ? { ...status, disabled: true } : status - ) - : statusList - }, [input.value, statusList]) + const mappedOptionsList = useMemo(() => { + const isAllOptionsSelected = input.value?.includes?.(FILTER_ALL_ITEMS) + return isAllOptionsSelected + ? optionsList.map(option => + option.id === FILTER_ALL_ITEMS ? { ...option, disabled: true } : option + ) + : optionsList + }, [input.value, optionsList]) - const handleFilterStateChange = (selectedValue, currentValue) => { + const handleFilterOptionChange = (selectedValue, currentValue) => { if ( selectedValue.length > 1 && selectedValue.includes(FILTER_ALL_ITEMS) && @@ -52,8 +52,8 @@ const StatusFilter = ({ statusList, name }) => { (!currentValue.includes(FILTER_ALL_ITEMS) && selectedValue.includes(FILTER_ALL_ITEMS) && selectedValue.indexOf(FILTER_ALL_ITEMS) > 0) || - mappedStatusList.filter(option => option.id !== FILTER_ALL_ITEMS).length === - selectedValue.length + mappedOptionsList.filter(option => option.id !== FILTER_ALL_ITEMS).length === + selectedValue.length ) { change(name, [FILTER_ALL_ITEMS]) } @@ -61,15 +61,15 @@ const StatusFilter = ({ statusList, name }) => { return ( <> - - handleFilterStateChange(value, some)} name={name} /> + + handleFilterOptionChange(value, some)} name={name} /> ) } -StatusFilter.propTypes = { +MultiSelectFilter.propTypes = { name: PropTypes.string.isRequired, - statusList: STATUS_LIST.isRequired + optionsList: OPTIONS_LIST.isRequired } -export default memo(StatusFilter) +export default memo(MultiSelectFilter) diff --git a/src/components/Alerts/AlertsFilters.jsx b/src/components/Alerts/AlertsFilters.jsx index 6849b05603..de6ce8e86c 100644 --- a/src/components/Alerts/AlertsFilters.jsx +++ b/src/components/Alerts/AlertsFilters.jsx @@ -24,7 +24,7 @@ import PropTypes from 'prop-types' import { useForm, useFormState } from 'react-final-form' import { upperFirst } from 'lodash' -import StatusFilter from '../../common/StatusFilter/StatusFilter' +import MultiSelectFilter from '../../common/MultiSelectFilter/MultiSelectFilter' import { FormSelect, FormInput, FormOnChange } from 'igz-controls/components' import { generateProjectsList } from '../../utils/projects' @@ -127,16 +127,16 @@ const AlertsFilters = ({ isAlertsPage, isCrossProjects }) => { {(entityType === FILTER_ALL_ITEMS || entityType === MODEL_MONITORING_APPLICATION || entityType === MODEL_ENDPOINT_RESULT) && ( -
      - - handleInputChange(value, ENTITY_ID)} name={ENTITY_ID} /> -
      - )} +
      + + handleInputChange(value, ENTITY_ID)} name={ENTITY_ID} /> +
      + )} {entityType === JOB && (
      { )}
      - +
      { @@ -36,12 +36,12 @@ const JobsFilters = () => { return (
      - +
      diff --git a/src/components/Jobs/MonitorWorkflows/WorkflowsFilters.jsx b/src/components/Jobs/MonitorWorkflows/WorkflowsFilters.jsx index 32586df3ca..1f3f90fead 100644 --- a/src/components/Jobs/MonitorWorkflows/WorkflowsFilters.jsx +++ b/src/components/Jobs/MonitorWorkflows/WorkflowsFilters.jsx @@ -21,7 +21,7 @@ import React from 'react' import { useForm } from 'react-final-form' import { FormInput, FormOnChange } from 'igz-controls/components' -import StatusFilter from '../../../common/StatusFilter/StatusFilter' +import MultiSelectFilter from '../../../common/MultiSelectFilter/MultiSelectFilter' import { LABELS_FILTER, STATUS_FILTER_NAME } from '../../../constants' import { workflowsStatuses } from '../../FilterMenu/filterMenu.settings' @@ -38,7 +38,7 @@ const WorkflowsFilters = () => { return (
      - +
      {isDemoMode && (
      diff --git a/src/components/Jobs/ScheduledJobs/ScheduledJobsFilters.jsx b/src/components/Jobs/ScheduledJobs/ScheduledJobsFilters.jsx index 69163fbeb4..ef6c4952de 100644 --- a/src/components/Jobs/ScheduledJobs/ScheduledJobsFilters.jsx +++ b/src/components/Jobs/ScheduledJobs/ScheduledJobsFilters.jsx @@ -20,9 +20,10 @@ such restriction. import React from 'react' import { useForm } from 'react-final-form' -import { FormInput, FormOnChange, FormSelect } from 'igz-controls/components' +import MultiSelectFilter from '../../../common/MultiSelectFilter/MultiSelectFilter' +import { FormInput, FormOnChange } from 'igz-controls/components' -import { JOBS_MONITORING_SCHEDULED_TAB, LABELS_FILTER } from '../../../constants' +import { JOBS_MONITORING_SCHEDULED_TAB, LABELS_FILTER, TYPE_FILTER } from '../../../constants' import { generateTypeFilter } from '../../FilterMenu/filterMenu.settings' const ScheduledJobsFilters = () => { @@ -35,11 +36,7 @@ const ScheduledJobsFilters = () => { return (
      - +
      {
      )}
      - +
      { } = React.useContext(ProjectJobsMonitoringContext) const filters = useFiltersFromSearchParams( - initialTabData[JOBS_MONITORING_SCHEDULED_TAB]?.filtersConfig, - initialTabData[JOBS_MONITORING_SCHEDULED_TAB]?.parseQueryParamsCallback + initialTabData?.[JOBS_MONITORING_SCHEDULED_TAB]?.filtersConfig, + initialTabData?.[JOBS_MONITORING_SCHEDULED_TAB]?.parseQueryParamsCallback ) useEffect(() => { diff --git a/src/components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoringFilters.jsx b/src/components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoringFilters.jsx index 4fecfc6b65..79a0779335 100644 --- a/src/components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoringFilters.jsx +++ b/src/components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoringFilters.jsx @@ -22,6 +22,7 @@ import { useForm } from 'react-final-form' import { upperFirst } from 'lodash' import { useSelector } from 'react-redux' +import MultiSelectFilter from '../../../common/MultiSelectFilter/MultiSelectFilter' import { FormInput, FormOnChange, FormSelect } from 'igz-controls/components' import { @@ -29,7 +30,8 @@ import { JOBS_MONITORING_SCHEDULED_TAB, LABELS_FILTER, PROJECT_FILTER, - PROJECTS_FILTER_ALL_ITEMS + PROJECTS_FILTER_ALL_ITEMS, + TYPE_FILTER } from '../../../constants' import { generateTypeFilter } from '../../FilterMenu/filterMenu.settings' import { generateProjectsList } from '../../../utils/projects' @@ -65,11 +67,7 @@ const ScheduledMonitoringFilters = () => { />
      - +
      { />
      - +
      {isDemoMode && (
      diff --git a/src/hooks/useJobsPageData.js b/src/hooks/useJobsPageData.js index db077b3a86..75de737b40 100644 --- a/src/hooks/useJobsPageData.js +++ b/src/hooks/useJobsPageData.js @@ -215,7 +215,7 @@ export const useJobsPageData = (initialTabData, selectedTab) => { .map(job => parseJob(job, SCHEDULE_TAB)) .filter(job => { return ( - !filters.type || filters.type === FILTER_ALL_ITEMS || job.type === filters.type + !filters.type || filters.type === FILTER_ALL_ITEMS || job.type === filters.type || (Array.isArray(filters.type) && filters.type.includes(job.type) || filters.type.includes(FILTER_ALL_ITEMS)) ) }) diff --git a/src/types.js b/src/types.js index dfe6c0400f..7777d03436 100644 --- a/src/types.js +++ b/src/types.js @@ -18,6 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import PropTypes from 'prop-types' +import {isEmpty} from 'lodash' import { BE_PAGE, BE_PAGE_SIZE, @@ -26,7 +27,8 @@ import { PANEL_CREATE_MODE, PANEL_EDIT_MODE, PANEL_FUNCTION_CREATE_MODE, - PANEL_RERUN_MODE + PANEL_RERUN_MODE, + STATUS_FILTER_NAME } from './constants' import { BUTTON_VARIANTS } from 'igz-controls/types' @@ -205,12 +207,12 @@ export const FILTERS_CONFIG = PropTypes.objectOf( }) ) -export const STATUS_LIST = PropTypes.arrayOf( +export const OPTIONS_LIST = PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.string.isRequired, label: PropTypes.string.isRequired, - status: PropTypes.string.isRequired, - disabled: PropTypes.bool + disabled: PropTypes.bool, + status: PropTypes.string, }) ) diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index 82cd342d4d..6620cca8f9 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -17,6 +17,8 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import { generateTypeFilter } from '../components/FilterMenu/filterMenu.settings' + import { APPLICATION, ARTIFACTS_PAGE, @@ -26,8 +28,8 @@ import { FILTER_ALL_ITEMS, JOBS_MONITORING_JOBS_TAB, JOBS_MONITORING_PAGE, + JOBS_MONITORING_SCHEDULED_TAB, JOBS_MONITORING_WORKFLOWS_TAB, - JOB_KIND_JOB, JOB_KIND_WORKFLOW, MODELS_PAGE, MONITORING_APP_PAGE, @@ -250,7 +252,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { counter: data.jobs || 0, link: () => navigateToJobsMonitoringPage({ - [TYPE_FILTER]: JOB_KIND_JOB, + [TYPE_FILTER]: generateTypeFilter(JOBS_MONITORING_SCHEDULED_TAB).filter(type => type.id !== JOB_KIND_WORKFLOW && type.id !== FILTER_ALL_ITEMS && !type.hidden).map(item => item.id).join(','), [DATES_FILTER]: NEXT_24_HOUR_DATE_OPTION }) }, diff --git a/src/utils/jobs.util.jsx b/src/utils/jobs.util.jsx index b3b089fed5..b25088dda8 100644 --- a/src/utils/jobs.util.jsx +++ b/src/utils/jobs.util.jsx @@ -261,7 +261,7 @@ export const getScheduledFiltersConfig = crossProjects => { ) }, [PROJECT_FILTER]: { label: 'Project:', initialValue: PROJECTS_FILTER_ALL_ITEMS, isModal: true }, - [TYPE_FILTER]: { label: 'Type:', initialValue: FILTER_ALL_ITEMS, isModal: true }, + [TYPE_FILTER]: { label: 'Type:', initialValue: [FILTER_ALL_ITEMS], isModal: true }, [LABELS_FILTER]: { label: 'Labels:', initialValue: '', isModal: true } } @@ -301,9 +301,14 @@ export const parseWorkflowsQueryParamsCallback = (paramName, paramValue) => { } export const parseScheduledQueryParamsCallback = (paramName, paramValue) => { - if (paramName === TYPE_FILTER) { - return generateTypeFilter(JOBS_MONITORING_SCHEDULED_TAB).find(type => type.id === paramValue) - ?.id + if (paramName === TYPE_FILTER && paramValue) { + const validTypes = new Set( + generateTypeFilter(JOBS_MONITORING_SCHEDULED_TAB).map(type => type.id) + ) + + const filteredStatuses = paramValue.split(',').filter(paramType => validTypes.has(paramType)) + + return filteredStatuses.length ? filteredStatuses : null } return paramValue From 4e37d91d6adb4a723c45d4904b16c3a35e6777af Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Mon, 13 Oct 2025 11:23:27 +0200 Subject: [PATCH 181/228] Tests [QA] v1.10.0-rc30 (#3458) --- tests/features/artifacts.feature | 165 ++++--- tests/features/common-tools/common-consts.js | 27 ++ tests/features/common/page-objects.js | 1 + .../common/page-objects/info-pane.po.js | 136 ++++++ .../page-objects/interactive-popup.po.js | 8 + .../common/page-objects/llm-prompts.po.js | 29 +- tests/features/llmPrompts.feature | 420 +++++++++++++++++- tests/mockServer/dataGenerators.js | 256 ++++++++++- 8 files changed, 961 insertions(+), 81 deletions(-) diff --git a/tests/features/artifacts.feature b/tests/features/artifacts.feature index 8953e5f775..e8f619012c 100644 --- a/tests/features/artifacts.feature +++ b/tests/features/artifacts.feature @@ -300,76 +300,6 @@ Feature: Artifacts Page Then click on "Tabel_View_Button" element on "Files_Info_Pane" wizard Then verify "Cross_Close_Button" element visibility on "Files_Info_Pane" wizard - @MLA - @passive - @smoke - Scenario: MLA013 - Check Details panel still active on page refresh - # * set tear-down property "project" created with "automation-test" value - # * set tear-down property "file" created in "automation-test" project with "test-file" value - * create "automation-test" MLRun Project with code 201 - * create "test-file" File with "test" tag in "automation-test" project with code 200 - Given open url - And wait load page - And click on row root with value "automation-test" in "name" column in "Projects_Table" table on "Projects" wizard - And wait load page - And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard - And click on cell with value "Artifacts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard - And wait load page - Then verify "Table_FilterBy_Button" element on "Files" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" - Then click on "Table_FilterBy_Button" element on "Files" wizard - Then select "test" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard - Then click on "Apply_Button" element on "FilterBy_Popup" wizard - And wait load page - When click on cell with value "test-file" in "name" column in "Files_Table" table on "Files" wizard - And wait load page - Then check "test" value in "tag" column in "Overview_Table" table on "Files_Info_Pane" wizard - Then click on "Edit_btn_table_view" element on "Files_Info_Pane" wizard - And wait load page - When type value "v1" to "Version_tag_Input" field on "Files_Info_Pane" wizard - Then click on "Apply_Button" element on "Files_Info_Pane" wizard - Then click on "Apply_Changes_Button" element on "Files_Info_Pane" wizard - And wait load page - Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard - Then verify "Not_In_Filtered_List_Message" element visibility on "Files_Info_Pane" wizard - Then "Not_In_Filtered_List_Message" component on "Files_Info_Pane" should be equal "Files_Info_Pane"."Info_Banner_Message" - Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard - Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" - Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard - Then verify "Header" element visibility on "Files_Info_Pane" wizard - Then "Header" element on "Files_Info_Pane" should contains "test-file" value - Then refresh a page - And wait load page - Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard - Then verify "Not_In_Filtered_List_Message" element visibility on "Files_Info_Pane" wizard - Then "Not_In_Filtered_List_Message" component on "Files_Info_Pane" should be equal "Files_Info_Pane"."Info_Banner_Message" - Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard - Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" - Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard - Then verify "Header" element visibility on "Files_Info_Pane" wizard - Then "Header" element on "Files_Info_Pane" should contains "test-file" value - Then verify "Table_Refresh_Button" element visibility on "Files" wizard - Then verify "Table_Refresh_Button" element on "Files" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" - Then click on "Table_Refresh_Button" element on "Files" wizard - And wait load page - Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard - Then verify "Not_In_Filtered_List_Message" element visibility on "Files_Info_Pane" wizard - Then "Not_In_Filtered_List_Message" component on "Files_Info_Pane" should be equal "Files_Info_Pane"."Info_Banner_Message" - Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard - Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" - Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard - Then verify "Header" element visibility on "Files_Info_Pane" wizard - Then click on "Cross_Close_Button" element on "Files_Info_Pane" wizard - And wait load page - Then verify "Header" element not exists on "Files_Info_Pane" wizard - When click on cell with value "test-file" in "name" column in "Files_Table" table on "Files" wizard - And wait load page - Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard - Then verify "Not_In_Filtered_List_Message" element not exists on "Files_Info_Pane" wizard - Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard - Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" - Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard - Then verify "Header" element visibility on "Files_Info_Pane" wizard - @MLA @passive @inProgress @@ -893,6 +823,101 @@ Feature: Artifacts Page And wait load page Then verify "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected attribute option value "All tags" + @MLA + @passive + @smoke + Scenario: MLA013 - Check Details panel still active on page refresh + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Artifacts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And wait load page + Then select "Add a tag" option in action menu on "Files" wizard in "Files_Table" table at row with "training_iteration_results" value in "name" column + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "test" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Tag was added successfully" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Table_FilterBy_Button" element on "Files" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" + Then click on "Table_FilterBy_Button" element on "Files" wizard + Then select "test" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "training_iteration_results" in "name" column in "Files_Table" table on "Files" wizard + And wait load page + Then check "test" value in "tag" column in "Overview_Table" table on "Files_Info_Pane" wizard + Then click on "Edit_btn_table_view" element on "Files_Info_Pane" wizard + And wait load page + When type value "v1" to "Version_tag_Input" field on "Files_Info_Pane" wizard + Then click on "Apply_Button" element on "Files_Info_Pane" wizard + Then click on "Apply_Changes_Button" element on "Files_Info_Pane" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element visibility on "Files_Info_Pane" wizard + Then "Not_In_Filtered_List_Message" component on "Files_Info_Pane" should be equal "Files_Info_Pane"."Info_Banner_Message" + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard + Then verify "Header" element visibility on "Files_Info_Pane" wizard + Then "Header" element on "Files_Info_Pane" should contains "training_iteration_results" value + Then refresh a page + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element visibility on "Files_Info_Pane" wizard + Then "Not_In_Filtered_List_Message" component on "Files_Info_Pane" should be equal "Files_Info_Pane"."Info_Banner_Message" + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard + Then verify "Header" element visibility on "Files_Info_Pane" wizard + Then "Header" element on "Files_Info_Pane" should contains "training_iteration_results" value + Then verify "Table_Refresh_Button" element visibility on "Files" wizard + Then verify "Table_Refresh_Button" element on "Files" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + Then click on "Table_Refresh_Button" element on "Files" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element visibility on "Files_Info_Pane" wizard + Then "Not_In_Filtered_List_Message" component on "Files_Info_Pane" should be equal "Files_Info_Pane"."Info_Banner_Message" + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard + Then verify "Header" element visibility on "Files_Info_Pane" wizard + Then click on "Cross_Close_Button" element on "Files_Info_Pane" wizard + And wait load page + Then verify "Header" element not exists on "Files_Info_Pane" wizard + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Artifact_Tag" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then click on "Clear_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "training_iteration_results" in "name" column in "Files_Table" table on "Files" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element not exists on "Files_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard + Then verify "Header" element visibility on "Files_Info_Pane" wizard + Then click on "Table_FilterBy_Button" element on "Files" wizard + Then select "v1" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "training_iteration_results" in "name" column in "Files_Table" table on "Files" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element not exists on "Files_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "Files_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard should contains "Files_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Files_Info_Pane" wizard + Then verify "Header" element visibility on "Files_Info_Pane" wizard + @MLA @smoke Scenario: MLA023 - Check components on artifact Full view content diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index f81eca0ac9..774c2a5b92 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -110,6 +110,7 @@ export default { }, Common_Lists: { Action_Menu_List: ['Add a tag', 'Download', 'Copy URI', 'View YAML', 'Delete', 'Delete all versions'], + Action_Menu_List_LLM_Prompt: ['Add a tag', 'Download', 'Copy URI', 'View YAML'], Action_Menu_List_Version_History: ['Add a tag', 'Download', 'Copy URI', 'View YAML', 'Delete'], Action_Menu_List_Expanded: ['Add a tag', 'Download', 'Copy URI', 'View YAML', 'Delete all'], Action_Menu_List_Dataset_Transition_Popup: ['Download', 'Copy URI', 'View YAML'], @@ -154,6 +155,26 @@ export default { ], Overview_Producer_Headers: ['Name:', 'Kind:', 'Tag:', 'Owner:', 'UID:'] }, + LLM_Prompts_Info_Pane: { + Tab_List: ['Overview', 'Prompt Template', 'Generation Configuration'], + Tab_List_Prompt_Template: ['Prompt', 'Arguments'], + Info_Banner_Message: /The LLM prompt is not in the filtered list\. Closing the details panel will return you to the current list\./, + Overview_General_Headers: [ + 'Key:', + 'Description:', + 'Model name:', + 'Hash:', + 'Version tag:', + 'Original source:', + 'Iter:', + 'URI:', + 'Path:', + 'UID:', + 'Updated:', + 'Labels:' + ], + Overview_Producer_Headers: ['Name:', 'Kind:', 'Tag:', 'Owner:', 'UID:'] + }, Alerts_Jobs_Info_Pane: { Overview_General_Headers: [ 'Project Name:', @@ -399,6 +420,7 @@ export default { Auto_Refresh: 'Uncheck Auto Refresh to view more results', FilterBy_Button: 'Filter', FilterBy_Button_1: 'Filter (1)', + Argument: 'The essence of all things', Show_All_Versions: 'Show all versions', Open_Metrics: 'Open metrics', Refresh_Button: 'Refresh', @@ -545,6 +567,7 @@ export default { FeatureSets_Stats_Tip: 'Each feature set can have multiple versions, produced by multiple runs and given multiple tags.\n' + ' You can browse them in the Feature store page.', + Model_Version_Tag: 'Enter a model name to enable field.', Artifacts_Stats_Tip: 'Each artifact can have multiple versions, produced by multiple runs and given multiple tags.\n' + ' You can browse them in the Artifacts page.', @@ -766,6 +789,10 @@ export default { Common_Message_Jobs_Monitoring: /No data matches the filter: "Start time: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, Common_Message_Monitor_Jobs_Name: /No data matches the filter: "Name: (.+?)"/, + Common_Message_LLM_Prompt_Name: /No data matches the filter: "Name: (.+?), LLM prompt version tag: (.+?), Show best iteration only: (.+?)"/, + Common_Message_LLM_Prompt_Label: /No data matches the filter: "Name: (.+?), LLM prompt version tag: (.+?), Labels: (.+?), Show best iteration only: (.+?)"/, + Common_Message_LLM_Prompt_Tag: /No data matches the filter: "LLM prompt version tag: (.+?), Show best iteration only: (.+?)"/, + Common_Message_Artifact_Tag: /No data matches the filter: "Version tag: (.+?), Show best iteration only: (.+?)"/, Common_Message_Jobs_Monitoring_Workflow_Project: /No data matches the filter: "Created at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, Common_Message_Jobs_Monitoring_Status: diff --git a/tests/features/common/page-objects.js b/tests/features/common/page-objects.js index 42df075d58..e55d8b4c73 100644 --- a/tests/features/common/page-objects.js +++ b/tests/features/common/page-objects.js @@ -85,6 +85,7 @@ export default { Jobs_Monitoring_Scheduled_Tab: jobsMonitoring['crossScheduledMonitorTab'], Jobs_Monitor_Tab_Info_Pane: infoPane['jobsMonitorTabInfoPane'], LLM_Prompts: llmPrompts['llmPrompts'], + LLM_Prompts_Info_Pane: infoPane['llmPromptsInfoPane'], Metrics_Selector_Popup: interactivePopup['metricsSelectorPopup'], ML_Function_Info_Pane: infoPane['mlFunctionInfoPane'], ML_Functions: Functions['mlFunctions'], diff --git a/tests/features/common/page-objects/info-pane.po.js b/tests/features/common/page-objects/info-pane.po.js index cc02bfc567..4e1e87ef52 100644 --- a/tests/features/common/page-objects/info-pane.po.js +++ b/tests/features/common/page-objects/info-pane.po.js @@ -63,6 +63,62 @@ const infoPaneTabSelector = { } } +const promptTemplateTabSelector = { + root: '.table__item .item-header-wrapper .content-menu__tabs', + header: {}, + body: { + row: { + root: '.content-menu__tab', + fields: { + key: '', + hintButton: '.tip-container' + } + } + } +} + +const promptArgumentsTabSelector = { + root: '.table__item .item-info .content-menu__tabs', + header: {}, + body: { + row: { + root: '.content-menu__tab', + fields: { + key: '', + hintButton: '.tip-container' + } + } + } +} + +const argumentsTabTable = { + root: '.arguments-tab', + header: {}, + body: { + row: { + root: '.arguments-tab__row', + fields: { + key: '.arguments-tab__row-key', + value: '.arguments-tab__row-value' + } + } + } +} + +const generationConfigurationTabTable = { + root: '.generation-configuration-tab', + header: {}, + body: { + row: { + root: '.generation-configuration-tab__row', + fields: { + key: '.generation-configuration-tab__row-key', + value: '.generation-configuration-tab__row-value' + } + } + } +} + const infoPaneOverviewHeaders = { root: '.table__item .item-info__details-wrapper:nth-of-type(1)', header: {}, @@ -78,6 +134,20 @@ const infoPaneOverviewHeaders = { } } +const infoPaneOverviewPromptTable = { + root: '.table__item .prompt-tab__table', + header: {}, + body: { + row: { + root: '.prompt-tab__row', + fields: { + role: '.prompt-tab__role', + content: '.prompt-tab__content' + } + } + } +} + const infoPaneOverviewProducerHeaders = { root: '.table__item .item-info__details-wrapper:nth-of-type(2)', header: {}, @@ -121,6 +191,7 @@ const infoPaneOverviewSourcesHeaders = { } } } + const artifactOverviewTable = { root: '.table__item .item-info__details:nth-of-type(1)', header: {}, @@ -143,6 +214,20 @@ const artifactOverviewTable = { } } +const llmPromptOverviewTable = { + root: '.table__item .item-info__details-wrapper:nth-of-type(1)', + header: {}, + body: { + row: { + root: '', + fields: { + key: '.details-item:nth-of-type(1) .details-item__data', + tag: '.details-item:nth-of-type(5) .details-item__data' + } + } + } +} + const datasetOverviewTable = { root: '.table__item .item-info__details:nth-of-type(1)', header: {}, @@ -990,6 +1075,57 @@ export default { Cross_Close_Button: By.css('.graph-pane__title .round-icon-cp .round-icon-cp__circle'), Overview_Headers: commonTable(modelsRealTimeinfoPaneOverviewHeaders) }, + llmPromptsInfoPane: { + Header: header, + Updated: updated, + Not_In_Filtered_List_Message: By.css('[data-testid="detailsPanel"] .item-header__status .info-banner'), + Action_Menu: commonActionMenu, + Apply_Changes_Button: applyChangesButton, + Apply_Button: applyButton, + Cross_Close_Button: crossCloseButton, + Full_View_Button: fullViewButton, + Tabel_View_Button: tabelViewButton, + Info_Pane_Tab_Selector: commonInfoPaneTabSelector, + Prompt_Template_Tab_Selector: commonTable(promptTemplateTabSelector), + Prompt_Arguments_Tab_Selector: commonTable(promptArgumentsTabSelector), + Arguments_Tab_Table: commonTable(argumentsTabTable), + Generation_Configuration_Tab_Table: commonTable(generationConfigurationTabTable), + Find_In_Prompt_Filter_Input: inputGroup( + generateInputGroup( + '.search-navigator [data-testid="search-container"]', + true, + false + ) + ), + Overview_General_Headers: commonTable(infoPaneOverviewHeaders), + Overview_Producer_Headers: commonTable(infoPaneOverviewProducerHeaders), + Overview_Hash_Header: labelComponent( + generateLabelGroup( + '.item-info__details:nth-of-type(1) .details-item:nth-of-type(4) .details-item__header', + false, + true + ) + ), + Overview_UID_Header: labelComponent( + generateLabelGroup( + '.item-info__details-wrapper:nth-of-type(2) .item-info__details .details-item:nth-of-type(5) .details-item__header', + false, + true + ) + ), + Overview_Table: commonTable(llmPromptOverviewTable), + Prompt_Template_Table: commonTable(infoPaneOverviewPromptTable), + Prompt_Template_Argument: By.css('.prompt-tab__table .prompt-tab__row:nth-of-type(3) .prompt-tab__content span'), + Generation_Configuration_Counter: By.css('.generation-configuration-tab .generation-configuration-tab__counter'), + Edit_btn_table_view: commonEditBtnTableView, + Version_tag_Input: inputGroup( + generateInputGroup( + '.details-item:nth-of-type(5) .details-item__input-wrapper', + false, + false + ) + ) + }, paginationInfoPane: { BE_Pagination_Navigate_Prev: By.css( '[data-testid="pagination-navigate-double-prev-btn"] button' diff --git a/tests/features/common/page-objects/interactive-popup.po.js b/tests/features/common/page-objects/interactive-popup.po.js index 417d550bb6..3d2a2e27ba 100644 --- a/tests/features/common/page-objects/interactive-popup.po.js +++ b/tests/features/common/page-objects/interactive-popup.po.js @@ -1732,6 +1732,14 @@ export default { true ) ), + Model_Name_Filter_Input: inputGroup( + generateInputGroup('[data-testid="model-name-form-field-input"]', true, false, 'svg') + ), + Model_Version_Tag_Filter_Input: inputGroup( + generateInputGroup('[data-testid="model-tag-form-field-input"]', true, false, 'svg') + ), + Model_Version_Tag_Filter_Field: By.css('[data-testid="model-tag-form-field-input"] > div:nth-child(2)'), + Model_Version_Tag_Filter_Tip: By.css('[data-testid="model-tag-form-field-input"] > div:nth-child(2) .form-field__icons svg'), Status_Filter_Element: By.css('[data-testid="state-form-field-select"]'), Status_Filter_Dropdown: dropdownComponent( generateDropdownGroup( diff --git a/tests/features/common/page-objects/llm-prompts.po.js b/tests/features/common/page-objects/llm-prompts.po.js index 9b36a87c0e..9e1f4ab606 100644 --- a/tests/features/common/page-objects/llm-prompts.po.js +++ b/tests/features/common/page-objects/llm-prompts.po.js @@ -25,6 +25,7 @@ import { generateDropdownGroup } from '../../common-tools/common-tools' import inputGroup from '../components/input-group.component' +import actionMenu from '../components/action-menu.component' const commonSearchByNameFilterInput = inputGroup( generateInputGroup( @@ -34,6 +35,14 @@ const commonSearchByNameFilterInput = inputGroup( ) ) +const actionMenuStructure = { + root: '.actions-menu__container', + menuElements: { + open_button: '[data-testid="actions-menu"] button', + options: '.actions-menu__body .actions-menu__option' + } +} + const overallTable = { root: '.table__content', header: { @@ -53,10 +62,11 @@ const overallTable = { root: '.table-row', fields: { name: '[data-testid="name"] a .link', + uid: '.table-body__cell:nth-of-type(1) a .name-wrapper .link', labels: { componentType: dropdownComponent, structure: generateDropdownGroup( - '.table-body__cell:nth-of-type(7)', + '.table-body__cell:nth-of-type(3)', '.chip-block span.chips_button', '.chip-block-hidden_visible .data-ellipsis.tooltip-wrapper', false, @@ -66,7 +76,12 @@ const overallTable = { producer: '[data-testid="producer"] .data-ellipsis', owner: '[data-testid="owner"] .data-ellipsis', updated: '[data-testid="updated"] .data-ellipsis', - size: '[data-testid="size"] .data-ellipsis' + size: '[data-testid="size"] .data-ellipsis', + show_all_versions: '[data-testid="quick-link-show-all-versions"]', + action_menu: { + componentType: actionMenu, + structure: actionMenuStructure + }, } } } @@ -77,6 +92,14 @@ export default { Search_By_Name_Filter_Input: commonSearchByNameFilterInput, Table_FilterBy_Button: By.css('[data-testid="filter-menu-btn-tooltip-wrapper"]'), Refresh_Button: By.css('[data-testid="refresh"] [data-testid="refresh-tooltip-wrapper"]'), - LLMPrompts_Table: commonTable(overallTable) + LLMPrompts_Table: commonTable(overallTable), + Overlay: By.css('#overlay_container .chip-block-hidden_visible'), + History_Back_Button: By.css('.history-back-link .history-back-link__icon'), + Version_History_Title: By.css( + '.history-back-link .history-back-link__title [data-testid="version-history"]' + ), + Version_History_Prompt_Name: By.css( + '.history-back-link .history-back-link__title .data-ellipsis.tooltip-wrapper' + ) } } diff --git a/tests/features/llmPrompts.feature b/tests/features/llmPrompts.feature index ea20a8653e..46c0bb06fd 100644 --- a/tests/features/llmPrompts.feature +++ b/tests/features/llmPrompts.feature @@ -7,18 +7,16 @@ Feature: LLM prompts Page Scenario: MLLP001 - Check components on LLM prompts page Given open url And wait load page - When turn on demo mode with query params "false" - And wait load page - And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page Then verify breadcrumbs "tab" label should be equal "Project monitoring" value - Then verify breadcrumbs "project" label should be equal "default" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard And wait load page Then verify breadcrumbs "tab" label should be equal "LLM prompts" value - Then verify redirection to "projects/default/llm-prompts?bePage=1&fePage=1" + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Project monitoring" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard @@ -27,7 +25,7 @@ Feature: LLM prompts Page And wait load page And select "tab" with "LLM prompts" value in breadcrumbs menu And wait load page - Then verify redirection to "projects/default/llm-prompts?bePage=1&fePage=1" + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" Then verify breadcrumbs "tab" label should be equal "LLM prompts" value Then verify "Search_By_Name_Filter_Input" element visibility on "LLM_Prompts" wizard Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard @@ -38,6 +36,11 @@ Feature: LLM prompts Page Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard Then verify "Table_Tree_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected attribute option value "latest" + Then verify "Model_Name_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Model_Version_Tag_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Model_Version_Tag_Filter_Field" element on "FilterBy_Popup" wizard is disabled by class name + Then verify "Model_Version_Tag_Filter_Tip" element visibility on "FilterBy_Popup" wizard + Then verify "Model_Version_Tag_Filter_Tip" element on "FilterBy_Popup" wizard should display hover hint "Label_Hint"."Model_Version_Tag" Then verify "Show_Iterations_Checkbox" element visibility on "FilterBy_Popup" wizard Then "Show_Iterations_Checkbox" element should be checked on "FilterBy_Popup" wizard Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard @@ -72,4 +75,407 @@ Feature: LLM prompts Page Then verify "Pagination_Page_Number" element visibility on "Pagination_Info_Pane" wizard Then "Pagination_Page_Number" element on "Pagination_Info_Pane" should contains "1" value Then verify "Pagination_Count" element visibility on "Pagination_Info_Pane" wizard - Then "Pagination_Count" element on "Pagination_Info_Pane" should contains "Showing 1 - 3" value + Then "Pagination_Count" element on "Pagination_Info_Pane" should contains "Showing 1 - 1" value + + @MLLP + @smoke + Scenario: MLLP002 - Verify searching by llm prompt name on LLM prompts page + Given open url + And wait load page + And click on row root with value "auto-generated-data" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "auto-generated-data" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/auto-generated-data/llm-prompts?bePage=1&fePage=1" + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Project monitoring" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + And wait load page + Then verify "LLM_Prompts_Counter_Subtitle" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then "LLM_Prompts_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "LLM prompt artifacts" value + When click on "LLM_Prompts_Counter_Number" element in "Artifacts_Stats_Container" on "Project" wizard + And wait load page + Then verify redirection to "projects/auto-generated-data/llm-prompts?bePage=1&fePage=1" + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify "Search_By_Name_Filter_Input" element visibility on "LLM_Prompts" wizard + Then type value "59" to "Search_By_Name_Filter_Input" field on "LLM_Prompts" wizard + Then click on "Refresh_Button" element on "LLM_Prompts" wizard + And wait load page + Then value in "name" column with "text" in "LLMPrompts_Table" on "LLM_Prompts" wizard should contains "59" + And wait load page + Then type value "yyyy" to "Search_By_Name_Filter_Input" field on "LLM_Prompts" wizard + Then click on "Refresh_Button" element on "LLM_Prompts" wizard + And wait load page + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_LLM_Prompt_Name" + + @MLLP + @smoke + Scenario: MLLP003 - Verify filtering by llm prompt label on LLM prompts page + Given open url + And wait load page + And click on row root with value "auto-generated-data" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "auto-generated-data" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/auto-generated-data/llm-prompts?bePage=1&fePage=1" + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Project monitoring" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + And wait load page + Then verify "LLM_Prompts_Counter_Subtitle" element visibility in "Artifacts_Stats_Container" on "Project" wizard + Then "LLM_Prompts_Counter_Subtitle" element in "Artifacts_Stats_Container" on "Project" should contains "LLM prompt artifacts" value + When click on "LLM_Prompts_Counter_Number" element in "Artifacts_Stats_Container" on "Project" wizard + And wait load page + Then verify redirection to "projects/auto-generated-data/llm-prompts?bePage=1&fePage=1" + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then type value "language" to "Table_Label_Filter_Input" field on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then type value "50" to "Search_By_Name_Filter_Input" field on "LLM_Prompts" wizard + Then click on "Refresh_Button" element on "LLM_Prompts" wizard + And wait load page + Then value in "labels" column with "dropdowns" in "LLMPrompts_Table" on "LLM_Prompts" wizard should contains "language" in "Overlay" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then type value "type=qa" to "Table_Label_Filter_Input" field on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then value in "labels" column with "text" in "LLMPrompts_Table" on "LLM_Prompts" wizard should contains "type=qa" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then type value "v3io_user=123" to "Table_Label_Filter_Input" field on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_LLM_Prompt_Label" + + @MLLP + @smoke + Scenario: MLLP004 - Verify the Show iterations checkbox on LLM prompts page + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "Project monitoring" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + And wait load page + And select "tab" with "LLM prompts" value in breadcrumbs menu + And wait load page + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then verify "Show_Iterations_Checkbox" element visibility on "FilterBy_Popup" wizard + Then "Show_Iterations_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then uncheck "Show_Iterations_Checkbox" element on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then "Show_Iterations_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then verify "show_all_versions" option is present on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column + Then verify "show_all_versions" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column should display hover tooltip "Common_Tooltips"."Show_All_Versions" with scroll "false" + Then click on cell with row index 1 in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then verify "Header" element visibility on "LM_Prompts_Info_Pane" wizard + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then check "Show_Iterations_Checkbox" element on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Header" element not exists on "LM_Prompts_Info_Pane" wizard + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then "Show_Iterations_Checkbox" element should be checked on "FilterBy_Popup" wizard + + @MLLP + @smoke + Scenario: MLLP005 - Check components on prompt item infopane on Overview tab table + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then click on cell with row index 1 in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Updated" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" dropdown element on "LLM_Prompts_Info_Pane" wizard should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then select "Download" option in action menu on "LLM_Prompts_Info_Pane" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then verify "Cross_Close_Button" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Full_View_Button" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Overview_General_Headers" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Overview_General_Headers" + Then verify "Overview_Hash_Header" on "LLM_Prompts_Info_Pane" wizard should display "Label_Hint"."Overview_Hash" + Then verify "Overview_Producer_Headers" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Overview_Producer_Headers" + Then verify "Overview_UID_Header" on "LLM_Prompts_Info_Pane" wizard should display "Label_Hint"."Overview_UID" + Then click on "Full_View_Button" element on "LLM_Prompts_Info_Pane" wizard + Then verify "Cross_Close_Button" element not exists on "LLM_Prompts_Info_Pane" wizard + Then click on "Tabel_View_Button" element on "LLM_Prompts_Info_Pane" wizard + Then verify "Cross_Close_Button" element visibility on "LLM_Prompts_Info_Pane" wizard + + @MLLP + @smoke + Scenario: MLLP006 - Verify Add a Tag, Edit a tag action and detail panel behavior after page refresh + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then select "Add a tag" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "test" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Tag was added successfully" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then select "test" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "my_llm" in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then check "test" value in "tag" column in "Overview_Table" table on "LLM_Prompts_Info_Pane" wizard + Then click on "Edit_btn_table_view" element on "LLM_Prompts_Info_Pane" wizard + And wait load page + When type value "v1" to "Version_tag_Input" field on "LLM_Prompts_Info_Pane" wizard + Then click on "Apply_Button" element on "LLM_Prompts_Info_Pane" wizard + Then click on "Apply_Changes_Button" element on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element visibility on "LLM_Prompts_Info_Pane" wizard + Then "Not_In_Filtered_List_Message" component on "LLM_Prompts_Info_Pane" should be equal "LLM_Prompts_Info_Pane"."Info_Banner_Message" + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then "Header" element on "LLM_Prompts_Info_Pane" should contains "my_llm" value + Then refresh a page + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element visibility on "LLM_Prompts_Info_Pane" wizard + Then "Not_In_Filtered_List_Message" component on "LLM_Prompts_Info_Pane" should be equal "LLM_Prompts_Info_Pane"."Info_Banner_Message" + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then "Header" element on "LLM_Prompts_Info_Pane" should contains "my_llm" value + Then verify "Refresh_Button" element visibility on "LLM_Prompts" wizard + Then verify "Refresh_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + Then click on "Refresh_Button" element on "LLM_Prompts" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element visibility on "LLM_Prompts_Info_Pane" wizard + Then "Not_In_Filtered_List_Message" component on "LLM_Prompts_Info_Pane" should be equal "LLM_Prompts_Info_Pane"."Info_Banner_Message" + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then click on "Cross_Close_Button" element on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify "Header" element not exists on "LLM_Prompts_Info_Pane" wizard + And wait load page + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_LLM_Prompt_Tag" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then click on "Clear_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "my_llm" in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element not exists on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then select "v1" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "my_llm" in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Not_In_Filtered_List_Message" element not exists on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + + @MLLP + @smoke + Scenario: MLLP007 - Check components on prompt item infopane on Prompt Template tab table + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then click on cell with row index 1 in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then select "Prompt Template" tab in "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify "Prompt_Template_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Prompt_Template_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List" + Then verify "Prompt Template" tab is active in "Prompt_Template_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Updated" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" dropdown element on "LLM_Prompts_Info_Pane" wizard should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then verify "Cross_Close_Button" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Prompt_Arguments_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Prompt_Arguments_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List_Prompt_Template" + Then verify "Prompt" tab is active in "Prompt_Arguments_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Find_In_Prompt_Filter_Input" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Prompt_Template_Table" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Prompt_Template_Argument" element visibility on "LLM_Prompts_Info_Pane" wizard + Then "Prompt_Template_Argument" element on "LLM_Prompts_Info_Pane" should contains "{something_with_meaning}" value + Then verify "Prompt_Template_Argument" element on "LLM_Prompts_Info_Pane" wizard should display hover tooltip "Common_Tooltips"."Argument" + Then click on "Prompt_Template_Argument" element on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify "Prompt Template" tab is active in "Prompt_Template_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Arguments" tab is active in "Prompt_Arguments_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then value in "key" column with "text" in "Arguments_Tab_Table" on "LLM_Prompts_Info_Pane" wizard should contains "word" + Then value in "value" column with "text" in "Arguments_Tab_Table" on "LLM_Prompts_Info_Pane" wizard should contains "The essence of all things" + + @MLLP + @smoke + Scenario: MLLP008 - Check components on prompt item infopane on Generation Configuration tab table + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then click on cell with row index 1 in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then select "Generation Configuration" tab in "Info_Pane_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify "Prompt_Template_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Prompt_Template_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard should contains "LLM_Prompts_Info_Pane"."Tab_List" + Then verify "Generation Configuration" tab is active in "Prompt_Template_Tab_Selector" on "LLM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Updated" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" dropdown element on "LLM_Prompts_Info_Pane" wizard should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then verify "Cross_Close_Button" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Generation_Configuration_Counter" element visibility on "LLM_Prompts_Info_Pane" wizard + Then "Generation_Configuration_Counter" element on "LLM_Prompts_Info_Pane" should contains "1 modifications made to the default configuration:" value + Then value in "key" column with "text" in "Generation_Configuration_Tab_Table" on "LLM_Prompts_Info_Pane" wizard should contains "temperature" + Then value in "value" column with "text" in "Generation_Configuration_Tab_Table" on "LLM_Prompts_Info_Pane" wizard should contains "0.5" + + @MLLP + @smoke + @uniqueTag + Scenario: MLLP009 - Check components on prompt version history page + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then verify action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then verify "show_all_versions" option is present on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column + Then verify "show_all_versions" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column should display hover tooltip "Common_Tooltips"."Show_All_Versions" with scroll "false" + Then click on "show_all_versions" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column with scroll "false" + And wait load page + Then verify "History_Back_Button" element visibility on "LLM_Prompts" wizard + Then verify "Version_History_Title" element visibility on "LLM_Prompts" wizard + Then "Version_History_Title" element on "LLM_Prompts" should contains "Version history:" value + Then verify "Version_History_Prompt_Name" element visibility on "LLM_Prompts" wizard + Then "Version_History_Prompt_Name" element on "LLM_Prompts" should contains "my_llm" value + Then verify "Refresh_Button" element visibility on "LLM_Prompts" wizard + Then verify "Table_FilterBy_Button" element visibility on "LLM_Prompts" wizard + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then "Show_Iterations_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then verify action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + When click on cell with row index 1 in "uid" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then check "latest" value in "tag" column in "Overview_Table" table on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" dropdown element on "LLM_Prompts_Info_Pane" wizard should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then "Header" element on "LLM_Prompts_Info_Pane" should contains "my_llm" value + Then click on "History_Back_Button" element on "LLM_Prompts" wizard + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard diff --git a/tests/mockServer/dataGenerators.js b/tests/mockServer/dataGenerators.js index 288dc83825..d9601c546f 100644 --- a/tests/mockServer/dataGenerators.js +++ b/tests/mockServer/dataGenerators.js @@ -31,6 +31,8 @@ export function makeUID(length) { return result } +export const makeHash = () => Math.random().toString(16).substring(2, 42) + export const generateArtifacts = existingArtifacts => { const artifactKinds = ['dataset', 'model', 'document', 'artifact'] const getArtifactTemplate = i => ({ @@ -64,6 +66,243 @@ export const generateArtifacts = existingArtifacts => { }, status: {} }) + + // unique model with unique prompt + const getModelWithPrompt = i => { + const modelKey = `model_${i}_${makeUID(6)}` + const modelUid = makeUID(32) + const modelTree = makeUID(32) + const modelHash = makeHash() + + const model = { + kind: 'model', + metadata: { + project: 'auto-generated-data', + uid: modelUid, + key: modelKey, + iter: 0, + tree: modelTree, + hash: modelHash, + updated: new Date().toISOString(), + created: new Date().toISOString(), + tag: 'latest' + }, + spec: { + target_path: `v3io:///projects/auto-generated-data/artifacts/${modelKey}`, + size: 4000, + license: '', + framework: '', + db_key: modelKey, + has_children: true, + model_file: 'RandomForestClassifier_file1.pkl', + parameters: { + default_config: { + model_version: '4' + } + }, + producer: { + kind: 'project', + name: 'auto-generated-data', + tag: modelTree, + owner: 'auto-user' + }, + parent_uri: null + }, + status: { state: 'created' }, + project: 'auto-generated-data' + } + + const promptKey = `prompt_${i}_${makeUID(6)}` + const promptHash = makeHash() + + const promptLabels = [ + { type: 'single-turn', language: 'english' }, + { type: 'multi-turn', language: 'ukrainian' }, + { type: 'qa', language: 'polish' }, + { type: 'complex', language: 'english' }, + { type: 'instruction-following', language: 'german' } + ] + const randomLabels = promptLabels[Math.floor(Math.random() * promptLabels.length)] + + + const prompt = { + kind: 'llm-prompt', + metadata: { + project: 'auto-generated-data', + uid: makeUID(32), + key: promptKey, + iter: 0, + tree: makeUID(32), + hash: promptHash, + labels: randomLabels, + updated: new Date().toISOString(), + created: new Date().toISOString(), + tag: 'latest' + }, + spec: { + target_path: `v3io:///projects/auto-generated-data/artifacts/${promptKey}`, + size: 256, + license: '', + invocation_config: { + temperature: 0.5 + }, + db_key: promptKey, + parent_uri: `store://models/auto-generated-data/${modelKey}#0:v1@${modelUid}`, + has_children: false, + prompt_legend: { + something_with_meaning: { + field: 'word', + description: 'The essence of all things' + } + }, + prompt_template: [ + { role: 'system', content: "don't tell them anything" }, + { role: 'user', content: 'What is the meaning of {something_with_meaning}?' }, + { role: 'system', content: 'tell you story' }, + { role: 'user', content: 'What is the biggest of {country} at all?' } + ], + producer: { + kind: 'project', + name: 'auto-generated-data', + tag: modelTree, + owner: 'auto-user' + } + }, + status: { state: 'created' }, + project: 'auto-generated-data' + } + + return [model, prompt] + } + + // mix - model shared prompts, prompts per model + const getMixedModelWithPrompt = (modelIndex, existingPromptsPool = []) => { + const modelKey = 'mix_model_' + makeUID(6) + const modelUid = makeUID(32) + const modelTree = makeUID(32) + const modelHash = makeUID(40) + + const model = { + kind: 'model', + metadata: { + project: 'auto-generated-data', + uid: modelUid, + key: modelKey, + iter: 0, + tree: modelTree, + hash: modelHash, + updated: new Date().toISOString(), + created: new Date().toISOString(), + tag: 'latest' + }, + spec: { + target_path: `v3io:///projects/auto-generated-data/artifacts/${modelKey}`, + size: 4000, + license: '', + framework: '', + db_key: modelKey, + has_children: true, + model_file: 'RandomForestClassifier_file1.pkl', + parameters: { + default_config: { + model_version: '4' + } + }, + producer: { + kind: 'project', + name: 'auto-generated-data', + tag: modelTree, + owner: 'auto-user' + }, + parent_uri: null + }, + status: { state: 'created' }, + project: 'auto-generated-data' + } + + const prompts = new Array(Math.floor(Math.random() * 3) + 1).fill().map((_, promptIndex) => { + let prompt + + if (existingPromptsPool.length && Math.random() < 0.5) { + const oldPrompt = existingPromptsPool[Math.floor(Math.random() * existingPromptsPool.length)] + existingPromptsPool + .filter(p => p.metadata.key === oldPrompt.metadata.key) + .forEach(p => p.metadata.tag = '') + prompt = { + ...oldPrompt, + metadata: { + ...oldPrompt.metadata, + tree: makeUID(32), + uid: makeUID(32), + tag: 'latest', + updated: new Date().toISOString(), + created: new Date().toISOString() + }, + spec: { + ...oldPrompt.spec, + parent_uri: `store://models/auto-generated-data/${modelKey}#0:v1@${modelUid}` + } + } + existingPromptsPool.push(prompt) + } else { + const promptKey = `prompt_${modelIndex}_${promptIndex}_${makeUID(6)}` + const promptHash = makeHash() + prompt = { + kind: 'llm-prompt', + metadata: { + project: 'auto-generated-data', + uid: makeUID(32), + key: promptKey, + iter: 0, + tree: makeUID(32), + hash: promptHash, + labels: { + example: 'single', + hebrew: 'english' + }, + updated: new Date().toISOString(), + created: new Date().toISOString(), + tag: 'latest' + }, + spec: { + target_path: `v3io:///projects/auto-generated-data/artifacts/${promptKey}`, + size: 256, + license: '', + invocation_config: { temperature: 0.5 }, + db_key: promptKey, + parent_uri: `store://models/auto-generated-data/${modelKey}#0:v1@${modelUid}`, + has_children: false, + prompt_legend: { + something_with_meaning: { + field: 'word', + description: 'The essence of all things' + } + }, + prompt_template: [ + { role: 'system', content: "don't tell them anything" }, + { role: 'user', content: 'What is the meaning of {something_with_meaning}?' }, + { role: 'system', content: 'tell you story' }, + { role: 'user', content: 'What is the biggest of {country} at all?' } + ], + producer: { + kind: 'project', + name: 'auto-generated-data', + tag: modelTree, + owner: 'auto-user' + } + }, + status: { state: 'created' }, + project: 'auto-generated-data' + } + existingPromptsPool.push(prompt) + } + + return prompt + }) + + return [model, ...prompts] + } + const newArtifactsWithDiffKeys = new Array(40000).fill().map((_, i) => { const artifact = getArtifactTemplate(i) @@ -85,10 +324,25 @@ export const generateArtifacts = existingArtifacts => { return artifact }) + // generate models and mix-prompts + const modelArtifacts = [] + const mixModelArtifacts = [] + const promptPool = [] + + for (let i = 0; i < 100; i++) { + modelArtifacts.push(...getModelWithPrompt(i)) + } + + for (let modelIndex = 0; modelIndex < 100; modelIndex++) { + mixModelArtifacts.push(...getMixedModelWithPrompt(modelIndex, promptPool)) + } + existingArtifacts.artifacts = [ ...existingArtifacts.artifacts, ...newArtifactsWithDiffKeys, - ...newArtifactsWithSameKey + ...newArtifactsWithSameKey, + ...modelArtifacts, + ...mixModelArtifacts ] } From 06525b8f137178625bb2df371a4c20a1f3d4ca6f Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 13 Oct 2025 12:23:45 +0300 Subject: [PATCH 182/228] Fix [Artifacts] Closing the overwrite message popup also closes the Register and Add Tag forms (#3459) --- src/utils/artifacts.util.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/artifacts.util.js b/src/utils/artifacts.util.js index 0bc767e103..5dcf826035 100644 --- a/src/utils/artifacts.util.js +++ b/src/utils/artifacts.util.js @@ -197,9 +197,10 @@ export const processActionAfterTagUniquesValidation = ({ throwError }) ) + + onErrorCallback?.() } - onErrorCallback?.() hideLoader() if (throwError) throw error From dfacf371f6eb7cab9a5714bed3daadac159f700e Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Thu, 16 Oct 2025 08:42:10 +0300 Subject: [PATCH 183/228] Fix [Scheduled] All type filtering checkbox behavior (#3460) --- src/common/MultiSelectFilter/MultiSelectFilter.jsx | 2 +- .../ProjectsJobsMonitoring/JobsMonitoring/JobsMonitoring.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/MultiSelectFilter/MultiSelectFilter.jsx b/src/common/MultiSelectFilter/MultiSelectFilter.jsx index 00adc99e08..595ffa43e5 100644 --- a/src/common/MultiSelectFilter/MultiSelectFilter.jsx +++ b/src/common/MultiSelectFilter/MultiSelectFilter.jsx @@ -52,7 +52,7 @@ const MultiSelectFilter = ({ optionsList, name }) => { (!currentValue.includes(FILTER_ALL_ITEMS) && selectedValue.includes(FILTER_ALL_ITEMS) && selectedValue.indexOf(FILTER_ALL_ITEMS) > 0) || - mappedOptionsList.filter(option => option.id !== FILTER_ALL_ITEMS).length === + mappedOptionsList.filter(option => option.id !== FILTER_ALL_ITEMS && !option.hidden).length === selectedValue.length ) { change(name, [FILTER_ALL_ITEMS]) diff --git a/src/components/ProjectsJobsMonitoring/JobsMonitoring/JobsMonitoring.jsx b/src/components/ProjectsJobsMonitoring/JobsMonitoring/JobsMonitoring.jsx index 9fafb1f84f..8992ced52d 100644 --- a/src/components/ProjectsJobsMonitoring/JobsMonitoring/JobsMonitoring.jsx +++ b/src/components/ProjectsJobsMonitoring/JobsMonitoring/JobsMonitoring.jsx @@ -61,8 +61,8 @@ const JobsMonitoring = () => { const dispatch = useDispatch() const filters = useFiltersFromSearchParams( - initialTabData[JOBS_MONITORING_JOBS_TAB]?.filtersConfig, - initialTabData[JOBS_MONITORING_JOBS_TAB]?.parseQueryParamsCallback + initialTabData?.[JOBS_MONITORING_JOBS_TAB]?.filtersConfig, + initialTabData?.[JOBS_MONITORING_JOBS_TAB]?.parseQueryParamsCallback ) const tableContent = useMemo( From d331815fa14f1a0e293b97dc853bf63034966dd2 Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Thu, 16 Oct 2025 08:06:47 +0200 Subject: [PATCH 184/228] Tests [QA] v1.10.0-rc31 (#3461) - updated LLM prompts test suite with preview option - updated LLM prompts test suite with overwrite Add a tag option - updated LLM prompts test suite to verify action menu list options - added verification filtering by types on Scheduled tab in Jobs & Workflow, Jobs monitoring, Project monitoring and Projects test suites --- tests/features/artifacts.feature | 20 +- tests/features/common-tools/common-consts.js | 7 +- tests/features/common/page-objects.js | 1 - .../page-objects/interactive-popup.po.js | 97 +++-- .../common/page-objects/llm-prompts.po.js | 1 + tests/features/datasets.feature | 38 +- tests/features/featureStore.feature | 1 + tests/features/jobsAndWorkflows.feature | 128 +++++- tests/features/jobsMonitoring.feature | 139 ++++++- tests/features/llmPrompts.feature | 384 +++++++++++++++++- tests/features/models.feature | 19 +- tests/features/projectMonitoring.feature | 37 +- tests/features/projectsPage.feature | 2 +- tests/features/step-definitions/steps.js | 2 +- tests/mockServer/data/artifacts.json | 2 +- 15 files changed, 796 insertions(+), 82 deletions(-) diff --git a/tests/features/artifacts.feature b/tests/features/artifacts.feature index e8f619012c..7ab1e75205 100644 --- a/tests/features/artifacts.feature +++ b/tests/features/artifacts.feature @@ -333,11 +333,19 @@ Feature: Artifacts Page Then verify "Pop_Out_Button" element visibility on "Files_Info_Pane" wizard Then click on "Pop_Out_Button" element on "Files_Info_Pane" wizard And wait load page - Then verify "Preview_Row" element visibility on "Artifact_Preview_Popup" wizard - Then verify "Cross_Cancel_Button" element visibility on "Artifact_Preview_Popup" wizard - Then verify "Preview_Header" on "Artifact_Preview_Popup" wizard should contains "Preview_Pop_Up"."Table_Header" - Then check "download_btn" visibility in "Preview_Row" on "Artifact_Preview_Popup" wizard with 1 offset - Then click on "Download_Button" element on "Artifact_Preview_Popup" wizard + Then verify "Preview_Table" element visibility on "Preview_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then value in "name" column with "text" in "Preview_Table" on "Preview_Popup" wizard should contains "download_content" + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard And wait load page And wait load page Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard @@ -347,7 +355,7 @@ Feature: Artifacts Page Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard - Then click on "Cross_Cancel_Button" element on "Artifact_Preview_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard Then verify "Preview_Tab_Info_Pane_Table" element visibility on "Files_Info_Pane" wizard @MLA diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index 774c2a5b92..940d46b3de 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -594,7 +594,9 @@ export default { Delete_Scheduled_Job: /Are you sure you want to delete the scheduled job "[^"]+[$"]\? Deleted scheduled jobs can not be restored\./, Delete_Feature: - /You try to delete feature "[^"]+[$"] from vector "[^"]+[$"]\. The feature could be added back later./ + /You try to delete feature "[^"]+[$"] from vector "[^"]+[$"]\. The feature could be added back later./, + Add_A_Tag_Overwrite_Message: + /That combination of name and tag is already in use in an existing (artifact|dataset|plotly|LLM prompt)\. If you proceed, the existing (artifact|dataset|plotly|LLM prompt) will be overwritten/ }, Messages: { How_To_Create: @@ -824,8 +826,5 @@ export default { No_Models_data: 'No data matches the filter: "Version tag: latest, Labels: MY-KEY, Show best iteration only: true"', No_Pods_data: 'Pods not found, it is likely because Kubernetes removed these pods listing', No_Pods_data_Completion: 'Pods not found, it is likely because Kubernetes removed these pods listing after their completion' - }, - Preview_Pop_Up: { - Table_Header: ['Name', 'Path', 'Size', 'Updated'] } } diff --git a/tests/features/common/page-objects.js b/tests/features/common/page-objects.js index e55d8b4c73..71d93687cc 100644 --- a/tests/features/common/page-objects.js +++ b/tests/features/common/page-objects.js @@ -48,7 +48,6 @@ export default { Analysis_Info_Pane: infoPane['analysisInfoPane'], Application_Metrics: monitoringApp['applicationMetrics'], Application_Monitoring: monitoringApp['applicationMonitoring'], - Artifact_Preview_Popup: interactivePopup['artifactPreviewPopup'], Artifacts_Info_Pane: infoPane['artifactsInfoPane'], Change_Project_Owner_Popup: interactivePopup['changeProjectOwnerPopup'], Common_Popup: interactivePopup['commonPopup'], diff --git a/tests/features/common/page-objects/interactive-popup.po.js b/tests/features/common/page-objects/interactive-popup.po.js index 3d2a2e27ba..5d261a96e8 100644 --- a/tests/features/common/page-objects/interactive-popup.po.js +++ b/tests/features/common/page-objects/interactive-popup.po.js @@ -115,15 +115,20 @@ const deployModelTable = { } } -const artifactsPreviewRow = { - root: '.pop-up-dialog .preview-body', +const artifactsPreviewTable = { + root: '.pop-up-dialog .item-artifacts__modal-preview', header: { - root: '', - sorters: {} + root: '.preview-item:nth-of-type(1)', + sorters: { + name: '.item-data__header:nth-of-type(1)', + path: '.item-data__path', + size: '.item-data__header:nth-of-type(3)', + updated: '.item-data__header:nth-of-type(4)' + } }, body: { row: { - root: '.preview-item', + root: '.preview-item:nth-of-type(2)', fields: { name: '.item-data__name', path: '.item-data__path', @@ -135,20 +140,6 @@ const artifactsPreviewRow = { } } -const artifactsPreviewHeader = { - root: '.pop-up-dialog', - header: {}, - body: { - root: '.preview-body', - row: { - root: '.preview-item:nth-of-type(1)', - fields: { - key: '.item-data' - } - } - } -} - const createFeatureVectorLabelsTable = { root: '[data-testid="labels-chips"] .chips-cell', header: {}, @@ -1464,6 +1455,7 @@ export default { previewPopup: { Title: By.css('.pop-up-dialog .pop-up-dialog__header'), Cross_Cancel_Button: commonCrossCancelButton, + Preview_Table: commonTable(artifactsPreviewTable), Preview_Modal_Container: By.css('.pop-up-dialog .item-artifacts__modal-preview'), Download_Button: By.css('.pop-up-dialog .preview-item:nth-of-type(2) .preview-body__download') }, @@ -1633,14 +1625,6 @@ export default { ), Schedule_Button: By.css('.feature-set-panel__schedule .btn__schedule') }, - artifactPreviewPopup: { - Cross_Cancel_Button: commonCrossCancelButton, - Preview_Row: commonTable(artifactsPreviewRow), - Preview_Header: commonTable(artifactsPreviewHeader), - Download_Button: By.css( - '.pop-up-dialog .preview-body .preview-item:nth-of-type(2) .preview-body__download' - ) - }, removeMemberPopup: { Title: By.css('.delete-member__pop-up .pop-up-dialog__header-text'), Remove_Member_Button: By.css('.delete-member__pop-up .btn-danger') @@ -1748,11 +1732,12 @@ export default { '[data-testid="select-body"] label' ) ), + Type_Filter_Element: By.css('[data-testid="type-form-field-select"]'), Type_Filter_Dropdown: dropdownComponent( generateDropdownGroup( '[data-testid="type-form-field-select"]', '[data-testid="select-header"]', - '.options-list .select__item:not(.hidden) .tooltip-wrapper' + '.select__item.multiple:not(.hidden) label' ) ), Show_Iterations_Checkbox: checkboxComponent({ @@ -1771,6 +1756,62 @@ export default { icon: '' } }), + Type_All_Checkbox: checkboxComponent({ + root: '[data-testid="select-checkbox"]:nth-of-type(1)', + elements: { + checkbox: 'input', + name: 'label', + icon: '' + } + }), + Type_Job_Checkbox: checkboxComponent({ + root: '[data-testid="select-checkbox"]:nth-of-type(2)', + elements: { + checkbox: 'input', + name: 'label', + icon: '' + } + }), + Type_Workflow_Checkbox: checkboxComponent({ + root: '[data-testid="select-checkbox"]:nth-of-type(3)', + elements: { + checkbox: 'input', + name: 'label', + icon: '' + } + }), + Type_Spark_Checkbox: checkboxComponent({ + root: '[data-testid="select-checkbox"]:nth-of-type(7)', + elements: { + checkbox: 'input', + name: 'label', + icon: '' + } + }), + Type_Horovod_Checkbox: checkboxComponent({ + root: '[data-testid="select-checkbox"]:nth-of-type(8)', + elements: { + checkbox: 'input', + name: 'label', + icon: '' + } + }), + Type_Dask_Checkbox: checkboxComponent({ + root: '[data-testid="select-checkbox"]:nth-of-type(9)', + elements: { + checkbox: 'input', + name: 'label', + icon: '' + } + }), + Type_Databricks_Checkbox: checkboxComponent({ + root: '[data-testid="select-checkbox"]:nth-of-type(10)', + elements: { + checkbox: 'input', + name: 'label', + icon: '' + } + }), Status_All_Checkbox: checkboxComponent({ root: '[data-testid="select-checkbox"]:nth-of-type(1)', elements: { diff --git a/tests/features/common/page-objects/llm-prompts.po.js b/tests/features/common/page-objects/llm-prompts.po.js index 9e1f4ab606..372510628a 100644 --- a/tests/features/common/page-objects/llm-prompts.po.js +++ b/tests/features/common/page-objects/llm-prompts.po.js @@ -82,6 +82,7 @@ const overallTable = { componentType: actionMenu, structure: actionMenuStructure }, + preview: '.table-body__cell:nth-of-type(8) [data-testid="quick-link-artifact-preview"]' } } } diff --git a/tests/features/datasets.feature b/tests/features/datasets.feature index da894c1002..8cb4de88dc 100644 --- a/tests/features/datasets.feature +++ b/tests/features/datasets.feature @@ -514,10 +514,19 @@ Feature: Datasets Page Then hover on cell with row index 2 in "name" column in "Datasets_Table" table on "Datasets" wizard When click on cell with row index 2 in "artifact_preview_btn" column in "Datasets_Table" table on "Datasets" wizard And wait load page - Then verify "Preview_Row" element visibility on "Artifact_Preview_Popup" wizard - Then verify "Cross_Cancel_Button" element visibility on "Artifact_Preview_Popup" wizard - Then check "download_btn" visibility in "Preview_Row" on "Artifact_Preview_Popup" wizard with 1 offset - Then click on "Download_Button" element on "Artifact_Preview_Popup" wizard + Then verify "Preview_Table" element visibility on "Preview_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then value in "name" column with "text" in "Preview_Table" on "Preview_Popup" wizard should contains "test_new_structure" + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard And wait load page And wait load page Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard @@ -527,7 +536,7 @@ Feature: Datasets Page Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard - Then click on "Cross_Cancel_Button" element on "Artifact_Preview_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard When click on cell with value "auto-trainer-train_test_set" in "name" column in "Datasets_Table" table on "Datasets" wizard And wait load page Then select "Preview" tab in "Info_Pane_Tab_Selector" on "Datasets_Info_Pane" wizard @@ -535,10 +544,19 @@ Feature: Datasets Page Then verify "Pop_Out_Button" element visibility on "Datasets_Info_Pane" wizard Then click on "Pop_Out_Button" element on "Datasets_Info_Pane" wizard And wait load page - Then verify "Preview_Row" element visibility on "Artifact_Preview_Popup" wizard - Then verify "Cross_Cancel_Button" element visibility on "Artifact_Preview_Popup" wizard - Then check "download_btn" visibility in "Preview_Row" on "Artifact_Preview_Popup" wizard with 1 offset - Then click on "Download_Button" element on "Artifact_Preview_Popup" wizard + Then verify "Preview_Table" element visibility on "Preview_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then value in "name" column with "text" in "Preview_Table" on "Preview_Popup" wizard should contains "auto-trainer-train_test_set" + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard And wait load page And wait load page Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard @@ -548,7 +566,7 @@ Feature: Datasets Page Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard - Then click on "Cross_Cancel_Button" element on "Artifact_Preview_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard @MLD @smoke diff --git a/tests/features/featureStore.feature b/tests/features/featureStore.feature index 29eabdbbd8..1c0ec54636 100644 --- a/tests/features/featureStore.feature +++ b/tests/features/featureStore.feature @@ -574,6 +574,7 @@ Feature: Feature Store Page And select "tab" with "Feature store" value in breadcrumbs menu And wait load page And select "Feature Vectors" tab in "Feature_Store_Tab_Selector" on "Feature_Store_Feature_Sets_Tab" wizard + And wait load page Then click on "Table_FilterBy_Button" element on "Feature_Store_Features_Vectors_Tab" wizard And wait load page When select "test-tag" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index 322ce07ea0..0ad945f71e 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -171,6 +171,61 @@ Feature: Jobs and workflows Then wait for 3 seconds Then verify "Schedule_Monitor_Table" element visibility on "Schedule_Monitor_Tab" wizard + @MLJW + @passive + @smoke + Scenario: MLJW092 - Check filter by Types options on Scheduled tab + Given open url + And wait load page + And click on row root with value "cat-vs-dog-classification" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + When click on "Scheduled_Stats_Counter" element in "Scheduled_Stats_Container" on "Project" wizard + And wait load page + Then verify "Schedule" tab is active in "Jobs_Tab_Selector" on "Jobs_Monitor_Tab" wizard + Then verify "Table_Name_Filter_Input" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Next 24 hours" + Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "Databricks" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Databricks" + When select "Dask" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Dask, Databricks" + When select "Horovod" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "3 items selected" + When select "Spark" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "4 items selected" + When select "Workflow" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Schedule_Monitor_Table" element visibility on "Schedule_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + When select "Job" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Schedule_Monitor_Table" element visibility on "Schedule_Monitor_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "Spark" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + When select "Horovod" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Spark, Horovod" + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Scheduled_Type" + @MLJW @passive @smoke @@ -621,6 +676,7 @@ Feature: Jobs and workflows @MLJW @passive @smoke + #TODO: add data for verifying iteration filtering of artifacts on the Artifacts tab of the detail run Scenario: MLJW065 - Check all mandatory components in Item infopane on Artifacts tab on Jobs Monitor Page Given open url And wait load page @@ -637,7 +693,7 @@ Feature: Jobs and workflows Then click on "Title" element on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page - When click on cell with value "trainer-train" in "name" column in "Jobs_Monitor_Table" table on "Jobs_Monitor_Tab" wizard + When click on cell with value "data_clean" in "name" column in "Jobs_Monitor_Table" table on "Jobs_Monitor_Tab" wizard And wait load page When click on cell with row index 1 in "name" column in "Jobs_Monitor_Table" table on "Jobs_Monitor_Tab" wizard And wait load page @@ -649,21 +705,46 @@ Feature: Jobs and workflows Then click on cell with row index 1 in "name" column in "Artifacts_Table" table on "Artifacts_Info_Pane" wizard Then click on "Artifact_Preview_Button" element on "Artifacts_Info_Pane" wizard And wait load page - Then verify "Preview_Row" element visibility on "Artifact_Preview_Popup" wizard - Then verify "Cross_Cancel_Button" element visibility on "Artifact_Preview_Popup" wizard - Then click on "Cross_Cancel_Button" element on "Artifact_Preview_Popup" wizard + Then verify "Preview_Table" element visibility on "Preview_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then value in "name" column with "text" in "Preview_Table" on "Preview_Popup" wizard should contains "data_clean" + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard + Then click on "Arrow_Back" element on "Jobs_Monitor_Tab_Info_Pane" wizard + And wait load page + When click on cell with value "trainer-train" in "name" column in "Jobs_Monitor_Table" table on "Jobs_Monitor_Tab" wizard + And wait load page + When click on cell with row index 1 in "name" column in "Jobs_Monitor_Table" table on "Jobs_Monitor_Tab" wizard And wait load page + And select "Artifacts" tab in "Info_Pane_Tab_Selector" on "Jobs_Monitor_Tab_Info_Pane" wizard + And wait load page + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Data" Then verify "Iterations_Dropdown" element visibility on "Artifacts_Info_Pane" wizard Then select "1" option in "Iterations_Dropdown" dropdown on "Artifacts_Info_Pane" wizard And wait load page - Then verify "Artifacts_Table" element visibility on "Artifacts_Info_Pane" wizard - Then click on cell with row index 1 in "name" column in "Artifacts_Table" table on "Artifacts_Info_Pane" wizard - Then click on "Artifact_Preview_Button" element on "Artifacts_Info_Pane" wizard - Then verify "Preview_Row" element visibility on "Artifact_Preview_Popup" wizard - Then click on "Cross_Cancel_Button" element on "Artifact_Preview_Popup" wizard - Then select "2" option in "Iterations_Dropdown" dropdown on "Artifacts_Info_Pane" wizard + Then select "5" option in "Iterations_Dropdown" dropdown on "Artifacts_Info_Pane" wizard And wait load page - Then verify "Artifacts_Table" element visibility on "Artifacts_Info_Pane" wizard + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Data" @MLJM @smoke @@ -1271,8 +1352,29 @@ Feature: Jobs and workflows Then click on cell with row index 1 in "name" column in "Artifacts_Table" table on "Artifacts_Info_Pane" wizard Then click on "Artifact_Preview_Button" element on "Artifacts_Info_Pane" wizard And wait load page - Then verify "Preview_Row" element visibility on "Artifact_Preview_Popup" wizard - Then verify "Cross_Cancel_Button" element visibility on "Artifact_Preview_Popup" wizard + Then verify "Preview_Table" element visibility on "Preview_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then value in "name" column with "text" in "Preview_Table" on "Preview_Popup" wizard should contains "data_clean" + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard @MLJW @passive diff --git a/tests/features/jobsMonitoring.feature b/tests/features/jobsMonitoring.feature index ead871e264..561ac2e71d 100644 --- a/tests/features/jobsMonitoring.feature +++ b/tests/features/jobsMonitoring.feature @@ -1084,7 +1084,18 @@ Feature: Jobs Monitoring Page Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" - Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then "Type_All_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard @@ -1097,7 +1108,7 @@ Feature: Jobs Monitoring Page Then verify "Total_Job_Counter_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard When click on "Total_Job_Counter_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard And wait load page - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=job&dates=next24hours" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=job%2Cspark%2Cmpijob%2Cdask%2Cdatabricks&dates=next24hours" And wait load page Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value @@ -1109,6 +1120,7 @@ Feature: Jobs Monitoring Page Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Scheduled_Tab" wizard selected option value "Next 24 hours" Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Jobs_Monitoring_Scheduled_Tab" wizard should contains "Dropdown_Options"."Scheduled_Date_Picker_Filter_Options" Then verify "Table_FilterBy_Button" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard + Then verify "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" Then verify "Refresh_Button" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then click on "Refresh_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard And wait load page @@ -1118,7 +1130,18 @@ Feature: Jobs Monitoring Page Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Job" + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard @@ -1143,12 +1166,24 @@ Feature: Jobs Monitoring Page Then verify "Date_Picker_Filter_Dropdown" dropdown on "Jobs_Monitoring_Scheduled_Tab" wizard selected option value "Next 24 hours" Then verify "Date_Picker_Filter_Dropdown" dropdown element on "Jobs_Monitoring_Scheduled_Tab" wizard should contains "Dropdown_Options"."Scheduled_Date_Picker_Filter_Options" Then verify "Table_FilterBy_Button" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard + Then verify "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then "Title" element on "FilterBy_Popup" should contains "Filter by" value Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard @@ -1251,10 +1286,34 @@ Feature: Jobs Monitoring Page Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then "Type_All_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page When select "Job" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + And wait load page Then click on "Title" element on "FilterBy_Popup" wizard + And wait load page Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then select "View YAML" option in action menu on "Jobs_Monitoring_Scheduled_Tab" wizard in "Scheduled_Table" table at row with "clean-data" value in "name" column Then verify if "View_YAML" popup dialog appears @@ -1264,22 +1323,86 @@ Feature: Jobs Monitoring Page And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Job" + When select "Job" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard When select "Workflow" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page - Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard - Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then select "View YAML" option in action menu on "Jobs_Monitoring_Scheduled_Tab" wizard in "Scheduled_Table" table at row with "main3" value in "name" column Then verify if "View_YAML" popup dialog appears Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard - + Then click on "Cross_Cancel_Button" element on "View_YAML" wizard + And wait load page + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" + + @MLJM + @smoke + Scenario: MLJM021 - Check filter by Types options on Scheduled tab of Jobs monitoring page + Given open url + And wait load page + When click on "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard + And wait load page + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard + Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard + Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "Databricks" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Databricks" + When select "Dask" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Dask, Databricks" + When select "Horovod" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "3 items selected" + When select "Spark" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "4 items selected" + When select "Workflow" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + When select "Job" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard + Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "Spark" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + When select "Horovod" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then click on "Title" element on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Spark, Horovod" + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_Scheduled_Type" + @MLJM @smoke - # TODO: Total wf counter = 4, 3 row elements are displayed - known bug (due to running not in 24h period), couln't be fixed yet + # TODO: Total wf counter = 4, 3 row elements are displayed - known bug (due to running not in 24h period), couldn't be fixed yet Scenario: MLJM012 - Check jobs/workflows/scheduled count consistency among counter data and Jobs monitoring Tabs Given open url And wait load page diff --git a/tests/features/llmPrompts.feature b/tests/features/llmPrompts.feature index 46c0bb06fd..6df7503c24 100644 --- a/tests/features/llmPrompts.feature +++ b/tests/features/llmPrompts.feature @@ -203,12 +203,12 @@ Feature: LLM prompts Page Then verify "show_all_versions" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column should display hover tooltip "Common_Tooltips"."Show_All_Versions" with scroll "false" Then click on cell with row index 1 in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard And wait load page - Then verify "Header" element visibility on "LM_Prompts_Info_Pane" wizard + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard Then check "Show_Iterations_Checkbox" element on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page - Then verify "Header" element not exists on "LM_Prompts_Info_Pane" wizard + Then verify "Header" element not exists on "LLM_Prompts_Info_Pane" wizard Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard Then "Show_Iterations_Checkbox" element should be checked on "FilterBy_Popup" wizard @@ -440,7 +440,6 @@ Feature: LLM prompts Page @MLLP @smoke - @uniqueTag Scenario: MLLP009 - Check components on prompt version history page Given open url And wait load page @@ -479,3 +478,382 @@ Feature: LLM prompts Page Then "Header" element on "LLM_Prompts_Info_Pane" should contains "my_llm" value Then click on "History_Back_Button" element on "LLM_Prompts" wizard Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + + @MLLP + @smoke + Scenario: MLLP010 - Verify action menu list options on main llm prompts list + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then verify action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then select "Download" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then select "View YAML" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column + Then verify if "View_YAML" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard + Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard + Then click on "Cross_Cancel_Button" element on "View_YAML" wizard + Then select "Copy URI" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Copied to clipboard successfully" value + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then click on cell with row index 1 in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" dropdown element on "LLM_Prompts_Info_Pane" wizard should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then select "Download" option in action menu on "LLM_Prompts_Info_Pane" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then select "View YAML" option in action menu on "LLM_Prompts_Info_Pane" wizard + Then verify if "View_YAML" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard + Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard + Then click on "Cross_Cancel_Button" element on "View_YAML" wizard + Then select "Copy URI" option in action menu on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Copied to clipboard successfully" value + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then click on "Cross_Close_Button" element on "LLM_Prompts_Info_Pane" wizard + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then select "Add a tag" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "instructions" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Tag was added successfully" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then select "instructions" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "my_llm" in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then check "instructions" value in "tag" column in "Overview_Table" table on "LLM_Prompts_Info_Pane" wizard + Then select "Add a tag" option in action menu on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "criteria" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Tag was added successfully" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then select "criteria" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "my_llm" in "name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then check "criteria" value in "tag" column in "Overview_Table" table on "LLM_Prompts_Info_Pane" wizard + + @MLLP + @smoke + Scenario: MLLP011 - Verify action menu list options on version history llm prompts list + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then verify "show_all_versions" option is present on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column + Then verify "show_all_versions" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column should display hover tooltip "Common_Tooltips"."Show_All_Versions" with scroll "false" + Then click on "show_all_versions" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column with scroll "false" + And wait load page + Then verify "History_Back_Button" element visibility on "LLM_Prompts" wizard + Then "Version_History_Prompt_Name" element on "LLM_Prompts" should contains "my_llm" value + Then verify "Refresh_Button" element visibility on "LLM_Prompts" wizard + Then verify "Table_FilterBy_Button" element visibility on "LLM_Prompts" wizard + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then "Show_Iterations_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then verify action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then verify action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then select "Download" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then select "View YAML" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column + Then verify if "View_YAML" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard + Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard + Then click on "Cross_Cancel_Button" element on "View_YAML" wizard + Then select "Copy URI" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Copied to clipboard successfully" value + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "History_Back_Button" element visibility on "LLM_Prompts" wizard + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + When click on cell with row index 1 in "uid" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then verify "Header" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "LLM_Prompts_Info_Pane" wizard + Then verify "Action_Menu" dropdown element on "LLM_Prompts_Info_Pane" wizard should contains "Common_Lists"."Action_Menu_List_LLM_Prompt" + Then select "Download" option in action menu on "LLM_Prompts_Info_Pane" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then select "View YAML" option in action menu on "LLM_Prompts_Info_Pane" wizard + Then verify if "View_YAML" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard + Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard + Then click on "Cross_Cancel_Button" element on "View_YAML" wizard + Then select "Copy URI" option in action menu on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Copied to clipboard successfully" value + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then click on "Cross_Close_Button" element on "LLM_Prompts_Info_Pane" wizard + Then verify "History_Back_Button" element visibility on "LLM_Prompts" wizard + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then select "Add a tag" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "context" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Tag was added successfully" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then select "context" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" in "uid" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then check "context" value in "tag" column in "Overview_Table" table on "LLM_Prompts_Info_Pane" wizard + Then select "Add a tag" option in action menu on "LLM_Prompts_Info_Pane" wizard + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "Final_Answer" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Tag was added successfully" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then select "Final_Answer" option in "Table_Tree_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" in "uid" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then check "Final_Answer" value in "tag" column in "Overview_Table" table on "LLM_Prompts_Info_Pane" wizard + + @MLLP + @smoke + #TODO: verify 'Add a Tag' behavior in Version History page when overwriting an existing prompt instance + Scenario: MLLP012 - Verify overwrite Add a tag option in action menu on llm prompts list + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then select "Add a tag" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "latest" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page + Then verify "Add_Button" element on "Add_Tag_Popup" wizard is disabled + Then type value "system" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Tag was added successfully" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then select "Add a tag" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "system" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then "Title" element on "Confirm_Popup" should contains "Overwrite LLM prompt?" value + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + Then verify "Confirm_Dialog_Message" element visibility on "Confirm_Popup" wizard + Then "Confirm_Dialog_Message" component on "Confirm_Popup" should be equal "Descriptions"."Add_A_Tag_Overwrite_Message" + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + Then "Cancel_Button" element on "Confirm_Popup" should contains "Cancel" value + Then verify "Overwrite_Button" element visibility on "Confirm_Popup" wizard + Then "Overwrite_Button" element on "Confirm_Popup" should contains "Overwrite" value + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then select "Add a tag" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column + And wait load page + Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard + Then type value "system" to "Tag_Input" field on "Add_Tag_Popup" wizard + Then click on "Add_Button" element on "Add_Tag_Popup" wizard + Then verify if "Confirm_Popup" popup dialog appears + Then "Title" element on "Confirm_Popup" should contains "Overwrite LLM prompt?" value + Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard + Then verify "Confirm_Dialog_Message" element visibility on "Confirm_Popup" wizard + Then "Confirm_Dialog_Message" component on "Confirm_Popup" should be equal "Descriptions"."Add_A_Tag_Overwrite_Message" + Then verify "Cancel_Button" element visibility on "Confirm_Popup" wizard + Then "Cancel_Button" element on "Confirm_Popup" should contains "Cancel" value + Then verify "Overwrite_Button" element visibility on "Confirm_Popup" wizard + Then "Overwrite_Button" element on "Confirm_Popup" should contains "Overwrite" value + When click on "Overwrite_Button" element on "Confirm_Popup" wizard + And wait load page + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + And wait load page + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Tag was added successfully" value + And wait load page + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + + @MLLP + @smoke + Scenario: MLLP013 - Verify prompt preview option on the main an version history llm prompts lists + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then verify "preview" option is present on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column + Then click on "preview" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column with scroll "false" + And wait load page + Then verify if "Preview_Popup" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Preview_Modal_Container" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard + Then verify "show_all_versions" option is present on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column + Then click on "show_all_versions" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "my_llm" value in "name" column with scroll "false" + And wait load page + Then verify "History_Back_Button" element visibility on "LLM_Prompts" wizard + Then "Version_History_Prompt_Name" element on "LLM_Prompts" should contains "my_llm" value + Then verify "preview" option is present on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column + Then click on "preview" option on "LLM_Prompts" wizard in "LLMPrompts_Table" table with "1d459c52a1102adcbbe242e6bb36e99129f2a8b9" value in "uid" column with scroll "false" + And wait load page + Then verify if "Preview_Popup" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Preview_Modal_Container" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard diff --git a/tests/features/models.feature b/tests/features/models.feature index 5aff9bd407..f2190170e3 100644 --- a/tests/features/models.feature +++ b/tests/features/models.feature @@ -680,10 +680,19 @@ Feature: Models Page Then verify "Pop_Out_Button" element visibility on "Models_Info_Pane" wizard Then click on "Pop_Out_Button" element on "Models_Info_Pane" wizard And wait load page - Then verify "Preview_Row" element visibility on "Artifact_Preview_Popup" wizard - Then verify "Cross_Cancel_Button" element visibility on "Artifact_Preview_Popup" wizard - Then check "download_btn" visibility in "Preview_Row" on "Artifact_Preview_Popup" wizard with 1 offset - Then click on "Download_Button" element on "Artifact_Preview_Popup" wizard + Then verify "Preview_Table" element visibility on "Preview_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then value in "name" column with "text" in "Preview_Table" on "Preview_Popup" wizard should contains "transaction_fraud_xgboost" + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard And wait load page And wait load page Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard @@ -693,7 +702,7 @@ Feature: Models Page Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard - Then click on "Cross_Cancel_Button" element on "Artifact_Preview_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard @MLM @passive diff --git a/tests/features/projectMonitoring.feature b/tests/features/projectMonitoring.feature index 331739397d..fd4f46e8fe 100644 --- a/tests/features/projectMonitoring.feature +++ b/tests/features/projectMonitoring.feature @@ -945,6 +945,17 @@ Feature: Project Monitoring Page Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then "Type_All_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page Then verify "Batch_Run_Button" element visibility on "Schedule_Monitor_Tab" wizard Then "Batch_Run_Button" element on "Schedule_Monitor_Tab" should contains "Batch run" value Then verify "Table_Refresh_Button" element visibility on "Schedule_Monitor_Tab" wizard @@ -958,8 +969,20 @@ Feature: Project Monitoring Page Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Next 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Job" + Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page Then verify "Batch_Run_Button" element visibility on "Schedule_Monitor_Tab" wizard Then "Batch_Run_Button" element on "Schedule_Monitor_Tab" should contains "Batch run" value Then verify "Table_Refresh_Button" element visibility on "Schedule_Monitor_Tab" wizard @@ -973,8 +996,20 @@ Feature: Project Monitoring Page Then verify "Date_Picker_Filter_Dropdown" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Next 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard + Then verify "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page + Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Job_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Workflow_Checkbox" element should be checked on "FilterBy_Popup" wizard + Then "Type_Spark_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Horovod_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Dask_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard + Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard + And wait load page Then verify "Batch_Run_Button" element visibility on "Schedule_Monitor_Tab" wizard Then "Batch_Run_Button" element on "Schedule_Monitor_Tab" should contains "Batch run" value Then verify "Table_Refresh_Button" element visibility on "Schedule_Monitor_Tab" wizard diff --git a/tests/features/projectsPage.feature b/tests/features/projectsPage.feature index 046c4ef928..2ef665505c 100644 --- a/tests/features/projectsPage.feature +++ b/tests/features/projectsPage.feature @@ -540,7 +540,7 @@ Feature: Projects Page Then navigate back And wait load page When click on "Total_Job_Counter_Number" element in "Monitoring_Scheduled_Box" on "Projects" wizard - Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=job&dates=next24hours" + Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=job%2Cspark%2Cmpijob%2Cdask%2Cdatabricks&dates=next24hours" Then verify breadcrumbs "cross" label should be equal "Jobs monitoring" value Then verify breadcrumbs "projectsPage" label should be equal "Projects" value And wait load page diff --git a/tests/features/step-definitions/steps.js b/tests/features/step-definitions/steps.js index 432592296a..54b9ec9d90 100644 --- a/tests/features/step-definitions/steps.js +++ b/tests/features/step-definitions/steps.js @@ -894,7 +894,7 @@ Then( Then( 'verify visibility of header column {string} in {string} table on {string} wizard', async function (columnName, tableName, wizardName) { - const locator = pageObjects[wizardName][tableName].headerSorters[columnName] + const locator = pageObjects[wizardName][tableName]['headerSorters'][columnName] await componentIsVisible(this.driver, locator) } ) diff --git a/tests/mockServer/data/artifacts.json b/tests/mockServer/data/artifacts.json index 164488df06..88bb5ecf95 100644 --- a/tests/mockServer/data/artifacts.json +++ b/tests/mockServer/data/artifacts.json @@ -40048,7 +40048,7 @@ "tag": "latest" }, "spec": { - "target_path": "v3io:///projects/llmdeploy332/artifacts/my_llm", + "target_path": "v3io:///projects/llmdeploy332/artifacts/my_llm.json", "size": 262, "license": "", "invocation_config": { From abd4015b718451f68ad12f10d7013881ef40050b Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:15:32 +0300 Subject: [PATCH 185/228] Fix [Feature vector] Detail popup issues (#3463) --- .../DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx | 4 ++-- tests/mockServer/data/artifacts.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx b/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx index 7559c04f65..0d861c1e24 100644 --- a/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx +++ b/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx @@ -49,8 +49,8 @@ const FeatureVectorPopUp = ({ featureVectorData, isOpen, onResolve }) => { ) const actionsMenu = useMemo( - () => generateActionsMenu(() => {}, toggleConvertedYaml, true), - [toggleConvertedYaml] + () => generateActionsMenu(dispatch, () => {}, toggleConvertedYaml, true), + [toggleConvertedYaml, dispatch] ) const pageData = useMemo(() => generatePageData(selectedFeatureVector), [selectedFeatureVector]) const detailsFormInitialValues = useMemo( diff --git a/tests/mockServer/data/artifacts.json b/tests/mockServer/data/artifacts.json index 88bb5ecf95..c03c6fc404 100644 --- a/tests/mockServer/data/artifacts.json +++ b/tests/mockServer/data/artifacts.json @@ -37534,7 +37534,7 @@ "sources": [ { "name": "dataset", - "path": "store://feature-vectors/default/short" + "path": "store://feature-vectors/default/default-fv" } ], "license": "" From 4e9c62130391284736c3a319fa7ff7a9e52156bb Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:17:32 +0300 Subject: [PATCH 186/228] Fix [Jobs monitoring] Infinite request issue (#3464) --- .../ProjectsJobsMonitoring.jsx | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.jsx b/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.jsx index 0b63cd81ad..bb2ab0d190 100644 --- a/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.jsx +++ b/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.jsx @@ -17,8 +17,8 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import React, { useLayoutEffect, useMemo, useState } from 'react' +import { useSelector } from 'react-redux' import { Outlet, useLocation, useNavigate, useParams } from 'react-router-dom' import { defaultsDeep, isEmpty } from 'lodash' @@ -49,7 +49,6 @@ import { parseWorkflowsQueryParamsCallback } from '../../utils/jobs.util' import { useJobsPageData } from '../../hooks/useJobsPageData' -import { fetchProjects } from '../../reducers/projectReducer' import './projectsJobsMonitoring.scss' @@ -72,9 +71,6 @@ const ProjectsJobsMonitoring = () => { const workflowsStore = useSelector(store => store.workflowsStore) const functionsStore = useSelector(store => store.functionsStore) const filtersStore = useSelector(store => store.filtersStore) - const [, setProjectsRequestErrorMessage] = useState('') - const projectStore = useSelector(state => state.projectStore) - const dispatch = useDispatch() const jobsFiltersConfig = useMemo( () => getJobsFiltersConfig(params.jobName, true), @@ -142,21 +138,6 @@ const ProjectsJobsMonitoring = () => { navigate(`/projects/*/${JOBS_MONITORING_PAGE}/${tabName}`) } - const fetchMinimalProjects = useCallback(() => { - dispatch( - fetchProjects({ - params: { format: 'minimal' }, - setRequestErrorMessage: setProjectsRequestErrorMessage - }) - ) - }, [dispatch]) - - useEffect(() => { - if (isEmpty(projectStore.projectsNames.data)) { - fetchMinimalProjects() - } - }, [fetchMinimalProjects, projectStore.projectsNames.data]) - useLayoutEffect(() => { setSelectedTab( location.pathname.includes(JOBS_MONITORING_WORKFLOWS_TAB) From 1b47e3e11147ee3b8a66bb91718ba67d773ca969 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:17:55 +0300 Subject: [PATCH 187/228] Fix [UI] UI issues (#3465) --- src/common/Download/downloadContainer.scss | 3 ++- .../MonitoringApplicationCard/MonitoringApplicationCard.jsx | 2 +- .../monitoringApplicationCounters.scss | 4 ++++ .../monitoringApplicationCounters.util.jsx | 6 +++++- src/elements/ProjectJobs/projectJobs.utils.js | 5 +---- .../projectsMonitoringCounters.scss | 5 +++-- src/utils/generateMonitoringData.js | 2 +- 7 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/common/Download/downloadContainer.scss b/src/common/Download/downloadContainer.scss index d5219a3bb2..f1e8093ff8 100644 --- a/src/common/Download/downloadContainer.scss +++ b/src/common/Download/downloadContainer.scss @@ -29,7 +29,8 @@ display: flex; flex-direction: column; max-height: 140px; - overflow-y: scroll; + overflow-x: hidden; + overflow-y: auto; .download-item { display: flex; diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx index 57a3858d66..6c74682fc8 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/MonitoringApplicationCard/MonitoringApplicationCard.jsx @@ -48,7 +48,7 @@ const MonitoringApplicationCard = ({ hidden={!counter.tooltipText} template={} > - + {loading ? ( ) : error || isNil(counter.title) ? ( diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss index 4676f27132..3303de6ac8 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.scss @@ -41,6 +41,10 @@ font-size: 28px; } + .stats__failed > .stats__counter { + color: colors.$amaranth; + } + .stats__status { margin-bottom: 10px; } diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index b0db895f48..41f863fbd7 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -18,6 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import { capitalize } from 'lodash' +import classNames from 'classnames' import { aggregateApplicationStatuses } from '../../../../utils/applications.utils' import { formatMinutesToString } from '../../../../utils/measureTime' @@ -64,9 +65,12 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => subtitleStatus: 'running' }, { + counterClassName: classNames({ + stats__failed: appError > 0 + }), id: 'failed', title: appError, - tooltipText: 'Failed, Error, Unhealthy', + tooltipText: 'Error, Unhealthy', subtitle: 'Failed', subtitleStatus: 'failed' } diff --git a/src/elements/ProjectJobs/projectJobs.utils.js b/src/elements/ProjectJobs/projectJobs.utils.js index 40ab03691d..e609236316 100644 --- a/src/elements/ProjectJobs/projectJobs.utils.js +++ b/src/elements/ProjectJobs/projectJobs.utils.js @@ -29,10 +29,7 @@ export const getJobsStatistics = (projectCounter, projectName) => { running: { value: projectCounter.error ? 'N/A' : projectCounter?.data?.runs_running_count, label: 'In Process', - className: - projectCounter.error || projectCounter?.data?.runs_running_count === 0 - ? 'default' - : 'running', + className: 'running', status: 'running', link: `/projects/${projectName}/jobs/${MONITOR_JOBS_TAB}`, counterTooltip: 'Aborting, Pending, Pending retry, Running', diff --git a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss index 884d0b2352..3bf732b97e 100644 --- a/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss +++ b/src/elements/ProjectsMonitoringCounters/projectsMonitoringCounters.scss @@ -74,8 +74,8 @@ .stats__line { position: relative; display: flex; - justify-content: space-between; align-items: center; + justify-content: space-between; width: 100%; padding-bottom: 0.5rem; } @@ -124,7 +124,8 @@ @include counterLinkHover; } - .stats__failed > .stats__counter { + .stats__failed > .stats__counter, + &.stats__failed > .stats__counter { color: colors.$amaranth; text-decoration: underline; text-underline-offset: 1px; diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index 6620cca8f9..e5ad8409ba 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -235,7 +235,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { statusClass: 'failed', label: FAILED, popUpClassName: classNames({ 'card-popup_text_link': projectName }), - tooltip: 'Failed, Error, Unhealthy' + tooltip: 'Error, Unhealthy' } ] } From ece6e8ddccc28fecc4581b0b6a9399439c5d99ab Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:18:12 +0300 Subject: [PATCH 188/228] Fix [Projects] 'No data' message is missing (#3466) --- src/components/ProjectsPage/ProjectsView.jsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/ProjectsPage/ProjectsView.jsx b/src/components/ProjectsPage/ProjectsView.jsx index bd29dd78c8..0892acb3e8 100644 --- a/src/components/ProjectsPage/ProjectsView.jsx +++ b/src/components/ProjectsPage/ProjectsView.jsx @@ -160,11 +160,12 @@ const ProjectsView = ({
      {projectStore.projects.length > 0 && !projectStore.error ? ( - filterByName.length > 0 && - (filterMatches.length === 0 || filteredProjects.length === 0) ? ( + filterByName.length > 0 && filterMatches.length === 0 ? ( + ) : filteredProjects.length === 0 ? ( + ) : selectedProjectsState === 'archived' && filteredProjects.length === 0 ? ( -
      No archived projects.
      + ) : (
      {filteredProjects.map(project => { From ac25565d8ae860426196a9eb711d83c2d1f024dc Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:18:37 +0300 Subject: [PATCH 189/228] Fix [Artifacts] tag uniques validation on UI (#3467) --- src/scss/main.scss | 6 ------ src/utils/artifacts.util.js | 5 ++++- tests/mockServer/mock.js | 32 +++++++++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/scss/main.scss b/src/scss/main.scss index daee56e3ac..3361e1bdff 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -550,12 +550,6 @@ div[id^='chartjs-tooltip'] { } } -/* =========== OVERRIDE ARTIFACT DIALOG ============= */ - -.override-artifact-dialog { - z-index: 10; -} - /* =========== ICONS ============= */ .table-severity-warning-icon { diff --git a/src/utils/artifacts.util.js b/src/utils/artifacts.util.js index 5dcf826035..cca4b5a3c0 100644 --- a/src/utils/artifacts.util.js +++ b/src/utils/artifacts.util.js @@ -144,7 +144,7 @@ export const processActionAfterTagUniquesValidation = ({ const messagesByKind = createArtifactMessages[artifact.kind.toLowerCase()] return artifactApi - .getExpandedArtifact(projectName, artifact.key || artifact.metadata.key, tag) + .getExpandedArtifact(projectName, artifact.db_key ?? artifact.spec.db_key ?? artifact.key , tag) .then(response => { if (response?.data) { if (!isEmpty(response.data.artifacts)) { @@ -155,11 +155,14 @@ export const processActionAfterTagUniquesValidation = ({ return _reject(...args) } + // hide and show loader again to avoid UI loader above confirmation dialog + hideLoader() openPopUp(ConfirmDialog, { confirmButton: { label: 'Overwrite', variant: PRIMARY_BUTTON, handler: () => { + showLoader() actionCallback().then(resolve).catch(reject).finally(hideLoader) } }, diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index beee93cf01..5d2fb13f9b 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -2367,9 +2367,35 @@ function putTags(req, res) { }) if (collectedArtifacts?.length > 0) { - let editedTag = cloneDeep(collectedArtifacts[0]) - editedTag.metadata ? (editedTag.metadata.tag = tagName) : (editedTag.tag = tagName) - artifacts.artifacts.push(editedTag) + let artifactWithEditedTag = cloneDeep(collectedArtifacts[0]) + artifactWithEditedTag.metadata + ? (artifactWithEditedTag.metadata.tag = tagName) + : (artifactWithEditedTag.tag = tagName) + + const collectedArtifactsWithSameName = artifacts.artifacts.filter(artifact => { + return ( + artifact.metadata?.project === req.params.project && + ((artifact.spec && artifact.spec.db_key === req.body.identifiers[0].key) || + artifact.metadata.key === req.body.identifiers[0].key) + ) + }) + + // handle existing artifacts with same name and tag + collectedArtifactsWithSameName.forEach(artifact => { + if (artifact.metadata?.tag === tagName) { + if ( + collectedArtifactsWithSameName.filter( + searchedArtifact => searchedArtifact.metadata.uid === artifact.metadata.uid + ).length > 1 + ) { + remove(artifacts.artifacts, artifact) + } else { + artifact.metadata.tag = null + } + } + }) + + artifacts.artifacts.push(artifactWithEditedTag) } res.send({ From 614c9690e62eb0871106bc5a6ef1ff85cc1ea9f1 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:48:57 +0300 Subject: [PATCH 190/228] Fix [UI] monitoring app page is not responding (#3468) --- .../MonitoringApplicationsPage/MonitoringApplicationsPage.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index e2041ecd30..7077180c27 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -94,7 +94,8 @@ const MonitoringApplicationsPage = () => { filters: { ...filters, labels: `mlrun/app-name=${params.name}` - } + }, + config: { params: { page: 1, 'page-size': 50, format: 'minimal'} } // limit to 50 artifacts the same as we have on Artifacts page per 1 FE page to avoid overload }) ) .unwrap() From 9a13e77f273d02d245c5d2bba334854356d8c8a9 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Thu, 23 Oct 2025 14:43:58 +0300 Subject: [PATCH 191/228] Fix [Projects] 'No data' message is missing (#3470) --- src/components/ProjectsPage/ProjectsView.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/ProjectsPage/ProjectsView.jsx b/src/components/ProjectsPage/ProjectsView.jsx index 0892acb3e8..64522cc25e 100644 --- a/src/components/ProjectsPage/ProjectsView.jsx +++ b/src/components/ProjectsPage/ProjectsView.jsx @@ -163,9 +163,7 @@ const ProjectsView = ({ filterByName.length > 0 && filterMatches.length === 0 ? ( ) : filteredProjects.length === 0 ? ( - - ) : selectedProjectsState === 'archived' && filteredProjects.length === 0 ? ( - + ) : (
      {filteredProjects.map(project => { From 27bc2304f4cd7eaade885efd335ba2edf181f25f Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Sun, 26 Oct 2025 10:49:17 +0200 Subject: [PATCH 192/228] Fix [Artifacts] Closing the overwrite message popup also closes the Register and Add Tag forms (#3472) --- .../RegisterArtifactModal.jsx | 46 ++++++++-------- src/utils/artifacts.util.js | 4 +- src/utils/createArtifact.util.js | 52 +++++++++++-------- 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx b/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx index da496174e5..0649e2b553 100644 --- a/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx +++ b/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx @@ -38,7 +38,7 @@ import { import artifactApi from '../../api/artifacts-api' import { ARTIFACT_TYPE } from '../../constants' import { convertChipsData } from '../../utils/convertChipsData' -import { createArtifactMessages } from '../../utils/createArtifact.util' +import { getArtifactMessagesByKind } from '../../utils/createArtifact.util' import { setFieldState, isSubmitDisabled } from 'igz-controls/utils/form.util' import { setNotification } from 'igz-controls/reducers/notificationReducer' import { useModalBlockHistory } from '../../hooks/useModalBlockHistory.hook' @@ -81,7 +81,7 @@ const RegisterArtifactModal = ({ const dispatch = useDispatch() const { handleCloseModal, resolveModal } = useModalBlockHistory(onResolve, formRef.current) const messagesByKind = useMemo(() => { - return createArtifactMessages[artifactKind.toLowerCase()] + return getArtifactMessagesByKind(artifactKind) }, [artifactKind]) const registerArtifact = values => { @@ -136,7 +136,7 @@ const RegisterArtifactModal = ({ }, onErrorCallback: resolveModal, showLoader: () => setIsLoading(true), - hideLoader: () => setIsLoading(false), + hideLoader: () => setIsLoading(false) }) } @@ -164,26 +164,26 @@ const RegisterArtifactModal = ({ {formState => { return ( <> - {isLoading && } - - - + {isLoading && } + + + ) }} diff --git a/src/utils/artifacts.util.js b/src/utils/artifacts.util.js index cca4b5a3c0..24da05b618 100644 --- a/src/utils/artifacts.util.js +++ b/src/utils/artifacts.util.js @@ -59,7 +59,7 @@ import { generateObjectNotInTheListMessage } from './generateMessage.util' import { openPopUp } from 'igz-controls/utils/common.util' import { ConfirmDialog } from 'igz-controls/components' import { PRIMARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' -import { createArtifactMessages } from './createArtifact.util' +import { getArtifactMessagesByKind } from './createArtifact.util' export const applyTagChanges = (changes, artifactItem, projectName, dispatch, setNotification) => { let updateTagMsg = 'Tag was updated' @@ -141,7 +141,7 @@ export const processActionAfterTagUniquesValidation = ({ return actionCallback().finally(hideLoader) } - const messagesByKind = createArtifactMessages[artifact.kind.toLowerCase()] + const messagesByKind = getArtifactMessagesByKind(artifact.kind) return artifactApi .getExpandedArtifact(projectName, artifact.db_key ?? artifact.spec.db_key ?? artifact.key , tag) diff --git a/src/utils/createArtifact.util.js b/src/utils/createArtifact.util.js index e4d431e104..4daf2c4bdb 100644 --- a/src/utils/createArtifact.util.js +++ b/src/utils/createArtifact.util.js @@ -23,27 +23,35 @@ const artifactSubTitle = const getOverwriteConfirmMessage = (existingKind = '') => `That combination of name and tag is already in use in an existing ${existingKind}. If you proceed, the existing ${existingKind} will be overwritten` -export const createArtifactMessages = { - artifact: { - title: - 'Register an artifact in MLRun so it can be used, for example, by functions, jobs, and pipelines.', - subTitle: artifactSubTitle, - overwriteConfirmTitle: 'Overwrite artifact?', - getOverwriteConfirmMessage - }, - dataset: { - title: - 'Register a dataset as an artifact in MLRun so it can be used, for example, by functions, jobs, and pipelines.', - subTitle: artifactSubTitle, - overwriteConfirmTitle: 'Overwrite dataset?', - getOverwriteConfirmMessage - }, - model: { - overwriteConfirmTitle: 'Overwrite model?', - getOverwriteConfirmMessage - }, - 'llm-prompt': { - overwriteConfirmTitle: 'Overwrite LLM prompt?', - getOverwriteConfirmMessage +export const getArtifactMessagesByKind = (kind = '') => { + const messagesByKind = { + artifact: { + title: + 'Register an artifact in MLRun so it can be used, for example, by functions, jobs, and pipelines.', + subTitle: artifactSubTitle, + overwriteConfirmTitle: 'Overwrite artifact?', + getOverwriteConfirmMessage + }, + dataset: { + title: + 'Register a dataset as an artifact in MLRun so it can be used, for example, by functions, jobs, and pipelines.', + subTitle: artifactSubTitle, + overwriteConfirmTitle: 'Overwrite dataset?', + getOverwriteConfirmMessage + }, + model: { + overwriteConfirmTitle: 'Overwrite model?', + getOverwriteConfirmMessage + }, + 'llm-prompt': { + overwriteConfirmTitle: 'Overwrite LLM prompt?', + getOverwriteConfirmMessage + }, + document: { + overwriteConfirmTitle: 'Overwrite document?', + getOverwriteConfirmMessage + } } + + return messagesByKind[kind.toLowerCase()] ?? messagesByKind['artifact'] } From 7463d2f6d958bdf496bc2a729fc07dd674651f92 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Sun, 26 Oct 2025 10:52:51 +0200 Subject: [PATCH 193/228] Fix [Project settings] tabs position should be static (#3469) --- src/components/ProjectSettings/projectSettings.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ProjectSettings/projectSettings.scss b/src/components/ProjectSettings/projectSettings.scss index a5a09d8df4..1cac62de27 100644 --- a/src/components/ProjectSettings/projectSettings.scss +++ b/src/components/ProjectSettings/projectSettings.scss @@ -4,12 +4,11 @@ @use 'igz-controls/scss/variables'; .settings-content { - padding: 15px 24px 10px; - .settings__card { width: 100%; - padding: 24px 0; + padding: 0 26px 24px 0; background-color: colors.$white; + overflow-y: auto; &-content { display: flex; From dc1ad66ff30e64080dba04cc0aee64878e713689 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:37:43 +0200 Subject: [PATCH 194/228] Fix [UI] Remove monitoring application counter from cross-projects view (#3471) --- .../ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx b/src/components/ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx index c82365fbe2..acf144e604 100644 --- a/src/components/ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx +++ b/src/components/ProjectsPage/ProjectsMonitoring/ProjectsMonitoring.jsx @@ -31,7 +31,6 @@ import WorkflowsCounters from '../../../elements/ProjectsMonitoringCounters/Work import { COUNTERS_GENERAL_MESSAGE } from '../../../constants' - import './projectsMonitoring.scss' const ProjectsMonitoring = () => { @@ -43,7 +42,7 @@ const ProjectsMonitoring = () => { return (
      - {!projectName && } + {!projectName && }
      {!projectName && } @@ -52,7 +51,7 @@ const ProjectsMonitoring = () => {
      - + {projectName && }
      {/* Todo: implement as part of ML-5460 From a31004f9f60f6fa557c8d5e3954add0589cf5540 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:10:49 +0200 Subject: [PATCH 195/228] Fix [Monitoring apps] Artifact tag is not displayed (#3475) --- .../MonitoringApplication.util.jsx | 3 +- src/elements/SectionTable/SectionTable.jsx | 52 +++++++++++-------- src/elements/SectionTable/SectionTable.scss | 24 ++++++++- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx index 01d6c50f5d..5a53de524f 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx @@ -43,7 +43,8 @@ export const generateArtifactsTableContent = (artifacts = []) => { return { name: { value: capitalize(artifact.db_key), - className: 'table-cell_big' + tag: artifact.tag, + className: 'table-cell_big table-cell_with-tag' }, artifactType: { value: artifact.kind || 'artifact', diff --git a/src/elements/SectionTable/SectionTable.jsx b/src/elements/SectionTable/SectionTable.jsx index bedafd369a..88811aaa2f 100644 --- a/src/elements/SectionTable/SectionTable.jsx +++ b/src/elements/SectionTable/SectionTable.jsx @@ -67,6 +67,7 @@ const SectionTable = ({ loading = false, params, table }) => { const tableValueClassName = classnames( 'section-table__table-cell', body[key].className, + key === 'name' && 'name-wrapper', key === 'status' && 'status-cell', key === 'status' && !Array.isArray(body[key].value) && @@ -80,30 +81,39 @@ const SectionTable = ({ loading = false, params, table }) => { ) : (
      {parsedUri?.key && (parsedUri?.uid || parsedUri.tree) && ( -
      -
      handleOpenArtifactPopUp()}> - } textShow> - {parsedUri.key} - - {parsedUri.tag} + <> +
      +
      handleOpenArtifactPopUp()}> + } textShow> + {parsedUri.key} + +
      -
      + {parsedUri.tag && ( + }> + {parsedUri.tag} + + )} + )} {parsedUri?.key && !parsedUri?.uid && !parsedUri.tree && ( <> }>{parsedUri.key} - {parsedUri.tag} + {parsedUri.tag && ( + }> + {parsedUri.tag} + + )} )}
      {key === 'name' ? ( - body[key].href ? ( - - } - textShow={true} + <> + {body[key].href ? ( + - {extractedItemName} - - - ) : body[key].link ? ( - - }> + } + textShow={true} + > + {extractedItemName} + + + ) : body[key].link ? ( + + }> + {body[key].value} + + + ) : ( + }> {body[key].value} - - ) : ( - }> - {body[key].value} - - ) + )} + + {body[key].tag ? ( + }> + {body[key].tag} + + ) : null} + ) : key === 'labels' ? ( ) : key === 'status' ? ( diff --git a/src/elements/SectionTable/SectionTable.scss b/src/elements/SectionTable/SectionTable.scss index fe9b3e1d0e..3f7828319b 100644 --- a/src/elements/SectionTable/SectionTable.scss +++ b/src/elements/SectionTable/SectionTable.scss @@ -45,7 +45,8 @@ &-cell { display: flex; - padding: 10px 5px 10px 0; + align-items: center; + padding: 8px 5px 8px 0; color: colors.$primary; line-height: 24px; @@ -89,6 +90,27 @@ margin-right: 5px; } + &.name-wrapper { + display: flex; + flex-wrap: wrap; + + &.table-cell_with-tag { + gap: 4px; + height: 57px; + } + + .item-name { + width: 100%; + } + + .item-tag { + display: inline; + max-width: 150px; + color: colors.$topaz; + line-height: 16px; + } + } + .table-body__cell { &_type { display: flex; From 850a240438084b919f635c8ce6ac0303d2769a17 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:10:58 +0200 Subject: [PATCH 196/228] Fix [Artifacts] Info banner is missing after refresh on full detail view (#3476) --- src/components/Artifacts/Artifacts.jsx | 30 +++++--------------------- src/utils/artifacts.util.js | 3 ++- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/components/Artifacts/Artifacts.jsx b/src/components/Artifacts/Artifacts.jsx index cc3a938a39..4bf940a671 100644 --- a/src/components/Artifacts/Artifacts.jsx +++ b/src/components/Artifacts/Artifacts.jsx @@ -40,7 +40,7 @@ import { TAG_FILTER, TAG_FILTER_ALL_ITEMS } from '../../constants' -import { checkForSelectedArtifact, setFullSelectedArtifact } from '../../utils/artifacts.util' +import { checkForSelectedArtifact } from '../../utils/artifacts.util' import { fetchArtifactsFunctions, fetchArtifactTags } from '../../reducers/artifactsReducer' import { fetchModelFeatureVector } from '../../reducers/detailsReducer' import { getCloseDetailsLink, isDetailsTabExists } from '../../utils/link-helper.util' @@ -412,29 +412,6 @@ const Artifacts = ({ const tableHeaders = useMemo(() => tableContent[0]?.content ?? [], [tableContent]) - const getAndSetSelectedArtifact = useCallback(() => { - setFullSelectedArtifact( - page, - tab, - dispatch, - navigate, - params.artifactName, - setSelectedArtifact, - params.projectName, - params.id, - isAllVersions - ) - }, [ - page, - tab, - dispatch, - navigate, - params.artifactName, - params.projectName, - params.id, - isAllVersions - ]) - useEffect(() => { if (params.id && pageData.details.menu.length > 0) { isDetailsTabExists(params.tab, pageData.details.menu, navigate, location) @@ -447,11 +424,12 @@ const Artifacts = ({ } }, [selectedArtifact]) - useEffect(() => { + const getAndSetSelectedArtifact = useCallback((ignoreLastCheckedArtifact = false) => { checkForSelectedArtifact({ artifactName: params.artifactName, artifacts: isAllVersions ? artifactVersions : artifacts, dispatch, + ignoreLastCheckedArtifact, isAllVersions, navigate, paginatedArtifacts: isAllVersions ? paginatedArtifactVersions : paginatedArtifacts, @@ -487,6 +465,8 @@ const Artifacts = ({ tab ]) + useEffect(() => getAndSetSelectedArtifact(true), [getAndSetSelectedArtifact]) + useEffect(() => { const tagAbortControllerCurrent = tagAbortControllerRef.current diff --git a/src/utils/artifacts.util.js b/src/utils/artifacts.util.js index 24da05b618..249d2a8dd3 100644 --- a/src/utils/artifacts.util.js +++ b/src/utils/artifacts.util.js @@ -320,6 +320,7 @@ export const checkForSelectedArtifact = debounce( artifactName, artifacts, dispatch, + ignoreLastCheckedArtifact = false, isAllVersions, navigate, paginatedArtifacts, @@ -340,7 +341,7 @@ export const checkForSelectedArtifact = debounce( if ( artifacts && searchBePage === configBePage && - lastCheckedArtifactIdRef.current !== paramsId + (lastCheckedArtifactIdRef.current !== paramsId || ignoreLastCheckedArtifact) ) { lastCheckedArtifactIdRef.current = paramsId From 00a192eb2f22cafff099d7c68f96202b0376921f Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:11:09 +0200 Subject: [PATCH 197/228] Fix [Feature vector] Statistic tab tooltip is missing (#3477) --- .../FeatureStore/FeatureVectors/featureVectors.util.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx b/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx index 210ace0b85..a5470d48ce 100644 --- a/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx +++ b/src/components/FeatureStore/FeatureVectors/featureVectors.util.jsx @@ -58,7 +58,8 @@ export const generateFeatureVectorsDetailsMenu = (selectedItem) => [ { label: 'statistics', id: 'statistics', - hidden: !selectedItem.stats && !selectedItem.features + hidden: !selectedItem.stats && !selectedItem.features, + tip: 'Note that some values may be empty due to the use of different engines for calculating statistics' }, { label: 'analysis', From cd5e9f54d2140a3b03e6359fe6eb94852a0fdad7 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:17:48 +0200 Subject: [PATCH 198/228] Fix [ESlint] test errors (#3479) --- eslint.config.mjs | 5 ++++- src/App.test.js | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 6ec622e15d..3abaec7655 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -13,7 +13,10 @@ export default [ files: ['**/*.{js,jsx,ts,tsx}'], languageOptions: { ecmaVersion: 2021, - globals: globals.browser, + globals: { + ...globals.browser, + ...globals.jest + }, parserOptions: { ecmaFeatures: { jsx: true diff --git a/src/App.test.js b/src/App.test.js index 720bf81e06..eb8e8bec16 100755 --- a/src/App.test.js +++ b/src/App.test.js @@ -18,11 +18,11 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import React from 'react' -import ReactDOM from 'react-dom' +import { createRoot } from 'react-dom/client' import App from './App' it('renders without crashing', () => { - const div = document.createElement('div') - ReactDOM.render(, div) - ReactDOM.unmountComponentAtNode(div) + const root = createRoot(document.getElementById('root')) + root.render() + root.unmount() }) From e620714db6397f57f508dee23d4cb6dfe88b1c34 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:23:19 +0200 Subject: [PATCH 199/228] Fix [Monitoring app] Result name , first char should not capitalised (#3480) --- .../MonitoringApplication/MonitoringApplication.util.jsx | 8 ++++---- .../MonitoringApplications/monitoringApplications.util.js | 3 +-- src/elements/ProjectFunctions/ProjectFunctions.jsx | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx index 5a53de524f..648d3eec29 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import prettyBytes from 'pretty-bytes' -import { capitalize, isNumber } from 'lodash' +import { isNumber } from 'lodash' import { METRIC_TYPE, RESULT_TYPE } from '../../../../constants' import { formatDatetime } from 'igz-controls/utils/datetime.util' @@ -42,7 +42,7 @@ export const generateArtifactsTableContent = (artifacts = []) => { const tableBody = artifacts.map(artifact => { return { name: { - value: capitalize(artifact.db_key), + value: artifact.db_key, tag: artifact.tag, className: 'table-cell_big table-cell_with-tag' }, @@ -89,7 +89,7 @@ export const generateResultsTableContent = (metrics = []) => { return { name: { - value: capitalize(result.result_name), + value: result.result_name, className: 'table-cell_medium' }, kind: { @@ -138,7 +138,7 @@ export const generateMetricsTableContent = (metrics = []) => { return { name: { - value: capitalize(metric.metric_name), + value: metric.metric_name, className: 'table-cell_medium' }, value: { diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js index 298b7e6eba..9fe4510b4f 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js @@ -17,7 +17,6 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { capitalize } from 'lodash' import classnames from 'classnames' import moment from 'moment' @@ -52,7 +51,7 @@ export const generateOperatingFunctionsTable = (functions, projectName) => { return { name: { - value: capitalize(func.name), + value: func.name, href: generateNuclioLink(`/projects/${projectName}/functions/${nuclioFunctionName}`), className: 'table-cell_big' }, diff --git a/src/elements/ProjectFunctions/ProjectFunctions.jsx b/src/elements/ProjectFunctions/ProjectFunctions.jsx index bf04d451f5..c9526f5ffd 100644 --- a/src/elements/ProjectFunctions/ProjectFunctions.jsx +++ b/src/elements/ProjectFunctions/ProjectFunctions.jsx @@ -92,7 +92,7 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { loading: nuclioStore.loading }, failed: { - counterTooltip: 'Failed, Error, Unhealthy', + counterTooltip: 'Error, Unhealthy', value: functionsFailed, label: 'Failed', status: 'failed', From a13cdd0a4abc6ecf89fc72a67851e1ac39e42fd2 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:41:09 +0200 Subject: [PATCH 200/228] Fix [ESlint] test errors (#3481) --- eslint.config.mjs | 3 ++- src/components/Jobs/JobsPage.test.js | 2 +- src/setupProxy.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 3abaec7655..7931152bd2 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -15,7 +15,8 @@ export default [ ecmaVersion: 2021, globals: { ...globals.browser, - ...globals.jest + ...globals.jest, + ...globals.node, }, parserOptions: { ecmaFeatures: { diff --git a/src/components/Jobs/JobsPage.test.js b/src/components/Jobs/JobsPage.test.js index c34249195e..32cf36f264 100644 --- a/src/components/Jobs/JobsPage.test.js +++ b/src/components/Jobs/JobsPage.test.js @@ -33,7 +33,7 @@ jest.mock('igz-controls/images/arrow.svg', () => ({ ReactComponent: 'arrow-icon' })) -jest.spyOn(mainHttpClient, 'delete').mockImplementation(path => { +jest.spyOn(mainHttpClient, 'delete').mockImplementation(() => { return Promise.resolve([]) }) diff --git a/src/setupProxy.js b/src/setupProxy.js index 571c9c827d..80056e64d8 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -28,7 +28,7 @@ module.exports = function (app) { headers: { Connection: 'keep-alive' }, - onProxyReq: function (proxyReq, req, res) { + onProxyReq: function (proxyReq) { proxyReq.setHeader('x-v3io-session-key', import.meta.env.VITE_MLRUN_V3IO_ACCESS_KEY) proxyReq.setHeader('x-remote-user', 'admin') } From 6e53f4df5ef183559d8b61564578eff5ef961d4c Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:23:33 +0100 Subject: [PATCH 201/228] Tests [QA] v1.10.0-rc32 (#3482) --- tests/features/MLFunction.feature | 2 +- tests/features/common-tools/common-consts.js | 4 +- .../common/page-objects/info-pane.po.js | 11 +- .../page-objects/interactive-popup.po.js | 12 +- .../features/common/page-objects/models.po.js | 1 + .../common/page-objects/project.po.js | 4 +- tests/features/jobsAndWorkflows.feature | 1 + tests/features/llmPrompts.feature | 9 + tests/features/models.feature | 94 +- tests/features/monitoringApp.feature | 2 +- tests/features/projectMonitoring.feature | 6 +- tests/mockServer/data/featureVectors.json | 2337 ++++++++++++++++- .../data/monitoringApplications.json | 46 + tests/mockServer/data/nuclioFunctions.json | 12 +- tests/mockServer/mock.js | 2 +- 15 files changed, 2516 insertions(+), 27 deletions(-) diff --git a/tests/features/MLFunction.feature b/tests/features/MLFunction.feature index ff3a114412..b876bbe46b 100644 --- a/tests/features/MLFunction.feature +++ b/tests/features/MLFunction.feature @@ -1110,7 +1110,7 @@ Feature: ML Functions Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard Then click on "Cross_Cancel_Button" element on "View_YAML" wizard - Then click on cell with row index 8 in "expand_btn" column in "Functions_Table" table on "ML_Functions" wizard + Then click on cell with row index 9 in "expand_btn" column in "Functions_Table" table on "ML_Functions" wizard And wait load page Then select "View YAML" option in action menu on "ML_Functions" wizard in "Functions_Table" table at row with "Nov 23, 2021, 10:31:51 AM" value in "name" column Then verify if "View_YAML" popup dialog appears diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index 940d46b3de..2061db0cc6 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -96,6 +96,7 @@ export default { }, Feature_Vectors_Info_Pane: { Tab_List: ['Overview', 'Requested Features', 'Analysis'], + Tab_List_Extended: ['Overview', 'Requested Features', 'Returned Features', 'Statistics', 'Analysis'], Overview_General_Headers: [ 'Description:', 'Labels:', @@ -428,7 +429,8 @@ export default { Expand_All_Button: 'Expand all', In_Process_Jobs: 'Aborting, Pending, Pending retry, Running', Running_Tip: 'Running, Terminating', - Failed_Tip: 'Failed', + Running: 'Running', + Failed_Tip: 'Error, Unhealthy', Failed_Jobs: 'Aborted, Error', Failed_Worflows: 'Error, Failed', Succeeded: 'Completed', diff --git a/tests/features/common/page-objects/info-pane.po.js b/tests/features/common/page-objects/info-pane.po.js index 4e1e87ef52..61e15d5fc6 100644 --- a/tests/features/common/page-objects/info-pane.po.js +++ b/tests/features/common/page-objects/info-pane.po.js @@ -157,6 +157,7 @@ const infoPaneOverviewProducerHeaders = { fields: { key: '.details-item__header', link: '.details-item__data .link', + producer_link: '.details-item__link', value: '.details-item__data' } } @@ -313,7 +314,7 @@ const infoPaneDriftHeaders = { } const filesInfoSourcesTable = { - root: '.info-sources .info-sources-table', + root: '.info-sources', header: { root: '.info-sources-table__header', sorters: { @@ -323,10 +324,12 @@ const filesInfoSourcesTable = { }, body: { row: { - root: '.info-sources-table__content', + root: '.info-sources__table', fields: { - name: '.info-sources-table__content-key .data-ellipsis', - path: '.info-sources-table__content-value' + name_key: '.info-sources__table-row:nth-of-type(1) .info-sources__table-key', + name_value: '.info-sources__table-row:nth-of-type(1) .info-sources__table-value', + path_key: '.info-sources__table-row:nth-of-type(2) .info-sources__table-key', + path_value: '.info-sources__table-row:nth-of-type(2) .info-sources__table-value' } } } diff --git a/tests/features/common/page-objects/interactive-popup.po.js b/tests/features/common/page-objects/interactive-popup.po.js index 5d261a96e8..0333ae1ac7 100644 --- a/tests/features/common/page-objects/interactive-popup.po.js +++ b/tests/features/common/page-objects/interactive-popup.po.js @@ -810,7 +810,10 @@ export default { Title_Function_Log_Info: By.css('.item-info > div > h3:nth-of-type(2)'), Content_Function_Log_Info: By.css('.item-info .table__item-logs:nth-of-type(2)'), Logs_Text_container: By.css('#overlay_container .table__item .table__item-logs-content'), - Logs_Refresh_Button: By.css('#overlay_container .table__item .logs-refresh') + Logs_Refresh_Button: By.css('#overlay_container .table__item .logs-refresh'), + Requested_Features_Table: By.css('.item-info .item-requested-features__table'), + Returned_Features_Table: By.css('.item-info .details-metadata__table'), + Statistics_Table: By.css('.item-info #DETAILS_STATISTICS_TABLE_ID') }, modalWizardForm: { Title: By.css('.modal .modal__header-title'), @@ -1734,6 +1737,13 @@ export default { ), Type_Filter_Element: By.css('[data-testid="type-form-field-select"]'), Type_Filter_Dropdown: dropdownComponent( + generateDropdownGroup( + '[data-testid="type-form-field-select"]', + '[data-testid="select-header"]', + '.options-list .select__item:not(.hidden) .tooltip-wrapper' + ) + ), + Type_Filter_Dropdown_Schedule: dropdownComponent( generateDropdownGroup( '[data-testid="type-form-field-select"]', '[data-testid="select-header"]', diff --git a/tests/features/common/page-objects/models.po.js b/tests/features/common/page-objects/models.po.js index d298177acd..cbd7b82d4c 100644 --- a/tests/features/common/page-objects/models.po.js +++ b/tests/features/common/page-objects/models.po.js @@ -193,6 +193,7 @@ const realTimePipelinesTable = { ) }, name: '.table-body__cell:nth-of-type(1) a.data-ellipsis', + name_link: '.table-body__cell:nth-of-type(1) a .link', type: '.table-body__cell:nth-of-type(2) .data-ellipsis', function: '.table-body__cell:nth-of-type(3) .data-ellipsis', action_menu: { diff --git a/tests/features/common/page-objects/project.po.js b/tests/features/common/page-objects/project.po.js index a5569fff89..a77339ba33 100644 --- a/tests/features/common/page-objects/project.po.js +++ b/tests/features/common/page-objects/project.po.js @@ -52,10 +52,10 @@ const realtimeFunctionsNuclioTable = { root: '.project-data-card__header', sorters: { title: '.project-data-card__header-text a', - running_counter_number: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-value .tooltip-wrapper', + running_counter_number: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-value.statistics_running', running_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label span', running_counter_icon: '.project-data-card__statistics-item:nth-of-type(1) .project-data-card__statistics-label i', - failed_counter_number: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-value .tooltip-wrapper', + failed_counter_number: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-value.statistics_failed', failed_counter_subtitle: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-label span', failed_counter_icon: '.project-data-card__statistics-item:nth-of-type(2) .project-data-card__statistics-label i', api_gateways_counter_number: '.project-data-card__statistics-item:nth-of-type(3) .project-data-card__statistics-value .tooltip-wrapper', diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index 0ad945f71e..c7ae1bedd5 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -430,6 +430,7 @@ Feature: Jobs and workflows And hover "MLRun_Logo" component on "commonPagesHeader" wizard And wait load page When pick up "Custom range" from "09/03/2021 00:00" to "09/04/2021 00:00" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard + And wait load page Then verify from "09/03/2021 00:00" to "09/04/2021 00:00" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitor_Tab" wizard diff --git a/tests/features/llmPrompts.feature b/tests/features/llmPrompts.feature index 6df7503c24..f2224ccb03 100644 --- a/tests/features/llmPrompts.feature +++ b/tests/features/llmPrompts.feature @@ -151,6 +151,9 @@ Feature: LLM prompts Page Then click on "Refresh_Button" element on "LLM_Prompts" wizard And wait load page Then value in "labels" column with "dropdowns" in "LLMPrompts_Table" on "LLM_Prompts" wizard should contains "language" in "Overlay" + Then type value "5" to "Search_By_Name_Filter_Input" field on "LLM_Prompts" wizard + Then click on "Refresh_Button" element on "LLM_Prompts" wizard + And wait load page Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard Then type value "type=qa" to "Table_Label_Filter_Input" field on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard @@ -750,6 +753,7 @@ Feature: LLM prompts Page Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard Then type value "system" to "Tag_Input" field on "Add_Tag_Popup" wizard Then click on "Add_Button" element on "Add_Tag_Popup" wizard + And wait load page Then verify if "Confirm_Popup" popup dialog appears Then "Title" element on "Confirm_Popup" should contains "Overwrite LLM prompt?" value Then verify "Cross_Cancel_Button" element visibility on "Confirm_Popup" wizard @@ -760,6 +764,11 @@ Feature: LLM prompts Page Then verify "Overwrite_Button" element visibility on "Confirm_Popup" wizard Then "Overwrite_Button" element on "Confirm_Popup" should contains "Overwrite" value When click on "Cancel_Button" element on "Confirm_Popup" wizard + When click on "Cancel_Button" element on "Add_Tag_Popup" wizard + Then verify if "Common_Popup" popup dialog appears + Then "Title" element on "Common_Popup" should contains "Are you sure?" value + Then "Description" element on "Common_Popup" should contains "All changes will be lost" value + Then click on "Confirm_Button" element on "Common_Popup" wizard Then select "Add a tag" option in action menu on "LLM_Prompts" wizard in "LLMPrompts_Table" table at row with "my_llm" value in "name" column And wait load page Then verify "Add_Tag_Popup" element visibility on "Add_Tag_Popup" wizard diff --git a/tests/features/models.feature b/tests/features/models.feature index f2190170e3..4b18a2520d 100644 --- a/tests/features/models.feature +++ b/tests/features/models.feature @@ -851,26 +851,103 @@ Feature: Models Page And wait load page Then verify "Header" element visibility on "Models_Info_Pane" wizard Then "Header" element on "Models_Info_Pane" should contains "test-model" value + Then click on "Table_FilterBy_Button" element on "Models" wizard + Then click on "Clear_Button" element on "FilterBy_Popup" wizard + And wait load page + When click on cell with value "train_model" in "name" column in "Models_Table" table on "Models" wizard + And wait load page + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Models_Info_Pane" wizard + Then verify "Overview_Producer_Headers" on "Models_Info_Pane" wizard should contains "Models_Info_Pane"."Overview_Producer_Headers" + When click on cell with value "sk-project-admin/3d03c190ad57442099024be6bb8f5895-3" in "producer_link" column in "Overview_Producer_Headers" table on "Models_Info_Pane" wizard + And wait load page + Then verify if "Modal_Transition_Popup" popup dialog appears + Then verify "Title" element visibility on "Modal_Transition_Popup" wizard + Then "Title" element on "Modal_Transition_Popup" should contains "train" value + Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard @MLM @passive @inProgress @smoke - Scenario: MLM028 - Check tab list compontnts on Model Item infopane + Scenario: MLM028 - Check Overview tab Sources components on Model Item infopane Given open url And wait load page - And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And click on row root with value "churn-project-admin" in "name" column in "Projects_Table" table on "Projects" wizard And wait load page And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard And click on cell with value "Models" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard And hover "MLRun_Logo" component on "commonPagesHeader" wizard And wait load page - When click on cell with row index 1 in "name" column in "Models_Table" table on "Models" wizard + When click on cell with value "transaction_fraud_adaboost" in "name" column in "Models_Table" table on "Models" wizard And wait load page Then verify "Info_Pane_Tab_Selector" element visibility on "Models_Info_Pane" wizard Then verify "Info_Pane_Tab_Selector" on "Models_Info_Pane" wizard should contains "Models_Info_Pane"."Tab_List_Extended" Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Models_Info_Pane" wizard Then verify "Overview_Sources_Headers" on "Models_Info_Pane" wizard should contains "Models_Info_Pane"."Overview_Sources_Headers" + Then check "dataset" value in "name_value" column in "Info_Sources_Table" table on "Models_Info_Pane" wizard + Then check "store://feature-vectors/churn-project-admin/transactions-fraud" value in "path_value" column in "Info_Sources_Table" table on "Models_Info_Pane" wizard + When click on cell with value "store://feature-vectors/churn-project-admin/transactions-fraud" in "path_value" column in "Info_Sources_Table" table on "Models_Info_Pane" wizard + And wait load page + Then verify if "Modal_Transition_Popup" popup dialog appears + Then verify "Title" element visibility on "Modal_Transition_Popup" wizard + Then "Title" element on "Modal_Transition_Popup" should contains "transactions-fraud" value + Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard + Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard + Then verify "Refresh_Button" element on "Modal_Transition_Popup" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + Then click on "Refresh_Button" element on "Modal_Transition_Popup" wizard + And wait load page + Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard + Then verify "Action_Menu" element visibility on "Modal_Transition_Popup" wizard + Then verify "Action_Menu" dropdown element on "Modal_Transition_Popup" wizard should contains "Common_Lists"."Action_Menu_List_Function_Transition_Popup" + Then select "View YAML" option in action menu on "Modal_Transition_Popup" wizard + And wait load page + Then verify if "View_YAML" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard + Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard + Then click on "Cross_Cancel_Button" element on "View_YAML" wizard + And wait load page + Then verify "Tab_Selector" element visibility on "Modal_Transition_Popup" wizard + Then verify "Tab_Selector" on "Modal_Transition_Popup" wizard should contains "Feature_Vectors_Info_Pane"."Tab_List_Extended" + Then verify "Overview" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify "Overview_General_Headers" on "Modal_Transition_Popup" wizard should contains "Feature_Vectors_Info_Pane"."Overview_General_Headers" + And select "Requested Features" tab in "Tab_Selector" on "Modal_Transition_Popup" wizard + And wait load page + Then verify "Requested Features" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify "Requested_Features_Table" element visibility on "Modal_Transition_Popup" wizard + And select "Returned Features" tab in "Tab_Selector" on "Modal_Transition_Popup" wizard + And wait load page + Then verify "Returned Features" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify "Returned_Features_Table" element visibility on "Modal_Transition_Popup" wizard + Then select "Statistics" tab in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify "Statistics" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify cell with "Statistics" value in "key" column in "Tab_Selector" table on "Modal_Transition_Popup" wizard should display "Label_Hint"."Models_Statistics" + Then verify "Statistics_Table" element visibility on "Modal_Transition_Popup" wizard + Then select "Analysis" tab in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify "Analysis" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should contains "No_Data_Message"."No_Data" + Then verify "Cross_Close_Button" element visibility on "Modal_Transition_Popup" wizard + Then click on "Cross_Close_Button" element on "Modal_Transition_Popup" wizard + And wait load page + Then verify "Info_Pane_Tab_Selector" element visibility on "Models_Info_Pane" wizard + Then verify "Info_Pane_Tab_Selector" on "Models_Info_Pane" wizard should contains "Models_Info_Pane"."Tab_List_Extended" + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Models_Info_Pane" wizard + When click on cell with value "current-state_model" in "name" column in "Models_Table" table on "Models" wizard + And wait load page + Then verify "Header" element visibility on "Models_Info_Pane" wizard + Then "Header" element on "Models_Info_Pane" should contains "current-state_model" value + Then check "dataset" value in "name_value" column in "Info_Sources_Table" table on "Models_Info_Pane" wizard + Then check "/User/demos/customer-churn-prediction/data/pipeline/eaae138e-439a-47fa-93c6-ba0fe1dc3b79/encoded-data.csv" value in "path_value" column in "Info_Sources_Table" table on "Models_Info_Pane" wizard + When click on cell with value "/User/demos/customer-churn-prediction/data/pipeline/eaae138e-439a-47fa-93c6-ba0fe1dc3b79/encoded-data.csv" in "path_value" column in "Info_Sources_Table" table on "Models_Info_Pane" wizard + And wait load page + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Copied to clipboard successfully" value + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then verify "Info_Pane_Tab_Selector" element visibility on "Models_Info_Pane" wizard + Then verify "Overview" tab is active in "Info_Pane_Tab_Selector" on "Models_Info_Pane" wizard @MLM @passive @@ -1039,8 +1116,9 @@ Feature: Models Page And select "Real-Time Pipelines" tab in "Models_Tab_Selector" on "Models" wizard And wait load page Then verify "Real-Time Pipelines" tab is active in "Models_Tab_Selector" on "Models" wizard - Then save to context "name" column and "href" attribute on 2 row from "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard - When click on cell with row index 2 in "name" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + Then save to context "name" column and "href" attribute on 3 row from "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + When click on cell with value "model-monitoring-stream" in "name_link" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + And wait load page And wait load page Then compare current browser URL with test "href" context value Then verify "Real_Time_Pipelines_Graph" element visibility on "Real_Time_Pipelines" wizard @@ -1051,7 +1129,7 @@ Feature: Models Page Then verify "Overview_Headers" on "Real_Time_Pipeline_Pane" wizard should contains "Real_Time_Pipeline_Pane"."Overview_Headers" Then click on "Arrow_Back" element on "Real_Time_Pipeline_Pane" wizard And wait load page - Then click on cell with row index 2 in "function" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + Then click on cell with row index 3 in "function" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard And wait load page Then verify if "Modal_Transition_Popup" popup dialog appears Then verify "Title" element visibility on "Modal_Transition_Popup" wizard @@ -1076,7 +1154,7 @@ Feature: Models Page Then verify "Cross_Close_Button" element visibility on "Modal_Transition_Popup" wizard Then click on "Cross_Close_Button" element on "Modal_Transition_Popup" wizard And wait load page - Then click on cell with row index 2 in "function" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + Then click on cell with row index 3 in "function" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard And wait load page Then verify if "Modal_Transition_Popup" popup dialog appears Then verify "Tab_Selector" element visibility on "Modal_Transition_Popup" wizard @@ -1099,7 +1177,7 @@ Feature: Models Page Then click on "Cross_Close_Button" element on "Modal_Transition_Popup" wizard And wait load page Then verify "Real_Time_Pipelines_Table" element visibility on "Real_Time_Pipelines" wizard - Then click on cell with row index 1 in "name" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + When click on cell with value "vizro" in "name_link" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard And wait load page And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard Then "No_Data_Message" element on "commonPagesHeader" should contains "The ingestion function has no steps and therefore no graph." value diff --git a/tests/features/monitoringApp.feature b/tests/features/monitoringApp.feature index 5f0888de04..49944a1b22 100644 --- a/tests/features/monitoringApp.feature +++ b/tests/features/monitoringApp.feature @@ -67,7 +67,7 @@ Feature: Monitoring app Page Then "Apps_Status_Running_SubTitle" element on "Monitoring_App" should contains "Running" value Then verify "Apps_Status_Running_Counter" element visibility on "Monitoring_App" wizard Then verify "Apps_Status_Running_Tip" element visibility on "Monitoring_App" wizard - Then verify "Apps_Status_Running_Tip" element on "Monitoring_App" wizard should display hover tooltip "Common_Tooltips"."Running_Tip" + Then verify "Apps_Status_Running_Tip" element on "Monitoring_App" wizard should display hover tooltip "Common_Tooltips"."Running" Then verify "Apps_Status_Failed_SubTitle" element visibility on "Monitoring_App" wizard Then "Apps_Status_Failed_SubTitle" element on "Monitoring_App" should contains "Failed" value Then verify "Apps_Status_Failed_Counter" element visibility on "Monitoring_App" wizard diff --git a/tests/features/projectMonitoring.feature b/tests/features/projectMonitoring.feature index fd4f46e8fe..40d7177bd5 100644 --- a/tests/features/projectMonitoring.feature +++ b/tests/features/projectMonitoring.feature @@ -944,7 +944,7 @@ Feature: Project Monitoring Page Then verify "Date_Picker_Filter_Dropdown" dropdown on "Schedule_Monitor_Tab" wizard selected option value "Next 24 hours" Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page Then "Type_All_Checkbox" element should be checked on "FilterBy_Popup" wizard @@ -971,7 +971,7 @@ Feature: Project Monitoring Page Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard @@ -998,7 +998,7 @@ Feature: Project Monitoring Page Then verify "Table_FilterBy_Button" element visibility on "Schedule_Monitor_Tab" wizard Then verify "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" Then click on "Table_FilterBy_Button" element on "Schedule_Monitor_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard diff --git a/tests/mockServer/data/featureVectors.json b/tests/mockServer/data/featureVectors.json index f5a3a35b77..cd973f5f91 100644 --- a/tests/mockServer/data/featureVectors.json +++ b/tests/mockServer/data/featureVectors.json @@ -7973,6 +7973,2341 @@ } } } - } + }, + { + "kind": "FeatureVector", + "metadata": { + "name": "transactions-fraud", + "project": "churn-project-admin", + "tag": "latest", + "labels": {}, + "updated": "2025-09-30T15:57:17.432089+00:00", + "created": "2025-09-30T15:56:50.695000", + "uid": null + }, + "spec": { + "description": "Predicting a fraudulent transaction", + "graph": { + "engine": "async", + "track_models": false + }, + "features": [ + "events.*", + "transactions.amount_max_2h", + "transactions.amount_sum_2h", + "transactions.amount_count_2h", + "transactions.amount_avg_2h", + "transactions.amount_max_12h", + "transactions.amount_sum_12h", + "transactions.amount_count_12h", + "transactions.amount_avg_12h", + "transactions.amount_max_24h", + "transactions.amount_sum_24h", + "transactions.amount_count_24h", + "transactions.amount_avg_24h", + "transactions.es_transportation_sum_14d", + "transactions.es_health_sum_14d", + "transactions.es_otherservices_sum_14d", + "transactions.es_food_sum_14d", + "transactions.es_hotelservices_sum_14d", + "transactions.es_barsandrestaurants_sum_14d", + "transactions.es_tech_sum_14d", + "transactions.es_sportsandtoys_sum_14d", + "transactions.es_wellnessandbeauty_sum_14d", + "transactions.es_hyper_sum_14d", + "transactions.es_fashion_sum_14d", + "transactions.es_home_sum_14d", + "transactions.es_travel_sum_14d", + "transactions.es_leisure_sum_14d", + "transactions.gender_F", + "transactions.gender_M", + "transactions.step", + "transactions.amount", + "transactions.timestamp_hour", + "transactions.timestamp_day_of_week" + ], + "label_feature": "labels.label" + }, + "status": { + "state": "created", + "label_column": "label", + "stats": { + "event_password_change": { + "count": 82092, + "mean": 0.38064610437070606, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 1, + "std": 0.4855486787827919, + "hist": [ + [ + 50844, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 31248 + ], + [ + 0, + 0.05, + 0.1, + 0.15000000000000002, + 0.2, + 0.25, + 0.30000000000000004, + 0.35000000000000003, + 0.4, + 0.45, + 0.5, + 0.55, + 0.6000000000000001, + 0.65, + 0.7000000000000001, + 0.75, + 0.8, + 0.8500000000000001, + 0.9, + 0.9500000000000001, + 1 + ] + ] + }, + "event_details_change": { + "count": 82092, + "mean": 0.2858743848365249, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 1, + "std": 0.4518326103856129, + "hist": [ + [ + 58624, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 23468 + ], + [ + 0, + 0.05, + 0.1, + 0.15000000000000002, + 0.2, + 0.25, + 0.30000000000000004, + 0.35000000000000003, + 0.4, + 0.45, + 0.5, + 0.55, + 0.6000000000000001, + 0.65, + 0.7000000000000001, + 0.75, + 0.8, + 0.8500000000000001, + 0.9, + 0.9500000000000001, + 1 + ] + ] + }, + "event_login": { + "count": 82092, + "mean": 0.3334795107927691, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 1, + "std": 0.47145904837053226, + "hist": [ + [ + 54716, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 27376 + ], + [ + 0, + 0.05, + 0.1, + 0.15000000000000002, + 0.2, + 0.25, + 0.30000000000000004, + 0.35000000000000003, + 0.4, + 0.45, + 0.5, + 0.55, + 0.6000000000000001, + 0.65, + 0.7000000000000001, + 0.75, + 0.8, + 0.8500000000000001, + 0.9, + 0.9500000000000001, + 1 + ] + ] + }, + "amount_max_2h": { + "count": 10000, + "mean": 82.167229, + "min": 0.05, + "25%": 39.9275, + "50%": 53.205, + "75%": 69.55, + "max": 7635.41, + "std": 233.1742143601985, + "hist": [ + [ + 9845, + 84, + 29, + 19, + 2, + 3, + 0, + 0, + 7, + 0, + 4, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 4 + ], + [ + 0.05, + 381.818, + 763.5859999999999, + 1145.3539999999998, + 1527.1219999999998, + 1908.8899999999999, + 2290.658, + 2672.426, + 3054.194, + 3435.962, + 3817.73, + 4199.498, + 4581.266, + 4963.034, + 5344.802, + 5726.57, + 6108.338, + 6490.106, + 6871.874, + 7253.642, + 7635.41 + ] + ] + }, + "amount_sum_2h": { + "count": 10000, + "mean": 175.44363499999997, + "min": 0.05, + "25%": 86.5375, + "50%": 139.82999999999998, + "75%": 208.88500000000002, + "max": 7731.7, + "std": 255.86760733153568, + "hist": [ + [ + 9532, + 377, + 48, + 9, + 10, + 4, + 2, + 0, + 0, + 7, + 3, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 4 + ], + [ + 0.05, + 386.6325, + 773.2149999999999, + 1159.7975, + 1546.3799999999999, + 1932.9624999999999, + 2319.545, + 2706.1275, + 3092.71, + 3479.2925, + 3865.875, + 4252.4574999999995, + 4639.04, + 5025.6225, + 5412.205, + 5798.787499999999, + 6185.37, + 6571.9525, + 6958.535, + 7345.117499999999, + 7731.7 + ] + ] + }, + "amount_count_2h": { + "count": 10000, + "mean": 4.8871, + "min": 1, + "25%": 3, + "50%": 5, + "75%": 6, + "max": 15, + "std": 2.314581888577696, + "hist": [ + [ + 484, + 997, + 1526, + 0, + 1753, + 1625, + 0, + 1334, + 948, + 0, + 618, + 366, + 180, + 0, + 86, + 44, + 0, + 23, + 13, + 3 + ], + [ + 1, + 1.7, + 2.4, + 3.0999999999999996, + 3.8, + 4.5, + 5.199999999999999, + 5.8999999999999995, + 6.6, + 7.3, + 8, + 8.7, + 9.399999999999999, + 10.1, + 10.799999999999999, + 11.5, + 12.2, + 12.899999999999999, + 13.6, + 14.299999999999999, + 15 + ] + ] + }, + "amount_avg_2h": { + "count": 10000, + "mean": 38.61512201386391, + "min": 0.05, + "25%": 22.85108333333333, + "50%": 29.39089285714286, + "75%": 37.98785714285715, + "max": 5468.17, + "std": 99.12880723644561, + "hist": [ + [ + 9945, + 32, + 8, + 3, + 0, + 4, + 0, + 4, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ], + [ + 0.05, + 273.456, + 546.862, + 820.268, + 1093.674, + 1367.08, + 1640.486, + 1913.892, + 2187.2980000000002, + 2460.704, + 2734.11, + 3007.516, + 3280.9220000000005, + 3554.3280000000004, + 3827.7340000000004, + 4101.14, + 4374.546, + 4647.952, + 4921.358, + 5194.764, + 5468.17 + ] + ] + }, + "amount_max_12h": { + "count": 10000, + "mean": 217.180914, + "min": 0.05, + "25%": 72.2, + "50%": 97.41, + "75%": 183.97, + "max": 7635.41, + "std": 574.7305154744495, + "hist": [ + [ + 9357, + 296, + 97, + 97, + 5, + 26, + 0, + 0, + 38, + 0, + 23, + 16, + 0, + 0, + 19, + 0, + 0, + 0, + 0, + 26 + ], + [ + 0.05, + 381.818, + 763.5859999999999, + 1145.3539999999998, + 1527.1219999999998, + 1908.8899999999999, + 2290.658, + 2672.426, + 3054.194, + 3435.962, + 3817.73, + 4199.498, + 4581.266, + 4963.034, + 5344.802, + 5726.57, + 6108.338, + 6490.106, + 6871.874, + 7253.642, + 7635.41 + ] + ] + }, + "amount_sum_12h": { + "count": 10000, + "mean": 987.761435, + "min": 0.05, + "25%": 688.1524999999999, + "50%": 943.855, + "75%": 1163.3075000000001, + "max": 9266.04, + "std": 706.9679061427487, + "hist": [ + [ + 1252, + 3562, + 4195, + 624, + 145, + 46, + 27, + 24, + 17, + 29, + 27, + 9, + 11, + 5, + 1, + 0, + 0, + 6, + 3, + 17 + ], + [ + 0.05, + 463.3495000000001, + 926.6490000000001, + 1389.9485000000002, + 1853.2480000000003, + 2316.5475000000006, + 2779.8470000000007, + 3243.1465000000007, + 3706.446000000001, + 4169.745500000001, + 4633.045000000001, + 5096.344500000001, + 5559.644000000001, + 6022.943500000001, + 6486.243000000001, + 6949.542500000001, + 7412.8420000000015, + 7876.1415000000015, + 8339.441, + 8802.7405, + 9266.04 + ] + ] + }, + "amount_count_12h": { + "count": 10000, + "mean": 27.5866, + "min": 1, + "25%": 22, + "50%": 30, + "75%": 35, + "max": 52, + "std": 10.668012049492107, + "hist": [ + [ + 279, + 301, + 189, + 330, + 248, + 394, + 263, + 487, + 425, + 814, + 1097, + 849, + 1389, + 938, + 1064, + 443, + 321, + 99, + 55, + 15 + ], + [ + 1, + 3.55, + 6.1, + 8.649999999999999, + 11.2, + 13.75, + 16.299999999999997, + 18.849999999999998, + 21.4, + 23.95, + 26.5, + 29.049999999999997, + 31.599999999999998, + 34.15, + 36.699999999999996, + 39.25, + 41.8, + 44.349999999999994, + 46.9, + 49.449999999999996, + 52 + ] + ] + }, + "amount_avg_12h": { + "count": 10000, + "mean": 39.690992824939386, + "min": 0.05, + "25%": 27.973053724456165, + "50%": 31.49118154158215, + "75%": 36.44510416666667, + "max": 5468.17, + "std": 77.19114246739247, + "hist": [ + [ + 9909, + 77, + 6, + 3, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 0.05, + 273.456, + 546.862, + 820.268, + 1093.674, + 1367.08, + 1640.486, + 1913.892, + 2187.2980000000002, + 2460.704, + 2734.11, + 3007.516, + 3280.9220000000005, + 3554.3280000000004, + 3827.7340000000004, + 4101.14, + 4374.546, + 4647.952, + 4921.358, + 5194.764, + 5468.17 + ] + ] + }, + "amount_max_24h": { + "count": 10000, + "mean": 289.69621199999995, + "min": 0.05, + "25%": 86.41, + "50%": 147.62, + "75%": 228.89, + "max": 7635.41, + "std": 685.5336807658961, + "hist": [ + [ + 9055, + 397, + 129, + 169, + 10, + 49, + 0, + 0, + 62, + 0, + 32, + 25, + 0, + 0, + 44, + 0, + 0, + 0, + 0, + 28 + ], + [ + 0.05, + 381.818, + 763.5859999999999, + 1145.3539999999998, + 1527.1219999999998, + 1908.8899999999999, + 2290.658, + 2672.426, + 3054.194, + 3435.962, + 3817.73, + 4199.498, + 4581.266, + 4963.034, + 5344.802, + 5726.57, + 6108.338, + 6490.106, + 6871.874, + 7253.642, + 7635.41 + ] + ] + }, + "amount_sum_24h": { + "count": 10000, + "mean": 1690.288283, + "min": 0.05, + "25%": 1022.9075000000001, + "50%": 1759.455, + "75%": 2179.6399999999994, + "max": 10144.09, + "std": 1044.6191477481475, + "hist": [ + [ + 1190, + 1291, + 1516, + 2608, + 2403, + 532, + 179, + 61, + 61, + 26, + 31, + 37, + 1, + 11, + 14, + 11, + 0, + 0, + 0, + 28 + ], + [ + 0.05, + 507.25200000000007, + 1014.4540000000001, + 1521.6560000000002, + 2028.8580000000002, + 2536.0600000000004, + 3043.2620000000006, + 3550.4640000000004, + 4057.6660000000006, + 4564.868, + 5072.070000000001, + 5579.272000000001, + 6086.474000000001, + 6593.676000000001, + 7100.878000000001, + 7608.080000000001, + 8115.282000000001, + 8622.484, + 9129.686, + 9636.888, + 10144.09 + ] + ] + }, + "amount_count_24h": { + "count": 10000, + "mean": 47.6612, + "min": 1, + "25%": 28, + "50%": 54, + "75%": 67, + "max": 90, + "std": 23.04833480175332, + "hist": [ + [ + 444, + 367, + 433, + 356, + 441, + 371, + 488, + 359, + 452, + 408, + 401, + 565, + 522, + 986, + 950, + 1244, + 699, + 423, + 80, + 11 + ], + [ + 1, + 5.45, + 9.9, + 14.350000000000001, + 18.8, + 23.25, + 27.700000000000003, + 32.150000000000006, + 36.6, + 41.050000000000004, + 45.5, + 49.95, + 54.400000000000006, + 58.85, + 63.300000000000004, + 67.75, + 72.2, + 76.65, + 81.10000000000001, + 85.55, + 90 + ] + ] + }, + "amount_avg_24h": { + "count": 10000, + "mean": 39.9029276006047, + "min": 0.05, + "25%": 29.000666666666664, + "50%": 31.887500000000003, + "75%": 36.11239864864865, + "max": 5468.17, + "std": 75.22140915109931, + "hist": [ + [ + 9943, + 45, + 5, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 + ], + [ + 0.05, + 273.456, + 546.862, + 820.268, + 1093.674, + 1367.08, + 1640.486, + 1913.892, + 2187.2980000000002, + 2460.704, + 2734.11, + 3007.516, + 3280.9220000000005, + 3554.3280000000004, + 3827.7340000000004, + 4101.14, + 4374.546, + 4647.952, + 4921.358, + 5194.764, + 5468.17 + ] + ] + }, + "es_transportation_sum_14d": { + "count": 10000, + "mean": 54.8019, + "min": 0, + "25%": 24, + "50%": 52, + "75%": 83, + "max": 129, + "std": 34.801493801086735, + "hist": [ + [ + 736, + 570, + 696, + 587, + 655, + 568, + 635, + 504, + 589, + 493, + 487, + 555, + 448, + 498, + 417, + 452, + 370, + 388, + 251, + 101 + ], + [ + 0, + 6.45, + 12.9, + 19.35, + 25.8, + 32.25, + 38.7, + 45.15, + 51.6, + 58.050000000000004, + 64.5, + 70.95, + 77.4, + 83.85000000000001, + 90.3, + 96.75, + 103.2, + 109.65, + 116.10000000000001, + 122.55, + 129 + ] + ] + }, + "es_health_sum_14d": { + "count": 10000, + "mean": 1.377, + "min": 0, + "25%": 0, + "50%": 1, + "75%": 2, + "max": 16, + "std": 1.952755060224534, + "hist": [ + [ + 4715, + 2232, + 806, + 1069, + 0, + 378, + 292, + 80, + 301, + 0, + 65, + 37, + 6, + 7, + 0, + 2, + 2, + 3, + 2, + 3 + ], + [ + 0, + 0.8, + 1.6, + 2.4000000000000004, + 3.2, + 4, + 4.800000000000001, + 5.6000000000000005, + 6.4, + 7.2, + 8, + 8.8, + 9.600000000000001, + 10.4, + 11.200000000000001, + 12, + 12.8, + 13.600000000000001, + 14.4, + 15.200000000000001, + 16 + ] + ] + }, + "es_otherservices_sum_14d": { + "count": 10000, + "mean": 0.116, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 0, + "max": 2, + "std": 0.3492222725135984, + "hist": [ + [ + 8937, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 966, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 97 + ], + [ + 0, + 0.1, + 0.2, + 0.30000000000000004, + 0.4, + 0.5, + 0.6000000000000001, + 0.7000000000000001, + 0.8, + 0.9, + 1, + 1.1, + 1.2000000000000002, + 1.3, + 1.4000000000000001, + 1.5, + 1.6, + 1.7000000000000002, + 1.8, + 1.9000000000000001, + 2 + ] + ] + }, + "es_food_sum_14d": { + "count": 10000, + "mean": 2.624, + "min": 0, + "25%": 0, + "50%": 2, + "75%": 4, + "max": 13, + "std": 2.829456587837715, + "hist": [ + [ + 3197, + 1535, + 0, + 999, + 1140, + 0, + 848, + 708, + 0, + 409, + 380, + 0, + 299, + 256, + 0, + 112, + 28, + 0, + 40, + 49 + ], + [ + 0, + 0.65, + 1.3, + 1.9500000000000002, + 2.6, + 3.25, + 3.9000000000000004, + 4.55, + 5.2, + 5.8500000000000005, + 6.5, + 7.15, + 7.800000000000001, + 8.450000000000001, + 9.1, + 9.75, + 10.4, + 11.05, + 11.700000000000001, + 12.35, + 13 + ] + ] + }, + "es_hotelservices_sum_14d": { + "count": 10000, + "mean": 0.1652, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 0, + "max": 2, + "std": 0.3859065332243528, + "hist": [ + [ + 8403, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1542, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 55 + ], + [ + 0, + 0.1, + 0.2, + 0.30000000000000004, + 0.4, + 0.5, + 0.6000000000000001, + 0.7000000000000001, + 0.8, + 0.9, + 1, + 1.1, + 1.2000000000000002, + 1.3, + 1.4000000000000001, + 1.5, + 1.6, + 1.7000000000000002, + 1.8, + 1.9000000000000001, + 2 + ] + ] + }, + "es_barsandrestaurants_sum_14d": { + "count": 10000, + "mean": 0.7864, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 5, + "std": 1.110899837899432, + "hist": [ + [ + 5648, + 0, + 0, + 0, + 2195, + 0, + 0, + 0, + 1223, + 0, + 0, + 0, + 555, + 0, + 0, + 0, + 337, + 0, + 0, + 42 + ], + [ + 0, + 0.25, + 0.5, + 0.75, + 1, + 1.25, + 1.5, + 1.75, + 2, + 2.25, + 2.5, + 2.75, + 3, + 3.25, + 3.5, + 3.75, + 4, + 4.25, + 4.5, + 4.75, + 5 + ] + ] + }, + "es_tech_sum_14d": { + "count": 10000, + "mean": 0.1698, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 0, + "max": 3, + "std": 0.414710933682549, + "hist": [ + [ + 8446, + 0, + 0, + 0, + 0, + 0, + 1421, + 0, + 0, + 0, + 0, + 0, + 0, + 122, + 0, + 0, + 0, + 0, + 0, + 11 + ], + [ + 0, + 0.15, + 0.3, + 0.44999999999999996, + 0.6, + 0.75, + 0.8999999999999999, + 1.05, + 1.2, + 1.3499999999999999, + 1.5, + 1.65, + 1.7999999999999998, + 1.95, + 2.1, + 2.25, + 2.4, + 2.55, + 2.6999999999999997, + 2.85, + 3 + ] + ] + }, + "es_sportsandtoys_sum_14d": { + "count": 10000, + "mean": 0.3603, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 9, + "std": 0.7301624639231821, + "hist": [ + [ + 7454, + 0, + 1799, + 0, + 522, + 0, + 172, + 0, + 39, + 0, + 0, + 3, + 0, + 7, + 0, + 2, + 0, + 1, + 0, + 1 + ], + [ + 0, + 0.45, + 0.9, + 1.35, + 1.8, + 2.25, + 2.7, + 3.15, + 3.6, + 4.05, + 4.5, + 4.95, + 5.4, + 5.8500000000000005, + 6.3, + 6.75, + 7.2, + 7.65, + 8.1, + 8.55, + 9 + ] + ] + }, + "es_wellnessandbeauty_sum_14d": { + "count": 10000, + "mean": 1.4875, + "min": 0, + "25%": 0, + "50%": 1, + "75%": 2, + "max": 14, + "std": 1.7617474635748853, + "hist": [ + [ + 3439, + 2791, + 1820, + 0, + 888, + 413, + 0, + 258, + 224, + 0, + 55, + 31, + 13, + 0, + 35, + 16, + 0, + 8, + 4, + 5 + ], + [ + 0, + 0.7, + 1.4, + 2.0999999999999996, + 2.8, + 3.5, + 4.199999999999999, + 4.8999999999999995, + 5.6, + 6.3, + 7, + 7.699999999999999, + 8.399999999999999, + 9.1, + 9.799999999999999, + 10.5, + 11.2, + 11.899999999999999, + 12.6, + 13.299999999999999, + 14 + ] + ] + }, + "es_hyper_sum_14d": { + "count": 10000, + "mean": 0.7528, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 6, + "std": 1.0529021893329076, + "hist": [ + [ + 5417, + 0, + 0, + 2764, + 0, + 0, + 1133, + 0, + 0, + 0, + 326, + 0, + 0, + 301, + 0, + 0, + 38, + 0, + 0, + 21 + ], + [ + 0, + 0.3, + 0.6, + 0.8999999999999999, + 1.2, + 1.5, + 1.7999999999999998, + 2.1, + 2.4, + 2.6999999999999997, + 3, + 3.3, + 3.5999999999999996, + 3.9, + 4.2, + 4.5, + 4.8, + 5.1, + 5.3999999999999995, + 5.7, + 6 + ] + ] + }, + "es_fashion_sum_14d": { + "count": 10000, + "mean": 0.7147, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 8, + "std": 1.019611627428345, + "hist": [ + [ + 5215, + 0, + 3376, + 0, + 0, + 946, + 0, + 166, + 0, + 0, + 217, + 0, + 23, + 0, + 0, + 12, + 0, + 34, + 0, + 11 + ], + [ + 0, + 0.4, + 0.8, + 1.2000000000000002, + 1.6, + 2, + 2.4000000000000004, + 2.8000000000000003, + 3.2, + 3.6, + 4, + 4.4, + 4.800000000000001, + 5.2, + 5.6000000000000005, + 6, + 6.4, + 6.800000000000001, + 7.2, + 7.6000000000000005, + 8 + ] + ] + }, + "es_home_sum_14d": { + "count": 10000, + "mean": 0.2233, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 0, + "max": 5, + "std": 0.5310982174058327, + "hist": [ + [ + 8254, + 0, + 0, + 0, + 1295, + 0, + 0, + 0, + 429, + 0, + 0, + 0, + 14, + 0, + 0, + 0, + 2, + 0, + 0, + 6 + ], + [ + 0, + 0.25, + 0.5, + 0.75, + 1, + 1.25, + 1.5, + 1.75, + 2, + 2.25, + 2.5, + 2.75, + 3, + 3.25, + 3.5, + 3.75, + 4, + 4.25, + 4.5, + 4.75, + 5 + ] + ] + }, + "es_travel_sum_14d": { + "count": 10000, + "mean": 0.0508, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 0, + "max": 2, + "std": 0.2320016001544977, + "hist": [ + [ + 9520, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 452, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 28 + ], + [ + 0, + 0.1, + 0.2, + 0.30000000000000004, + 0.4, + 0.5, + 0.6000000000000001, + 0.7000000000000001, + 0.8, + 0.9, + 1, + 1.1, + 1.2000000000000002, + 1.3, + 1.4000000000000001, + 1.5, + 1.6, + 1.7000000000000002, + 1.8, + 1.9000000000000001, + 2 + ] + ] + }, + "es_leisure_sum_14d": { + "count": 10000, + "mean": 0.0652, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 0, + "max": 2, + "std": 0.29420675682515546, + "hist": [ + [ + 9476, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 396, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 128 + ], + [ + 0, + 0.1, + 0.2, + 0.30000000000000004, + 0.4, + 0.5, + 0.6000000000000001, + 0.7000000000000001, + 0.8, + 0.9, + 1, + 1.1, + 1.2000000000000002, + 1.3, + 1.4000000000000001, + 1.5, + 1.6, + 1.7000000000000002, + 1.8, + 1.9000000000000001, + 2 + ] + ] + }, + "gender_F": { + "count": 10000, + "mean": 0.4552, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 1, + "std": 0.498013816852683, + "hist": [ + [ + 5448, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4552 + ], + [ + 0, + 0.05, + 0.1, + 0.15000000000000002, + 0.2, + 0.25, + 0.30000000000000004, + 0.35000000000000003, + 0.4, + 0.45, + 0.5, + 0.55, + 0.6000000000000001, + 0.65, + 0.7000000000000001, + 0.75, + 0.8, + 0.8500000000000001, + 0.9, + 0.9500000000000001, + 1 + ] + ] + }, + "gender_M": { + "count": 10000, + "mean": 0.5448, + "min": 0, + "25%": 0, + "50%": 1, + "75%": 1, + "max": 1, + "std": 0.498013816852683, + "hist": [ + [ + 4552, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 5448 + ], + [ + 0, + 0.05, + 0.1, + 0.15000000000000002, + 0.2, + 0.25, + 0.30000000000000004, + 0.35000000000000003, + 0.4, + 0.45, + 0.5, + 0.55, + 0.6000000000000001, + 0.65, + 0.7000000000000001, + 0.75, + 0.8, + 0.8500000000000001, + 0.9, + 0.9500000000000001, + 1 + ] + ] + }, + "step": { + "count": 10000, + "mean": 78.9453, + "min": 0, + "25%": 44, + "50%": 81, + "75%": 115, + "max": 147, + "std": 41.598136357351876, + "hist": [ + [ + 392, + 355, + 443, + 404, + 416, + 498, + 441, + 468, + 551, + 479, + 498, + 559, + 500, + 531, + 608, + 569, + 537, + 623, + 538, + 590 + ], + [ + 0, + 7.35, + 14.7, + 22.049999999999997, + 29.4, + 36.75, + 44.099999999999994, + 51.449999999999996, + 58.8, + 66.14999999999999, + 73.5, + 80.85, + 88.19999999999999, + 95.55, + 102.89999999999999, + 110.25, + 117.6, + 124.94999999999999, + 132.29999999999998, + 139.65, + 147 + ] + ] + }, + "amount": { + "count": 10000, + "mean": 38.00471700000001, + "min": 0, + "25%": 13.57, + "50%": 26.69, + "75%": 42.36, + "max": 7635.41, + "std": 130.3568133027091, + "hist": [ + [ + 9958, + 21, + 8, + 6, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ], + [ + 0, + 381.77049999999997, + 763.5409999999999, + 1145.3114999999998, + 1527.0819999999999, + 1908.8525, + 2290.6229999999996, + 2672.3934999999997, + 3054.1639999999998, + 3435.9345, + 3817.705, + 4199.4755, + 4581.245999999999, + 4963.0165, + 5344.786999999999, + 5726.5575, + 6108.3279999999995, + 6490.098499999999, + 6871.869, + 7253.639499999999, + 7635.41 + ] + ] + }, + "timestamp_hour": { + "count": 10000, + "mean": 11.45, + "min": 0, + "25%": 5, + "50%": 11, + "75%": 17, + "max": 23, + "std": 6.927705197966422, + "hist": [ + [ + 834, + 421, + 415, + 441, + 424, + 421, + 836, + 431, + 405, + 398, + 441, + 394, + 434, + 825, + 386, + 403, + 423, + 411, + 418, + 839 + ], + [ + 0, + 1.15, + 2.3, + 3.4499999999999997, + 4.6, + 5.75, + 6.8999999999999995, + 8.049999999999999, + 9.2, + 10.35, + 11.5, + 12.649999999999999, + 13.799999999999999, + 14.95, + 16.099999999999998, + 17.25, + 18.4, + 19.549999999999997, + 20.7, + 21.849999999999998, + 23 + ] + ] + }, + "timestamp_day_of_week": { + "count": 10000, + "mean": 1.663, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 1, + "max": 6, + "std": 2.4345479462048467, + "hist": [ + [ + 5085, + 0, + 0, + 2572, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2343 + ], + [ + 0, + 0.3, + 0.6, + 0.8999999999999999, + 1.2, + 1.5, + 1.7999999999999998, + 2.1, + 2.4, + 2.6999999999999997, + 3, + 3.3, + 3.5999999999999996, + 3.9, + 4.2, + 4.5, + 4.8, + 5.1, + 5.3999999999999995, + 5.7, + 6 + ] + ] + }, + "label": { + "count": 10000, + "mean": 0.0095, + "min": 0, + "25%": 0, + "50%": 0, + "75%": 0, + "max": 1, + "std": 0.09700871645943425, + "hist": [ + [ + 9905, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 95 + ], + [ + 0, + 0.05, + 0.1, + 0.15000000000000002, + 0.2, + 0.25, + 0.30000000000000004, + 0.35000000000000003, + 0.4, + 0.45, + 0.5, + 0.55, + 0.6000000000000001, + 0.65, + 0.7000000000000001, + 0.75, + 0.8, + 0.8500000000000001, + 0.9, + 0.9500000000000001, + 1 + ] + ] + } + }, + "features": [ + { + "origin": "churn-project-admin/events:latest.event_password_change", + "value_type": "int", + "name": "event_password_change" + }, + { + "origin": "churn-project-admin/events:latest.event_details_change", + "value_type": "int", + "name": "event_details_change" + }, + { + "origin": "churn-project-admin/events:latest.event_login", + "value_type": "int", + "name": "event_login" + }, + { + "origin": "churn-project-admin/transactions:latest.amount_max_2h", + "value_type": "float", + "name": "amount_max_2h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_sum_2h", + "value_type": "float", + "name": "amount_sum_2h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_count_2h", + "value_type": "float", + "name": "amount_count_2h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_avg_2h", + "value_type": "float", + "name": "amount_avg_2h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_max_12h", + "value_type": "float", + "name": "amount_max_12h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_sum_12h", + "value_type": "float", + "name": "amount_sum_12h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_count_12h", + "value_type": "float", + "name": "amount_count_12h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_avg_12h", + "value_type": "float", + "name": "amount_avg_12h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_max_24h", + "value_type": "float", + "name": "amount_max_24h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_sum_24h", + "value_type": "float", + "name": "amount_sum_24h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_count_24h", + "value_type": "float", + "name": "amount_count_24h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.amount_avg_24h", + "value_type": "float", + "name": "amount_avg_24h", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_transportation_sum_14d", + "value_type": "float", + "name": "es_transportation_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_health_sum_14d", + "value_type": "float", + "name": "es_health_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_otherservices_sum_14d", + "value_type": "float", + "name": "es_otherservices_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_food_sum_14d", + "value_type": "float", + "name": "es_food_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_hotelservices_sum_14d", + "value_type": "float", + "name": "es_hotelservices_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_barsandrestaurants_sum_14d", + "value_type": "float", + "name": "es_barsandrestaurants_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_tech_sum_14d", + "value_type": "float", + "name": "es_tech_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_sportsandtoys_sum_14d", + "value_type": "float", + "name": "es_sportsandtoys_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_wellnessandbeauty_sum_14d", + "value_type": "float", + "name": "es_wellnessandbeauty_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_hyper_sum_14d", + "value_type": "float", + "name": "es_hyper_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_fashion_sum_14d", + "value_type": "float", + "name": "es_fashion_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_home_sum_14d", + "value_type": "float", + "name": "es_home_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_travel_sum_14d", + "value_type": "float", + "name": "es_travel_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.es_leisure_sum_14d", + "value_type": "float", + "name": "es_leisure_sum_14d", + "aggregate": true + }, + { + "origin": "churn-project-admin/transactions:latest.gender_F", + "value_type": "int", + "name": "gender_F" + }, + { + "origin": "churn-project-admin/transactions:latest.gender_M", + "value_type": "int", + "name": "gender_M" + }, + { + "origin": "churn-project-admin/transactions:latest.step", + "value_type": "int", + "name": "step" + }, + { + "origin": "churn-project-admin/transactions:latest.amount", + "value_type": "float", + "name": "amount" + }, + { + "origin": "churn-project-admin/transactions:latest.timestamp_hour", + "value_type": "int", + "name": "timestamp_hour" + }, + { + "origin": "churn-project-admin/transactions:latest.timestamp_day_of_week", + "value_type": "int", + "name": "timestamp_day_of_week" + }, + { + "origin": "churn-project-admin/labels:latest.label", + "value_type": "int", + "name": "label" + } + ], + "index_keys": [ + "source" + ], + "targets": [ + { + "path": "v3io:///projects/churn-project-admin/FeatureStore/transactions-fraud/parquet/vectors/transactions-fraud-latest.parquet", + "size": 151274, + "status": "ready", + "name": "parquet", + "updated": "2025-09-30T15:57:17.402617+00:00", + "partitioned": true, + "kind": "parquet" + } + ] + } + } ] } diff --git a/tests/mockServer/data/monitoringApplications.json b/tests/mockServer/data/monitoringApplications.json index eb4eb0d869..b4eb779df0 100644 --- a/tests/mockServer/data/monitoringApplications.json +++ b/tests/mockServer/data/monitoringApplications.json @@ -194,6 +194,52 @@ ] }, "status": "ready" + }, + { + "name": "monitorAppV4", + "application_class": "MyAppV4", + "started_at": "2025-05-02T09:00:00Z", + "updated_time": "2025-05-08T11:00:00Z", + "base_period": 15, + "nuclio_function_uri": "default/functions/default-monitorAppV4/", + "stats": { + "detected": 850, + "potential_detection": 60, + "stream_stats": { + "0": { + "lag": 5, + "committed": 42 + } + }, + "shards": { + "1": { + "committed": 50, + "lag": 2 + }, + "2": { + "committed": 60, + "lag": 0 + } + }, + "processed_model_endpoints": 8, + "metrics": [ + { + "type": "result", + "time": "2025-05-07T09:07:14+00:00", + "result_name": "some_result", + "kind": 0, + "status": 2, + "value": 0.95 + }, + { + "type": "metric", + "time": "2025-05-07T09:07:14+00:00", + "metric_name": "some_metric", + "value": 0.4 + } + ] + }, + "status": "error" } ] } diff --git a/tests/mockServer/data/nuclioFunctions.json b/tests/mockServer/data/nuclioFunctions.json index 353dbce763..25bb06f7ee 100644 --- a/tests/mockServer/data/nuclioFunctions.json +++ b/tests/mockServer/data/nuclioFunctions.json @@ -582,7 +582,8 @@ "namespace": "default-tenant", "labels": { "mlrun/class": "serving", - "nuclio.io/project-name": "default" + "nuclio.io/project-name": "default", + "mlrun__type": "mlrun__model-monitoring-application" }, "resourceVersion": "30099716" }, @@ -3950,7 +3951,8 @@ "name": "test", "namespace": "default-tenant", "labels": { - "nuclio.io/project-name": "cat-vs-dog-classification" + "nuclio.io/project-name": "cat-vs-dog-classification", + "mlrun__type": "mlrun__model-monitoring-infra" }, "resourceVersion": "37855264" }, @@ -4009,7 +4011,8 @@ "name": "test1", "namespace": "default-tenant", "labels": { - "nuclio.io/project-name": "default" + "nuclio.io/project-name": "default", + "mlrun__type": "mlrun__model-monitoring-infra" }, "resourceVersion": "28276699" }, @@ -4070,7 +4073,8 @@ "name": "test2", "namespace": "default-tenant", "labels": { - "nuclio.io/project-name": "default" + "nuclio.io/project-name": "default", + "mlrun__type": "mlrun__model-monitoring-infra" }, "resourceVersion": "37855235" }, diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 5d2fb13f9b..8be1a9b777 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -836,7 +836,7 @@ function getMonitoringApplications(req, res) { const collectedMonitoringApplications = (monitoringApplications[req.params['project']] || []).map( application => ({ ...application, - stats: omit(application.stats, ['shards', 'processed_model_endpoints', 'metrics']) + stats: { ...omit(application.stats, ['shards', 'processed_model_endpoints', 'metrics']), stream_stats: application.stats.stream_stats['0']} }) ) From 75714fb93a43036c66d2818e40c5ffb425bb0409 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:12:53 +0200 Subject: [PATCH 202/228] Bump DRC version `3.2.0` (#3483) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6545c0e419..56e0eae8d3 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.1.11", + "iguazio.dashboard-react-controls": "3.2.0", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", From d3828193582e8d365a435c94ca0397e9fb997a57 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Wed, 29 Oct 2025 14:04:11 +0200 Subject: [PATCH 203/228] Fix [UI] optimize no-data-metric-icon image (#3474) --- .../DetailsAlertsMetrics.jsx | 4 +- .../DetailsMetrics/DetailsMetrics.jsx | 6 +- .../DetailsMetrics/DetailsMetrics.scss | 357 ------------------ .../ApplicationMetricCard.jsx | 14 +- .../InvocationsMetricCard.jsx | 13 +- .../InvocationsMetricCard.scss | 201 ++++++++++ .../MetricsCards/MetricsCards.scss | 144 +++++++ .../{ => NoMetricData}/NoMetricData.jsx | 9 +- .../NoMetricData/NoMetricData.scss | 19 + 9 files changed, 390 insertions(+), 377 deletions(-) rename src/components/DetailsMetrics/MetricsCards/{ => ApplicationMetricCard}/ApplicationMetricCard.jsx (91%) rename src/components/DetailsMetrics/MetricsCards/{ => InvocationsMetricCard}/InvocationsMetricCard.jsx (95%) create mode 100644 src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard/InvocationsMetricCard.scss create mode 100644 src/components/DetailsMetrics/MetricsCards/MetricsCards.scss rename src/components/DetailsMetrics/MetricsCards/{ => NoMetricData}/NoMetricData.jsx (85%) create mode 100644 src/components/DetailsMetrics/MetricsCards/NoMetricData/NoMetricData.scss diff --git a/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.jsx b/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.jsx index 7eea478bf7..5f63dd0bc3 100644 --- a/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.jsx +++ b/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.jsx @@ -22,10 +22,10 @@ import PropTypes from 'prop-types' import { useDispatch, useSelector } from 'react-redux' import { isEmpty } from 'lodash' -import ApplicationMetricCard from '../DetailsMetrics/MetricsCards/ApplicationMetricCard' +import ApplicationMetricCard from '../DetailsMetrics/MetricsCards/ApplicationMetricCard/ApplicationMetricCard' import DatePicker from '../../common/DatePicker/DatePicker' import NoData from '../../common/NoData/NoData' -import NoMetricData from '../DetailsMetrics/MetricsCards/NoMetricData' +import NoMetricData from '../DetailsMetrics/MetricsCards/NoMetricData/NoMetricData' import StatsCard from '../../common/StatsCard/StatsCard' import { REQUEST_CANCELED } from '../../constants' diff --git a/src/components/DetailsMetrics/DetailsMetrics.jsx b/src/components/DetailsMetrics/DetailsMetrics.jsx index b88f8122e1..a68d4f7d70 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.jsx +++ b/src/components/DetailsMetrics/DetailsMetrics.jsx @@ -22,12 +22,12 @@ import PropTypes from 'prop-types' import { useDispatch, useSelector } from 'react-redux' import { isEmpty } from 'lodash' -import ApplicationMetricCard from './MetricsCards/ApplicationMetricCard' +import ApplicationMetricCard from './MetricsCards/ApplicationMetricCard/ApplicationMetricCard' import DatePicker from '../../common/DatePicker/DatePicker' -import InvocationsMetricCard from './MetricsCards/InvocationsMetricCard' +import InvocationsMetricCard from './MetricsCards/InvocationsMetricCard/InvocationsMetricCard' import MetricsSelector from '../../elements/MetricsSelector/MetricsSelector' import NoData from '../../common/NoData/NoData' -import NoMetricData from './MetricsCards/NoMetricData' +import NoMetricData from './MetricsCards/NoMetricData/NoMetricData' import StatsCard from '../../common/StatsCard/StatsCard' import { diff --git a/src/components/DetailsMetrics/DetailsMetrics.scss b/src/components/DetailsMetrics/DetailsMetrics.scss index a36bdcd10d..e012f3d79b 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.scss +++ b/src/components/DetailsMetrics/DetailsMetrics.scss @@ -53,363 +53,12 @@ $stickyHeaderHeight: 55px; font-size: 20px; } - &__card { - width: 100%; - padding-bottom: 35px; - border: borders.$primaryBorder; - box-shadow: none; - - &.metrics__card-metric { - .metrics__card-body { - min-height: 130px; - aspect-ratio: 7; - } - } - - &.metrics__card-invocation { - .metrics__card-body { - aspect-ratio: 5; - } - } - - .metrics__card-row { - display: flex; - flex: 1 0 100%; - } - - &-invocation { - position: relative; - z-index: 1; - width: 100%; - - &__toggle-icon { - position: absolute; - right: 5px; - bottom: 5px; - align-self: flex-start; - visibility: hidden; - opacity: 0; - transition: all 0.2s ease-in-out; - } - - &:hover { - .metrics__card-invocation__toggle-icon { - visibility: visible; - opacity: 1; - - .round-icon-cp__circle { - &::before { - opacity: 0.4; - } - - &:hover::before { - opacity: 1; - } - } - } - } - - &-header { - display: flex; - flex: 1; - align-items: baseline; - justify-content: end; - height: 40px; - color: colors.$primary; - font-weight: 500; - font-size: 14px; - - &__drift-icon-container { - align-self: stretch; - margin-right: 2px; - - svg { - box-sizing: content-box; - width: 17px; - height: 17px; - padding-top: 9px; - } - } - - &__drift_up { - color: colors.$brightTurquoise; - } - - &__drift_down { - color: colors.$ceriseRed; - } - - &__selected-date { - margin-left: 4px; - color: colors.$topaz; - } - - &__total-title { - margin: 0 6px 0 12px; - font-weight: 700; - } - - &__total-score { - font-weight: 700; - font-size: 24px; - } - } - - &-content { - flex: 0 0 0; - flex-wrap: wrap; - align-content: center; - align-items: baseline; - justify-content: center; - width: 0; - font-weight: 700; - font-size: 18px; - visibility: hidden; - opacity: 0; - transition: flex 0.2s; - - &-visible { - display: flex; - flex: 0 1 auto; - width: fit-content; - margin-right: 15px; - visibility: visible; - opacity: 1; - transition: - flex 0.2s, - visibility 0s, - opacity 1s; - } - - &-title { - margin-right: 24px; - color: colors.$primary; - font-size: 18px; - text-align: center; - } - - &-container { - display: flex; - gap: 2px; - align-items: baseline; - font-weight: 700; - font-size: 14px; - - &__drift-icon { - align-self: stretch; - - svg { - box-sizing: content-box; - width: 17px; - height: 17px; - margin-top: -1px; - } - } - - &__drift_up { - margin-right: 4px; - color: colors.$brightTurquoise; - } - - &__drift_down { - margin-right: 4px; - color: colors.$ceriseRed; - } - } - - &-data { - display: flex; - align-items: baseline; - margin-left: 15px; - - &__total-title { - margin-right: 7px; - font-weight: 700; - font-size: 14px; - } - - &__total-score { - font-weight: 700; - font-size: 24px; - } - } - } - - .metrics__card { - padding-top: 12px; - padding-bottom: 0; - } - - &_collapsed .stats-card__row { - height: 0; - min-height: 0 !important; - margin-bottom: 0 !important; - opacity: 0; - transition: all 0.2s ease-in-out; - } - - &_expanded .stats-card__row { - height: 40px; - opacity: 1; - transition: all 0.2s ease-in-out; - } - } - - &-drift-status { - display: inline-block; - width: 10px; - height: 10px; - margin-left: 8px; - border-radius: 50%; - } - - &-drift-status-possible_drift { - background-color: colors.$grandis; - } - - &-drift-status-drift_detected { - background-color: colors.$ceriseRed; - } - - &-drift-status-no_drift { - background-color: colors.$brightTurquoise; - } - - &-drift-no_status { - background-color: colors.$doveGray; - } - - &-header { - position: relative; - top: -5px; - display: flex; - flex-direction: row; - gap: 8px; - align-items: center; - justify-content: space-between; - padding-left: 5px; - font-weight: 500; - transition: all 0.2s linear; - - &-result-kind { - display: flex; - gap: 4px; - align-self: center; - justify-content: center; - width: max-content; - overflow: hidden; - color: colors.$topaz; - font-weight: 500; - font-size: 14px; - font-family: Roboto, sans-serif; - font-style: normal; - line-height: normal; - text-overflow: ellipsis; - } - - &-data { - color: colors.$topaz; - font-weight: 700; - font-size: 18px; - text-align: center; - leading-trim: both; - text-edge: cap; - } - - &-label { - font-size: 14px; - } - } - - &-body { - position: relative; - display: flex; - flex: 1; - align-self: stretch; - box-sizing: border-box; - width: 100%; - - &-collapsed { - height: 80px; - } - - .chart-item { - flex: 1; - - canvas { - width: 100%; - height: 100%; - } - } - - &-bar { - flex: 0 1 25%; - min-width: 210px; - margin-right: 15px; - - canvas { - width: 100%; - height: 100%; - } - - canvas.hidden-canvas { - position: absolute; - top: 0; - left: 0; - opacity: 0; - } - } - - &-line { - flex: 1 1 0; - margin-top: 3px; - - canvas { - width: 100% !important; - height: 100% !important; - } - - canvas.hidden-canvas { - position: absolute; - top: 0; - left: 0; - opacity: 0; - } - } - - &-invocation { - flex: 1; - border: 1px solid transparent; - - canvas { - width: 100% !important; - height: 100% !important; - } - - canvas.hidden-canvas { - position: absolute; - top: 0; - left: 0; - opacity: 0; - } - } - } - } - &-wrapper { display: flex; flex-flow: column nowrap; height: 100%; } - &__empty-card { - display: flex; - gap: 25px; - align-items: center; - justify-content: center; - width: 100%; - } - &__empty-select { display: flex; flex-direction: column; @@ -422,9 +71,3 @@ $stickyHeaderHeight: 55px; } } } - -.empty-invocation-card { - z-index: 1; - padding-bottom: 1em; - box-shadow: 0 -10px 0 0 colors.$white; -} diff --git a/src/components/DetailsMetrics/MetricsCards/ApplicationMetricCard.jsx b/src/components/DetailsMetrics/MetricsCards/ApplicationMetricCard/ApplicationMetricCard.jsx similarity index 91% rename from src/components/DetailsMetrics/MetricsCards/ApplicationMetricCard.jsx rename to src/components/DetailsMetrics/MetricsCards/ApplicationMetricCard/ApplicationMetricCard.jsx index d14447ea37..75eb7aa0ee 100644 --- a/src/components/DetailsMetrics/MetricsCards/ApplicationMetricCard.jsx +++ b/src/components/DetailsMetrics/MetricsCards/ApplicationMetricCard/ApplicationMetricCard.jsx @@ -19,17 +19,17 @@ such restriction. */ import React, { useMemo, memo } from 'react' -import MetricChart from '../../../common/MlChart/MetricChart/MetricChart' -import StatsCard from '../../../common/StatsCard/StatsCard' +import MetricChart from '../../../../common/MlChart/MetricChart/MetricChart' +import StatsCard from '../../../../common/StatsCard/StatsCard' import { TextTooltipTemplate, Tooltip } from 'igz-controls/components' -import { CHART_TYPE_LINE, CHART_TYPE_BAR } from '../../../constants' -import { METRIC_DATA } from '../../../types' -import { calculateHistogram, METRIC_COMPUTED_AVG_POINTS } from '../detailsMetrics.util' -import { getMetricChartConfig } from '../../../utils/getChartConfig' +import { CHART_TYPE_LINE, CHART_TYPE_BAR } from '../../../../constants' +import { METRIC_DATA } from '../../../../types' +import { calculateHistogram, METRIC_COMPUTED_AVG_POINTS } from '../../detailsMetrics.util' +import { getMetricChartConfig } from '../../../../utils/getChartConfig' import { getScssVariableValue } from 'igz-controls/utils/common.util' -import '../DetailsMetrics.scss' +import '../MetricsCards.scss' const ApplicationMetricCard = ({ metric }) => { const javaColor = useMemo(() => getScssVariableValue('--javaColor'), []) diff --git a/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard.jsx b/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard/InvocationsMetricCard.jsx similarity index 95% rename from src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard.jsx rename to src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard/InvocationsMetricCard.jsx index 40077e8d49..4cac6a9065 100644 --- a/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard.jsx +++ b/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard/InvocationsMetricCard.jsx @@ -21,22 +21,25 @@ import { forwardRef, useMemo } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' -import MetricChart from '../../../common/MlChart/MetricChart/MetricChart' -import StatsCard from '../../../common/StatsCard/StatsCard' +import MetricChart from '../../../../common/MlChart/MetricChart/MetricChart' +import StatsCard from '../../../../common/StatsCard/StatsCard' import { RoundedIcon, Tip } from 'igz-controls/components' import { calculatePercentageDrift, METRIC_COMPUTED_TOTAL_POINTS, METRIC_RAW_TOTAL_POINTS -} from '../detailsMetrics.util' -import { CHART_TYPE_LINE, CHART_TYPE_GRADIENT_LINE } from '../../../constants' -import { getMetricChartConfig } from '../../../utils/getChartConfig' +} from '../../detailsMetrics.util' +import { CHART_TYPE_LINE, CHART_TYPE_GRADIENT_LINE } from '../../../../constants' +import { getMetricChartConfig } from '../../../../utils/getChartConfig' import { getScssVariableValue } from 'igz-controls/utils/common.util' import EnlargeIcon from 'igz-controls/images/expand.svg?react' import MinimizeIcon from 'igz-controls/images/collapse.svg?react' +import '../MetricsCards.scss' +import './InvocationsMetricCard.scss' + const InvocationsMetricCard = forwardRef( ( { diff --git a/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard/InvocationsMetricCard.scss b/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard/InvocationsMetricCard.scss new file mode 100644 index 0000000000..c0cc0bc0cb --- /dev/null +++ b/src/components/DetailsMetrics/MetricsCards/InvocationsMetricCard/InvocationsMetricCard.scss @@ -0,0 +1,201 @@ +@use 'igz-controls/scss/colors'; +@use 'igz-controls/scss/borders'; + +.metrics__card-invocation { + position: relative; + z-index: 1; + width: 100%; + + .metrics__card-body { + aspect-ratio: 5; + + &-invocation { + flex: 1; + border: 1px solid transparent; + + canvas { + width: 100% !important; + height: 100% !important; + } + + canvas.hidden-canvas { + position: absolute; + top: 0; + left: 0; + opacity: 0; + } + } + } + + &__toggle-icon { + position: absolute; + right: 5px; + bottom: 5px; + align-self: flex-start; + visibility: hidden; + opacity: 0; + transition: all 0.2s ease-in-out; + } + + &:hover { + .metrics__card-invocation__toggle-icon { + visibility: visible; + opacity: 1; + + .round-icon-cp__circle { + &::before { + opacity: 0.4; + } + + &:hover::before { + opacity: 1; + } + } + } + } + + &-header { + display: flex; + flex: 1; + align-items: baseline; + justify-content: end; + height: 40px; + color: colors.$primary; + font-weight: 500; + font-size: 14px; + + &__drift-icon-container { + align-self: stretch; + margin-right: 2px; + + svg { + box-sizing: content-box; + width: 17px; + height: 17px; + padding-top: 9px; + } + } + + &__drift_up { + color: colors.$brightTurquoise; + } + + &__drift_down { + color: colors.$ceriseRed; + } + + &__selected-date { + margin-left: 4px; + color: colors.$topaz; + } + + &__total-title { + margin: 0 6px 0 12px; + font-weight: 700; + } + + &__total-score { + font-weight: 700; + font-size: 24px; + } + } + + &-content { + flex: 0 0 0; + flex-wrap: wrap; + align-content: center; + align-items: baseline; + justify-content: center; + width: 0; + font-weight: 700; + font-size: 18px; + visibility: hidden; + opacity: 0; + transition: flex 0.2s; + + &-visible { + display: flex; + flex: 0 1 auto; + width: fit-content; + margin-right: 15px; + visibility: visible; + opacity: 1; + transition: + flex 0.2s, + visibility 0s, + opacity 1s; + } + + &-title { + margin-right: 24px; + color: colors.$primary; + font-size: 18px; + text-align: center; + } + + &-container { + display: flex; + gap: 2px; + align-items: baseline; + font-weight: 700; + font-size: 14px; + + &__drift-icon { + align-self: stretch; + + svg { + box-sizing: content-box; + width: 17px; + height: 17px; + margin-top: -1px; + } + } + + &__drift_up { + margin-right: 4px; + color: colors.$brightTurquoise; + } + + &__drift_down { + margin-right: 4px; + color: colors.$ceriseRed; + } + } + + &-data { + display: flex; + align-items: baseline; + margin-left: 15px; + + &__total-title { + margin-right: 7px; + font-weight: 700; + font-size: 14px; + } + + &__total-score { + font-weight: 700; + font-size: 24px; + } + } + } + + .metrics__card { + padding-top: 12px; + padding-bottom: 0; + } + + &_collapsed .stats-card__row { + height: 0; + min-height: 0 !important; + margin-bottom: 0 !important; + opacity: 0; + transition: all 0.2s ease-in-out; + } + + &_expanded .stats-card__row { + height: 40px; + opacity: 1; + transition: all 0.2s ease-in-out; + } +} diff --git a/src/components/DetailsMetrics/MetricsCards/MetricsCards.scss b/src/components/DetailsMetrics/MetricsCards/MetricsCards.scss new file mode 100644 index 0000000000..51a466c785 --- /dev/null +++ b/src/components/DetailsMetrics/MetricsCards/MetricsCards.scss @@ -0,0 +1,144 @@ +@use 'igz-controls/scss/colors'; +@use 'igz-controls/scss/borders'; + +.metrics__card { + width: 100%; + padding-bottom: 35px; + border: borders.$primaryBorder; + box-shadow: none; + + &.metrics__card-metric { + .metrics__card-body { + min-height: 130px; + aspect-ratio: 7; + } + } + + .metrics__card-row { + display: flex; + flex: 1 0 100%; + } + + &-drift-status { + display: inline-block; + width: 10px; + height: 10px; + margin-left: 8px; + border-radius: 50%; + } + + &-drift-status-possible_drift { + background-color: colors.$grandis; + } + + &-drift-status-drift_detected { + background-color: colors.$ceriseRed; + } + + &-drift-status-no_drift { + background-color: colors.$brightTurquoise; + } + + &-drift-no_status { + background-color: colors.$doveGray; + } + + &-header { + position: relative; + top: -5px; + display: flex; + flex-direction: row; + gap: 8px; + align-items: center; + justify-content: space-between; + padding-left: 5px; + font-weight: 500; + transition: all 0.2s linear; + + &-result-kind { + display: flex; + gap: 4px; + align-self: center; + justify-content: center; + width: max-content; + overflow: hidden; + color: colors.$topaz; + font-weight: 500; + font-size: 14px; + font-family: Roboto, sans-serif; + font-style: normal; + line-height: normal; + text-overflow: ellipsis; + } + + &-data { + color: colors.$topaz; + font-weight: 700; + font-size: 18px; + text-align: center; + leading-trim: both; + text-edge: cap; + } + + &-label { + font-size: 14px; + } + } + + &-body { + position: relative; + display: flex; + flex: 1; + align-self: stretch; + box-sizing: border-box; + width: 100%; + + &-collapsed { + height: 80px; + } + + .chart-item { + flex: 1; + + canvas { + width: 100%; + height: 100%; + } + } + + &-bar { + flex: 0 1 25%; + min-width: 210px; + margin-right: 15px; + + canvas { + width: 100%; + height: 100%; + } + + canvas.hidden-canvas { + position: absolute; + top: 0; + left: 0; + opacity: 0; + } + } + + &-line { + flex: 1 1 0; + margin-top: 3px; + + canvas { + width: 100% !important; + height: 100% !important; + } + + canvas.hidden-canvas { + position: absolute; + top: 0; + left: 0; + opacity: 0; + } + } + } +} diff --git a/src/components/DetailsMetrics/MetricsCards/NoMetricData.jsx b/src/components/DetailsMetrics/MetricsCards/NoMetricData/NoMetricData.jsx similarity index 85% rename from src/components/DetailsMetrics/MetricsCards/NoMetricData.jsx rename to src/components/DetailsMetrics/MetricsCards/NoMetricData/NoMetricData.jsx index c1817e834d..9b7f0d77b2 100644 --- a/src/components/DetailsMetrics/MetricsCards/NoMetricData.jsx +++ b/src/components/DetailsMetrics/MetricsCards/NoMetricData/NoMetricData.jsx @@ -19,9 +19,12 @@ such restriction. */ import PropTypes from 'prop-types' -import StatsCard from '../../../common/StatsCard/StatsCard' +import StatsCard from '../../../../common/StatsCard/StatsCard' -import NoDataIcon from 'igz-controls/images/no-data-metric-icon.svg?react' +import NoDataIcon from 'igz-controls/images/no-data-metric-image.png' + +import '../MetricsCards.scss' +import './NoMetricData.scss' const NoMetricData = ({ title = '', message = 'No data to show', className = '', tip = '' }) => { return ( @@ -29,7 +32,7 @@ const NoMetricData = ({ title = '', message = 'No data to show', className = '',
      - + No data icon
      {message}
      diff --git a/src/components/DetailsMetrics/MetricsCards/NoMetricData/NoMetricData.scss b/src/components/DetailsMetrics/MetricsCards/NoMetricData/NoMetricData.scss new file mode 100644 index 0000000000..53d9dff89c --- /dev/null +++ b/src/components/DetailsMetrics/MetricsCards/NoMetricData/NoMetricData.scss @@ -0,0 +1,19 @@ +@use 'igz-controls/scss/colors'; + +.metrics__empty-card { + display: flex; + gap: 25px; + align-items: center; + justify-content: center; + width: 100%; + + img { + width: 41px; + } +} + +.empty-invocation-card { + z-index: 1; + padding-bottom: 1em; + box-shadow: 0 -10px 0 0 colors.$white; +} From 11554c05ba6b59d08fb980c30f87ee829dec634f Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Wed, 29 Oct 2025 14:04:24 +0200 Subject: [PATCH 204/228] Impl [UI] Show error message in the tables across the app (#3455) --- .../MEPsWithDetections.jsx | 19 ++++++++------- .../MonitoringApplications.jsx | 24 +++++++++++++++---- src/reducers/featureStoreReducer.js | 20 ++++++++++------ src/reducers/workflowReducer.js | 4 ++-- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx index 9be57e4ecb..eebb38bb2d 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MEPsWithDetections.jsx @@ -24,9 +24,7 @@ import MlChart from '../../../common/MlChart/MlChart' import NoData from '../../../common/NoData/NoData' import { Loader, Tip } from 'igz-controls/components' -import { - MONITORING_APPLICATIONS_NO_DATA_MESSAGE -} from '../MonitoringApplicationsPage.util' +import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicationsPage.util' import { getMEPsWithDetectionChartConfig } from '../../../utils/getChartConfig' import { groupDataToBins } from './monitoringApplications.util' import { useSelector } from 'react-redux' @@ -38,7 +36,7 @@ const MEPsWithDetections = () => { const chartWrapperRef = useRef() const barConfig = useMemo(() => getMEPsWithDetectionChartConfig(), []) const { - endpointsWithDetections: { data: endpointsWithDetectionsData, loading } + endpointsWithDetections: { data: endpointsWithDetectionsData, loading, error } } = useSelector(store => store.monitoringApplicationsStore) const renderPlugin = useMemo(() => { @@ -133,7 +131,13 @@ const MEPsWithDetections = () => { {endpointsWithDetectionsData.values?.length === 0 && !(isLoading || loading) ? ( - + ) : (
      @@ -143,10 +147,7 @@ const MEPsWithDetections = () => { >
      - +
      Time range
      diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx index 83dcfc6101..a53bfbbe02 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx @@ -32,7 +32,10 @@ import { MODEL_ENDPOINTS_TAB, MONITORING_APP_PAGE } from '../../../constants' import { MONITORING_APPLICATIONS_NO_DATA_MESSAGE } from '../MonitoringApplicationsPage.util' import { createApplicationContent } from '../../../utils/createApplicationContent' import { generateOperatingFunctionsTable } from './monitoringApplications.util' -import { removeMonitoringApplications, removeMEPWithDetections } from '../../../reducers/monitoringApplicationsReducer' +import { + removeMonitoringApplications, + removeMEPWithDetections +} from '../../../reducers/monitoringApplicationsReducer' import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' @@ -42,7 +45,8 @@ const MonitoringApplications = () => { const navigate = useNavigate() const { monitoringApplications: { applications = [], operatingFunctions = [] }, - loading + loading, + error } = useSelector(store => store.monitoringApplicationsStore) const applicationsTableActionsMenu = useMemo( @@ -94,7 +98,13 @@ const MonitoringApplications = () => {
      {operatingFunctions.length === 0 && !loading ? ( - + ) : ( )} @@ -106,7 +116,13 @@ const MonitoringApplications = () => { All Applications {applications.length === 0 && !loading ? ( - + ) : loading ? ( ) : ( diff --git a/src/reducers/featureStoreReducer.js b/src/reducers/featureStoreReducer.js index 4e39613ab5..2caaa43176 100644 --- a/src/reducers/featureStoreReducer.js +++ b/src/reducers/featureStoreReducer.js @@ -124,7 +124,8 @@ export const createNewFeatureSet = createAsyncThunk( : error.message showErrorNotification(thunkAPI.dispatch, error, '', message) - thunkAPI.rejectWithValue(error) + + return thunkAPI.rejectWithValue(error) }) } ) @@ -181,7 +182,8 @@ export const fetchFeatureSets = createAsyncThunk( thunkAPI.dispatch, config?.ui?.setRequestErrorMessage ) - thunkAPI.rejectWithValue(error.message) + + return thunkAPI.rejectWithValue(error.message) }) } ) @@ -236,7 +238,8 @@ export const fetchFeatureVectors = createAsyncThunk( thunkAPI.dispatch, config?.ui?.setRequestErrorMessage ) - thunkAPI.rejectWithValue(error) + + return thunkAPI.rejectWithValue(error) } }) } @@ -268,7 +271,8 @@ export const fetchFeatureSetsTags = createAsyncThunk( ({ project, config }, thunkAPI) => { return featureStoreApi.fetchFeatureSetsTags(project, config).catch(error => { largeResponseCatchHandler(error, 'Failed to fetch tags', thunkAPI.dispatch) - thunkAPI.rejectWithValue(error) + + return thunkAPI.rejectWithValue(error) }) } ) @@ -277,7 +281,8 @@ export const fetchFeatureVectorsTags = createAsyncThunk( ({ project, config }, thunkAPI) => { return featureStoreApi.fetchFeatureVectorsTags(project, config).catch(error => { largeResponseCatchHandler(error, 'Failed to fetch tags', thunkAPI.dispatch) - thunkAPI.rejectWithValue(error) + + return thunkAPI.rejectWithValue(error) }) } ) @@ -296,7 +301,8 @@ export const startFeatureSetIngest = createAsyncThunk( : error.message showErrorNotification(thunkAPI.dispatch, error, '', message) - thunkAPI.rejectWithValue(message) + + return thunkAPI.rejectWithValue(message) }) } ) @@ -499,7 +505,7 @@ const featureStoreSlice = createSlice({ state.features.loading = true }) builder.addCase(fetchFeatures.rejected, (state, action) => { - state.features.loading = true + state.features.loading = false state.error = action.payload }) builder.addCase(fetchFeatures.fulfilled, (state, action) => { diff --git a/src/reducers/workflowReducer.js b/src/reducers/workflowReducer.js index 3d8bb8c9b8..8046b80cc0 100644 --- a/src/reducers/workflowReducer.js +++ b/src/reducers/workflowReducer.js @@ -45,7 +45,7 @@ export const fetchWorkflow = createAsyncThunk('fetchWorkflow', ({ project, workf }) export const fetchWorkflows = createAsyncThunk( 'fetchWorkflows', - async ({ project, filter, config, withPagination }, { rejectWithValue }) => { + async ({ project, filter, config, withPagination }, { dispatch, rejectWithValue }) => { const page = project === '*' ? JOBS_MONITORING_WORKFLOWS_TAB : MONITOR_WORKFLOWS_TAB let result = [] let nextPageToken = '' @@ -56,7 +56,7 @@ export const fetchWorkflows = createAsyncThunk( largeResponseCatchHandler( error, 'Failed to fetch workflows', - null, + dispatch, config?.ui?.setRequestErrorMessage ) From 2fc5f749172decce6cafa3a5c599391b2679d17f Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Mon, 3 Nov 2025 09:12:58 +0200 Subject: [PATCH 205/228] Impl [Real-time pipelines] Add model runner step (#3473) --- package.json | 2 +- src/common/ReactFlow/MlModelRunnerNode.jsx | 122 ++++++++ src/common/ReactFlow/MlReactFlow.jsx | 6 +- src/common/ReactFlow/MlReactFlowNode.jsx | 35 +-- src/common/ReactFlow/mlModelRunnerNode.scss | 49 ++++ src/common/ReactFlow/mlReactFlow.scss | 2 +- src/common/ReactFlow/mlReactFlow.util.js | 34 ++- .../DetailsTransformations.jsx | 36 +-- .../ModelEndpoints/ModelEndpoints.jsx | 49 ++-- .../ModelEndpoints/modelEndpoints.util.jsx | 32 +++ .../ModelsPage/ModelsPage.context.jsx | 3 +- src/components/Pipeline/Pipeline.jsx | 263 +++++++++++++----- src/components/Pipeline/pipeline.scss | 64 ++++- src/constants.js | 5 + .../ModelEndpointPopUp/ModelEndpointPopUp.jsx | 132 +++++++++ src/scss/main.scss | 32 ++- src/types.js | 29 +- tests/mockServer/data/artifacts.json | 97 ++++++- tests/mockServer/data/funcs.json | 184 ++++++++++++ tests/mockServer/data/modelEndpoints.json | 49 ++++ 20 files changed, 1054 insertions(+), 171 deletions(-) create mode 100644 src/common/ReactFlow/MlModelRunnerNode.jsx create mode 100644 src/common/ReactFlow/mlModelRunnerNode.scss create mode 100644 src/elements/DetailsPopUp/ModelEndpointPopUp/ModelEndpointPopUp.jsx diff --git a/package.json b/package.json index 56e0eae8d3..baa2a750cd 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "homepage": "/mlrun", "dependencies": { + "@dagrejs/dagre": "^1.1.5", "@monaco-editor/react": "^4.7.0", "@reduxjs/toolkit": "^1.9.5", "axios": "1.12.0", @@ -13,7 +14,6 @@ "classnames": "^2.5.1", "concurrently": "^6.4.2", "cronstrue": "^2.49.0", - "dagre": "^0.8.5", "dotenv": "^10.0.0", "dotenv-expand": "^5.1.0", "file-saver": "^2.0.5", diff --git a/src/common/ReactFlow/MlModelRunnerNode.jsx b/src/common/ReactFlow/MlModelRunnerNode.jsx new file mode 100644 index 0000000000..6f4452ab0c --- /dev/null +++ b/src/common/ReactFlow/MlModelRunnerNode.jsx @@ -0,0 +1,122 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React from 'react' +import PropTypes from 'prop-types' +import { Handle } from 'reactflow' +import { Form } from 'react-final-form' +import arrayMutators from 'final-form-arrays' + +import { Tooltip, TextTooltipTemplate, FormChipCell } from 'igz-controls/components' + +import { REACT_FLOW_NODE_DATA } from '../../types' +import { createForm } from 'final-form' +import { getChipOptions } from 'igz-controls/utils/chips.util' +import { setFieldState } from 'igz-controls/utils/form.util' + +import ConnectionIcon from 'igz-controls/images/connections-icon.svg?react' +import MonitoringIcon from 'igz-controls/images/monitoring-icon.svg?react' + +import './mlModelRunnerNode.scss' + +const MlModelRunnerNode = ({ data, isConnectable }) => { + const formRef = React.useRef( + createForm({ + initialValues: { + runningModels: Object.keys(data.customData.class_args.monitoring_data).map(runningModelName => { + return { + isKeyOnly: true, + key: runningModelName, + id: runningModelName + } + }) + }, + mutators: { ...arrayMutators, setFieldState }, + onSubmit: () => {} + }) + ) + + return ( +
      {}}> + {formState => ( + <> + +
      +
      + +
      +
      +
      + +
      +
      Model runner step
      +
      + {data.customData.track_models && ( +
      + }> + + +
      + )} +
      +
      Running models
      +
      + +
      + + + )} +
      + ) +} + +MlModelRunnerNode.propTypes = { + data: REACT_FLOW_NODE_DATA.isRequired, + isConnectable: PropTypes.bool.isRequired +} + +export default React.memo(MlModelRunnerNode) diff --git a/src/common/ReactFlow/MlReactFlow.jsx b/src/common/ReactFlow/MlReactFlow.jsx index f44552e253..7bade64c25 100644 --- a/src/common/ReactFlow/MlReactFlow.jsx +++ b/src/common/ReactFlow/MlReactFlow.jsx @@ -22,9 +22,10 @@ import PropTypes from 'prop-types' import ReactFlow, { ReactFlowProvider, MiniMap, Controls } from 'reactflow' import MlReactFlowNode from './MlReactFlowNode' +import MlModelRunnerNode from './MlModelRunnerNode' import MlReactFlowEdge from './MlReactFlowEdge' -import { ML_EDGE, ML_NODE } from '../../constants' +import { ML_EDGE, ML_MODEL_RUNNER_NODE, ML_NODE } from '../../constants' import { getNodeClassName } from './mlReactFlow.util' import './mlReactFlow.scss' @@ -34,7 +35,8 @@ const edgeTypes = { } const nodeTypes = { - [ML_NODE]: MlReactFlowNode + [ML_NODE]: MlReactFlowNode, + [ML_MODEL_RUNNER_NODE]: MlModelRunnerNode } const MlReactFlow = ({ alignTriggerItem = '', edges, nodes, onNodeClick = () => {} }) => { diff --git a/src/common/ReactFlow/MlReactFlowNode.jsx b/src/common/ReactFlow/MlReactFlowNode.jsx index cdec7ad8e2..877caf82c5 100644 --- a/src/common/ReactFlow/MlReactFlowNode.jsx +++ b/src/common/ReactFlow/MlReactFlowNode.jsx @@ -21,18 +21,9 @@ import React from 'react' import PropTypes from 'prop-types' import { Handle } from 'reactflow' -import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' -import { Tip } from 'igz-controls/components' +import { Tooltip, TextTooltipTemplate, Tip } from 'igz-controls/components' -import { - GREY_NODE, - INPUT_NODE, - OUTPUT_NODE, - OVAL_NODE_SHAPE, - PRIMARY_NODE, - ROUNDED_RECTANGLE_NODE_SHAPE, - SECONDARY_NODE -} from '../../constants' +import { REACT_FLOW_NODE_DATA } from '../../types' const MlReactFlowNode = ({ data, isConnectable }) => { return ( @@ -50,7 +41,7 @@ const MlReactFlowNode = ({ data, isConnectable }) => {
      {data.subLabel &&
      {data.subLabel}
      }
      @@ -71,25 +62,7 @@ const MlReactFlowNode = ({ data, isConnectable }) => { } MlReactFlowNode.propTypes = { - data: PropTypes.shape({ - subType: PropTypes.oneOf([INPUT_NODE, OUTPUT_NODE, PRIMARY_NODE, SECONDARY_NODE, GREY_NODE]) - .isRequired, - label: PropTypes.string.isRequired, - tip: PropTypes.string, - subLabel: PropTypes.string, - isSelectable: PropTypes.bool, - withOpacity: PropTypes.bool, - shape: PropTypes.oneOf([OVAL_NODE_SHAPE, ROUNDED_RECTANGLE_NODE_SHAPE, null]), - sourceHandle: PropTypes.shape({ - tooltip: PropTypes.string, - className: PropTypes.string - }), - targetHandle: PropTypes.shape({ - tooltip: PropTypes.string, - className: PropTypes.string - }), - customData: PropTypes.object - }).isRequired, + data: REACT_FLOW_NODE_DATA.isRequired, isConnectable: PropTypes.bool.isRequired } diff --git a/src/common/ReactFlow/mlModelRunnerNode.scss b/src/common/ReactFlow/mlModelRunnerNode.scss new file mode 100644 index 0000000000..b9ae93c7d1 --- /dev/null +++ b/src/common/ReactFlow/mlModelRunnerNode.scss @@ -0,0 +1,49 @@ +@use 'igz-controls/scss/colors'; + +.react-flow__renderer { + .react-flow__node.react-flow__node-ml-model-runner-node { + flex-direction: column; + align-items: flex-start; + + .react-flow__node-header { + display: flex; + width: 100%; + margin-bottom: 10px; + stroke: initial; + + &-title { + overflow: hidden; + margin-left: 10px; + margin-right: auto; + } + + &-label { + font-size: 16px; + } + + &-sub-label { + color: colors.$topaz; + font-size: 14px; + } + + &-icon { + display: flex; + align-items: center; + } + + &-monitoring-icon { + margin-left: 10px; + } + } + + .react-flow__node-chips-title { + font-size: 14px; + font-weight: 500; + } + + .react-flow__node-chips { + margin-top: 5px; + width: 100%; + } + } +} diff --git a/src/common/ReactFlow/mlReactFlow.scss b/src/common/ReactFlow/mlReactFlow.scss index 3d344c919d..1927c379a6 100644 --- a/src/common/ReactFlow/mlReactFlow.scss +++ b/src/common/ReactFlow/mlReactFlow.scss @@ -20,7 +20,7 @@ } @mixin primaryNode { - color: colors.$malibu; + color: colors.$primary; background-color: colors.$white; border-color: colors.$malibu; stroke: colors.$malibu; diff --git a/src/common/ReactFlow/mlReactFlow.util.js b/src/common/ReactFlow/mlReactFlow.util.js index 2a67678951..77383c0967 100644 --- a/src/common/ReactFlow/mlReactFlow.util.js +++ b/src/common/ReactFlow/mlReactFlow.util.js @@ -18,15 +18,21 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import classnames from 'classnames' -import dagre from 'dagre' +import dagre from '@dagrejs/dagre' import { Position } from 'reactflow' -import { ERROR_STATE, FAILED_STATE } from '../../constants' +import { ERROR_STATE, FAILED_STATE, ML_MODEL_RUNNER_NODE } from '../../constants' + +const nodeWidthByType = { + default: 300 +} +const nodeHeightByType = { + [ML_MODEL_RUNNER_NODE]: 120, + default: 80 +} +const dagreGraph = new dagre.graphlib.Graph() export const getLayoutedElements = (nodes, edges, direction = 'TB') => { - const elWidth = 300 - const elHeight = 80 - const dagreGraph = new dagre.graphlib.Graph() const isHorizontal = direction === 'LR' let layoutedNodes = [] let layoutedEdges = [] @@ -35,7 +41,9 @@ export const getLayoutedElements = (nodes, edges, direction = 'TB') => { dagreGraph.setGraph({ rankdir: direction }) nodes.forEach(node => { - dagreGraph.setNode(node.id, { width: elWidth, height: elHeight }) + const nodeHeight = nodeHeightByType[node.type] ?? nodeHeightByType.default + const nodeWidth = nodeWidthByType[node.type] ?? nodeWidthByType.default + dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight }) }) edges.forEach(edge => { @@ -47,6 +55,8 @@ export const getLayoutedElements = (nodes, edges, direction = 'TB') => { const selectedNode = nodes.find(node => node.className?.includes('selected')) layoutedNodes = nodes.map(node => { + const nodeHeight = nodeHeightByType[node.type] ?? nodeHeightByType.default + const nodeWidth = nodeWidthByType[node.type] ?? nodeWidthByType.default const nodeWithPosition = dagreGraph.node(node.id) node.targetPosition = isHorizontal ? 'left' : 'top' node.sourcePosition = isHorizontal ? 'right' : 'bottom' @@ -54,16 +64,16 @@ export const getLayoutedElements = (nodes, edges, direction = 'TB') => { node.className = getNodeClassName(node) node.style = { - width: elWidth, - height: elHeight, + width: nodeWidth, + height: nodeHeight, pointerEvents: 'all' } - // unfortunately we need this little hack to pass a slighltiy different position - // in order to notify react flow about the change + // We are shifting the dagre node position (anchor=center) to the top left + // so it matches the React Flow node anchor point (top left). node.position = { - x: nodeWithPosition.x + Math.random() / 1000, - y: nodeWithPosition.y + x: nodeWithPosition.x - nodeWidth / 2, + y: nodeWithPosition.y - nodeHeight / 2, } return node diff --git a/src/components/DetailsTransformations/DetailsTransformations.jsx b/src/components/DetailsTransformations/DetailsTransformations.jsx index 3918c4febd..ee2edb1892 100644 --- a/src/components/DetailsTransformations/DetailsTransformations.jsx +++ b/src/components/DetailsTransformations/DetailsTransformations.jsx @@ -203,23 +203,25 @@ const DetailsTransformations = ({ selectedItem }) => {
      -
      Configuration
      - - - - +
      +
      Configuration
      + + + + +
      ) diff --git a/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx b/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx index 15b39c1d91..82aee7afa6 100644 --- a/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx +++ b/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx @@ -36,7 +36,12 @@ import { MODELS_PAGE, REQUEST_CANCELED } from '../../../constants' -import { chooseOrFetchModelEndpoint, filtersConfig, generatePageData } from './modelEndpoints.util' +import { + chooseOrFetchModelEndpoint, + filtersConfig, + generateActionsMenu, + generatePageData +} from './modelEndpoints.util' import { createModelEndpointsRowData } from '../../../utils/createArtifactsContent' import { fetchModelEndpoints, removeModelEndpoints } from '../../../reducers/artifactsReducer' import { getNoDataMessage } from '../../../utils/getNoDataMessage' @@ -50,16 +55,12 @@ import { useInitialTableFetch } from '../../../hooks/useInitialTableFetch.hook' import { useModelsPage } from '../ModelsPage.context' import { useSortTable } from '../../../hooks/useSortTable.hook' -import MonitorIcon from 'igz-controls/images/monitor-icon.svg?react' -import Yaml from 'igz-controls/images/yaml.svg?react' - import './modelEndpoints.scss' const ModelEndpoints = () => { const [requestErrorMessage, setRequestErrorMessage] = useState('') const [modelEndpoints, setModelEndpoints] = useState([]) const [selectedModelEndpoint, setSelectedModelEndpoint] = useState({}) - const frontendSpec = useSelector(store => store.appStore.frontendSpec) const artifactsStore = useSelector(store => store.artifactsStore) const filtersStore = useSelector(store => store.filtersStore) const params = useParams() @@ -71,7 +72,7 @@ const ModelEndpoints = () => { const [, setSearchParams] = useSearchParams() const filters = useFiltersFromSearchParams(filtersConfig) - const { handleMonitoring, toggleConvertedYaml } = useModelsPage() + const { handleMonitoring, toggleConvertedYaml, frontendSpec } = useModelsPage() const modelEndpointsRowHeight = useMemo( () => getScssVariableValue('--modelEndpointsRowHeight'), @@ -96,34 +97,20 @@ const ModelEndpoints = () => { ) const actionsMenu = useMemo( - () => [ - [ - { - label: 'Monitoring', - icon: , - tooltip: !frontendSpec.model_monitoring_dashboard_url - ? 'Grafana service unavailable' - : '', - disabled: !frontendSpec.model_monitoring_dashboard_url, - onClick: handleMonitoring, - hidden: !isEmpty(selectedModelEndpoint) - }, - { - label: 'View YAML', - icon: , - onClick: modelEndpointMin => - chooseOrFetchModelEndpoint(dispatch, selectedModelEndpoint, modelEndpointMin).then( - toggleConvertedYaml - ) - } - ] - ], + () => + generateActionsMenu( + frontendSpec.model_monitoring_dashboard_url, + handleMonitoring, + toggleConvertedYaml, + selectedModelEndpoint, + dispatch + ), [ dispatch, - frontendSpec.model_monitoring_dashboard_url, handleMonitoring, selectedModelEndpoint, - toggleConvertedYaml + toggleConvertedYaml, + frontendSpec.model_monitoring_dashboard_url ] ) @@ -192,7 +179,7 @@ const ModelEndpoints = () => { } }, [dispatch, params.projectName]) - useEffect(()=> { + useEffect(() => { return () => { dispatch(clearMetricsOptions()) } diff --git a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx index a86e62fb79..61c36a42ab 100644 --- a/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx +++ b/src/components/ModelsPage/ModelEndpoints/modelEndpoints.util.jsx @@ -17,6 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ +import React from 'react' import { isEmpty } from 'lodash' import { @@ -32,6 +33,8 @@ import { fetchModelEndpoint } from '../../../reducers/artifactsReducer' import { formatDatetime } from 'igz-controls/utils/datetime.util' import Alert from 'igz-controls/images/alerts.svg?react' +import MonitorIcon from 'igz-controls/images/monitor-icon.svg?react' +import Yaml from 'igz-controls/images/yaml.svg?react' export const filtersConfig = { [ME_MODE_FILTER]: { label: 'Mode:', initialValue: FILTER_ALL_ITEMS, isModal: true }, @@ -98,6 +101,35 @@ export const generatePageData = ( } }) +export const generateActionsMenu = ( + modelMonitoringDashboardUrl, + handleMonitoring, + toggleConvertedYaml, + selectedModelEndpoint, + dispatch +) => { + return [ + [ + { + label: 'Monitoring', + icon: , + tooltip: !modelMonitoringDashboardUrl ? 'Grafana service unavailable' : '', + disabled: !modelMonitoringDashboardUrl, + onClick: handleMonitoring, + hidden: !isEmpty(selectedModelEndpoint) + }, + { + label: 'View YAML', + icon: , + onClick: modelEndpointMin => + chooseOrFetchModelEndpoint(dispatch, selectedModelEndpoint, modelEndpointMin).then( + toggleConvertedYaml + ) + } + ] + ] +} + export const monitorModelEndpoint = (model_monitoring_dashboard_url, item, projectName) => { let redirectUrl = model_monitoring_dashboard_url .replace('{project}', projectName) diff --git a/src/components/ModelsPage/ModelsPage.context.jsx b/src/components/ModelsPage/ModelsPage.context.jsx index 4d5bae7d58..404644ecaf 100644 --- a/src/components/ModelsPage/ModelsPage.context.jsx +++ b/src/components/ModelsPage/ModelsPage.context.jsx @@ -50,7 +50,8 @@ export const ModelsPageProvider = ({ children }) => { {children} diff --git a/src/components/Pipeline/Pipeline.jsx b/src/components/Pipeline/Pipeline.jsx index 6653faf9c7..08a5baf14a 100644 --- a/src/components/Pipeline/Pipeline.jsx +++ b/src/components/Pipeline/Pipeline.jsx @@ -20,31 +20,41 @@ such restriction. import React, { useEffect, useState } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import { groupBy, forEach, isEmpty, map, concat } from 'lodash' +import { groupBy, forEach, isEmpty, map, concat, mapValues } from 'lodash' import { Link, useParams } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' -import MlReactFlow from '../../common/ReactFlow/MlReactFlow' +import { Tooltip, TextTooltipTemplate, RoundedIcon, Loader } from 'igz-controls/components' +import Accordion from '../../common/Accordion/Accordion' +import ArtifactPopUp from '../../elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp' import CodeBlock from '../../common/CodeBlock/CodeBlock' +import MlReactFlow from '../../common/ReactFlow/MlReactFlow' +import ModelEndpointPopUp from '../../elements/DetailsPopUp/ModelEndpointPopUp/ModelEndpointPopUp' import NoData from '../../common/NoData/NoData' -import { Tooltip, TextTooltipTemplate, RoundedIcon, Loader } from 'igz-controls/components' import { DEFAULT_EDGE, FLOATING_EDGE, GREY_NODE, ML_EDGE, + ML_MODEL_RUNNER_NODE, ML_NODE, + MODEL_RUNNER_STEP_KIND, PRIMARY_NODE, REAL_TIME_PIPELINES_TAB, ROUNDED_RECTANGLE_NODE_SHAPE, SECONDARY_NODE } from '../../constants' -import { getLayoutedElements } from '../../common/ReactFlow/mlReactFlow.util' import { fetchAndParseFunction } from '../ModelsPage/RealTimePipelines/realTimePipelines.util' +import { getLayoutedElements } from '../../common/ReactFlow/mlReactFlow.util' +import { openPopUp } from 'igz-controls/utils/common.util' +import { parseUri } from '../../utils' +import { useModelsPage } from '../ModelsPage/ModelsPage.context' +import Arrow from 'igz-controls/images/arrow.svg?react' import Back from 'igz-controls/images/back-arrow.svg?react' import CloseIcon from 'igz-controls/images/close.svg?react' +import ConnectionIcon from 'igz-controls/images/connections-icon.svg?react' import './pipeline.scss' @@ -53,11 +63,12 @@ const Pipeline = ({ content }) => { const [edges, setEdges] = useState([]) const [pipeline, setPipeline] = useState({}) const [selectedStep, setSelectedStep] = useState({}) - const [selectedStepData, setSelectedStepData] = useState([]) + const [selectedStepData, setSelectedStepData] = useState({}) const [stepIsSelected, setStepIsSelected] = useState(false) const params = useParams() const dispatch = useDispatch() const functionsStore = useSelector(store => store.functionsStore) + const { handleMonitoring, toggleConvertedYaml, frontendSpec } = useModelsPage() useEffect(() => { const selectedFunction = content.find(contentItem => contentItem.hash === params.pipelineId) @@ -71,44 +82,87 @@ const Pipeline = ({ content }) => { useEffect(() => { if (selectedStep.data) { - const selectedStepData = selectedStep.data.customData - - setSelectedStepData([ - { - label: 'Type:', - value: selectedStepData.kind - }, - { - label: 'After:', - value: selectedStepData.after?.[0] - }, - { - label: 'Class name:', - value: selectedStepData.class_name - }, - { - label: 'Function name:', - value: selectedStepData.function - }, - { - label: 'Handler:', - value: selectedStepData.handler - }, - { - label: 'Arguments:', - value: selectedStepData.class_args, - type: 'codeblock' - }, - { - label: 'Input path:', - value: selectedStepData.input_path - }, - { - label: 'Result path:', - value: selectedStepData.result_path - } - ]) + const selectedStepCustomData = selectedStep.data.customData + + setSelectedStepData({ + general: [ + { + label: 'Type:', + value: selectedStepCustomData.kind + }, + { + label: 'Class name:', + value: selectedStepCustomData.class_name + }, + { + label: 'Function name:', + value: selectedStepCustomData.function + }, + { + label: 'Handler:', + value: selectedStepCustomData.handler, + hidden: selectedStepCustomData.kind === MODEL_RUNNER_STEP_KIND + }, + { + label: 'Arguments:', + value: selectedStepCustomData.class_args, + type: 'codeblock' + }, + { + label: 'Input path:', + value: selectedStepCustomData.input_path + }, + { + label: 'Result path:', + value: selectedStepCustomData.result_path + } + ], + runningModels: mapValues( + selectedStepCustomData?.class_args?.monitoring_data ?? {}, + (runningModelData, runningModelName) => { + return [ + { + label: 'Model endpoint:', + value: runningModelData.model_endpoint_uid, + additionalData: { + modelEndpointName: runningModelName + }, + type: 'pop-up' + }, + { + label: 'Model artifact:', + value: runningModelData.model_path, + type: 'pop-up' + }, + { + label: 'Class name:', + value: runningModelData.model_class + }, + { + label: 'Input path:', + value: runningModelData.input_path + }, + { + label: 'Result path:', + value: runningModelData.result_path + }, + { + label: 'Outputs:', + value: runningModelData.outputs.join(', ') + }, + { + label: 'Execution mechanism:', + value: + selectedStepCustomData?.class_args?.execution_mechanism_by_model_name?.[ + runningModelName + ] ?? '' + } + ] + } + ) + }) } + setStepIsSelected(Boolean(selectedStep.id)) }, [selectedStep]) @@ -142,12 +196,15 @@ const Pipeline = ({ content }) => { } forEach(steps, (step, stepName) => { + if (!step.kind) return + + let nodeType = step.kind === MODEL_RUNNER_STEP_KIND ? ML_MODEL_RUNNER_NODE : ML_NODE const subLabel = step.kind === 'queue' ? '« queue »' : step.kind === 'router' ? '« router »' : '' newNodes.push({ id: stepName, - type: ML_NODE, + type: nodeType, data: { subType: PRIMARY_NODE, label: stepName, @@ -268,6 +325,22 @@ const Pipeline = ({ content }) => { } }, [pipeline, selectedStep]) + const openModelRunnerPopUp = modelRunnerRowData => { + if (modelRunnerRowData.value.startsWith('store://')) { + openPopUp(ArtifactPopUp, { + artifactData: parseUri(modelRunnerRowData.value) + }) + } else { + openPopUp(ModelEndpointPopUp, { + modelEndpointUid: modelRunnerRowData.value, + modelEndpointName: modelRunnerRowData.additionalData.modelEndpointName, + frontendSpec, + handleMonitoring, + toggleConvertedYaml + }) + } + } + return (
      @@ -305,28 +378,92 @@ const Pipeline = ({ content }) => {
      {stepIsSelected && (
      -
      - {selectedStep.id} - setSelectedStep({})} tooltipText="Close"> - - -
      - {selectedStepData.map(rowData => ( -
      - {rowData.type === 'codeblock' ? ( - - ) : ( - <> -
      {rowData.label}
      -
      - }> - {rowData.value} - -
      - +
      +
      +
      + +
      + + setSelectedStep({})} tooltipText="Close"> + + +
      +
      +
      General
      + {selectedStepData.general.map( + rowData => + !rowData.hidden && ( +
      +
      {rowData.label}
      + {rowData.type === 'codeblock' ? ( + + ) : ( +
      + }> + {rowData.value} + +
      + )} +
      + ) )}
      - ))} + {Object.keys(selectedStepData.runningModels).length > 0 && ( +
      +
      + Running models ({Object.keys(selectedStepData.runningModels).length}) +
      + {Object.entries(selectedStepData.runningModels).map( + ([modelRunnerName, modelRunnerData]) => ( + } + iconClassName="graph-pane__expand-icon" + > +
      {modelRunnerName}
      +
      + {modelRunnerData.map(rowData => { + return ( +
      +
      {rowData.label}
      +
      openModelRunnerPopUp(rowData) + : null + } + > + } + className={classnames({ link: rowData.type === 'pop-up' })} + > + {rowData.value} + +
      +
      + ) + })} +
      +
      + ) + )} +
      + )} +
      )}
      diff --git a/src/components/Pipeline/pipeline.scss b/src/components/Pipeline/pipeline.scss index 6ae61b1ad7..04d6bf5615 100644 --- a/src/components/Pipeline/pipeline.scss +++ b/src/components/Pipeline/pipeline.scss @@ -33,21 +33,79 @@ .pipeline-content { .graph-pane { + &__section { + padding: 15px 0; + + & + .graph-pane__section { + border-top: borders.$secondaryBorder; + } + + &-title { + font-size: 16px; + font-weight: bold; + padding: 5px 25px; + } + } + &__row { display: flex; align-items: center; - margin: 5px 25px; + margin: 8px 25px; + + &_wrap { + flex-wrap: wrap; + } &-label { margin-right: 10px; - color: colors.$spunPearl; - font-weight: bold; white-space: nowrap; } &-value { overflow: hidden; + color: colors.$topaz; + } + } + + .graph-pane__expand-item { + height: unset; + margin-left: 20px; + margin-right: 20px; + border-bottom: borders.$secondaryBorder; + + .graph-pane__row { + margin-left: 0; + margin-right: 0; + } + + .graph-pane__expand-title { + margin-left: 45px; + padding: 8px 0; + font-weight: bold; + font-size: 15px; } + + .graph-pane__expand-content { + display: none; + margin: 5px 0 20px 45px; + } + + &.open { + height: auto; + + .graph-pane__expand-content { + display: block; + } + } + + .graph-pane__expand-icon { + position: absolute; + left: 0; + } + } + + .code-block { + margin-top: 5px; } } } diff --git a/src/constants.js b/src/constants.js index 45c67fce0a..261f4e389f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -282,6 +282,10 @@ export const FUNCTION_DEFAULT_HANDLER = 'handler' export const FUNCTION_RUN_KINDS = [FUNCTION_TYPE_JOB] export const FUNCTION_FILTERS = 'FUNCTION_FILTERS' +/*=========== PIPELINES =============*/ + +export const MODEL_RUNNER_STEP_KIND = 'model_runner' + /*=========== ARTIFACTS =============*/ export const ARTIFACTS_TAB = 'artifacts' @@ -421,6 +425,7 @@ export const PANEL_DEFAULT_ACCESS_KEY = '$generate' /*=========== ML REACT FLOW =============*/ export const ML_NODE = 'ml-node' +export const ML_MODEL_RUNNER_NODE = 'ml-model-runner-node' export const INPUT_NODE = 'input-node' export const OUTPUT_NODE = 'output-node' diff --git a/src/elements/DetailsPopUp/ModelEndpointPopUp/ModelEndpointPopUp.jsx b/src/elements/DetailsPopUp/ModelEndpointPopUp/ModelEndpointPopUp.jsx new file mode 100644 index 0000000000..74899e8b16 --- /dev/null +++ b/src/elements/DetailsPopUp/ModelEndpointPopUp/ModelEndpointPopUp.jsx @@ -0,0 +1,132 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useDispatch } from 'react-redux' +import { useParams } from 'react-router-dom' +import { isEmpty } from 'lodash' +import PropTypes from 'prop-types' + +import DetailsPopUp from '../DetailsPopUp' + +import { + generatePageData, + generateActionsMenu +} from '../../../components/ModelsPage/ModelEndpoints/modelEndpoints.util' +import modelEndpointsApi from '../../../api/modelEndpoints-api' +import { parseModelEndpoints } from '../../../utils/parseModelEndpoints' +import { showErrorNotification } from 'igz-controls/utils/notification.util' + +const ModelEndpointPopUp = ({ + modelEndpointUid, + modelEndpointName, + frontendSpec, + handleMonitoring, + isOpen, + onResolve, + toggleConvertedYaml +}) => { + const dispatch = useDispatch() + const params = useParams() + const [isLoading, setIsLoading] = useState(true) + const [selectedModelEndpoint, setSelectedModelEndpoint] = useState({}) + + const modelMonitoringDashboardUrl = useMemo( + () => frontendSpec.model_monitoring_dashboard_url, + [frontendSpec.model_monitoring_dashboard_url] + ) + + const fetchModelEndpoint = useCallback(() => { + setIsLoading(true) + + return modelEndpointsApi + .getModelEndpoint( + params.projectName, + modelEndpointName, + modelEndpointUid + ) + .then(({ data: endpoint }) => { + setSelectedModelEndpoint(parseModelEndpoints([endpoint])?.[0]) + setIsLoading(false) + }) + .catch(error => { + showErrorNotification( + dispatch, + error, + '', + 'This model endpoint either does not exist or was deleted' + ) + + onResolve() + }) + }, [dispatch, modelEndpointName, modelEndpointUid, onResolve, params.projectName]) + + const actionsMenu = useMemo( + () => + generateActionsMenu( + modelMonitoringDashboardUrl, + handleMonitoring, + toggleConvertedYaml, + selectedModelEndpoint, + dispatch + ), + [ + dispatch, + handleMonitoring, + selectedModelEndpoint, + toggleConvertedYaml, + modelMonitoringDashboardUrl + ] + ) + + const pageData = useMemo( + () => generatePageData(selectedModelEndpoint, modelMonitoringDashboardUrl, handleMonitoring), + [modelMonitoringDashboardUrl, handleMonitoring, selectedModelEndpoint] + ) + + useEffect(() => { + if (isEmpty(selectedModelEndpoint)) { + fetchModelEndpoint() + } + }, [fetchModelEndpoint, selectedModelEndpoint]) + + return ( + + ) +} + +ModelEndpointPopUp.propTypes = { + frontendSpec: PropTypes.object.isRequired, + handleMonitoring: PropTypes.func.isRequired, + isOpen: PropTypes.bool.isRequired, + modelEndpointUid: PropTypes.string.isRequired, + modelEndpointName: PropTypes.string.isRequired, + onResolve: PropTypes.func.isRequired, + toggleConvertedYaml: PropTypes.func.isRequired +} + +export default ModelEndpointPopUp diff --git a/src/scss/main.scss b/src/scss/main.scss index 3361e1bdff..dcba51a691 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -311,16 +311,21 @@ main { } .graph-pane { + position: relative; display: flex; - flex-direction: column; - width: 25%; - min-width: 350px; - overflow-y: auto; + width: 30%; + min-width: 400px; + color: colors.$primary; background: colors.$white; border: borders.$secondaryBorder; box-shadow: 0 0 30px rgba(colors.$black, 0.15); - &.scrollable { + &-scroll-container { + position: absolute; + top: 0; + right: 0; + width: 100%; + height: 100%; overflow-y: auto; } @@ -328,9 +333,24 @@ main { display: flex; align-items: center; justify-content: space-between; - padding: 25px; + padding: 10px 25px; + border-bottom: borders.$secondaryBorder; font-weight: bold; font-size: 20px; + position: sticky; + top: 0; + z-index: 1; + background-color: colors.$white; + + &-icon { + margin-right: 8px; + display: flex; + align-items: center; + } + + &-label { + margin-right: auto; + } } } } diff --git a/src/types.js b/src/types.js index 7777d03436..8ad5a2881c 100644 --- a/src/types.js +++ b/src/types.js @@ -18,17 +18,22 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import PropTypes from 'prop-types' -import {isEmpty} from 'lodash' import { BE_PAGE, BE_PAGE_SIZE, FE_PAGE, FE_PAGE_SIZE, + GREY_NODE, + INPUT_NODE, + OUTPUT_NODE, + OVAL_NODE_SHAPE, PANEL_CREATE_MODE, PANEL_EDIT_MODE, PANEL_FUNCTION_CREATE_MODE, PANEL_RERUN_MODE, - STATUS_FILTER_NAME + PRIMARY_NODE, + ROUNDED_RECTANGLE_NODE_SHAPE, + SECONDARY_NODE } from './constants' import { BUTTON_VARIANTS } from 'igz-controls/types' @@ -238,3 +243,23 @@ export const MEMBER = PropTypes.shape({ initialRole: PropTypes.string, modification: PropTypes.string }) + +export const REACT_FLOW_NODE_DATA = PropTypes.shape({ + subType: PropTypes.oneOf([INPUT_NODE, OUTPUT_NODE, PRIMARY_NODE, SECONDARY_NODE, GREY_NODE]) + .isRequired, + label: PropTypes.string.isRequired, + tip: PropTypes.string, + subLabel: PropTypes.string, + isSelectable: PropTypes.bool, + withOpacity: PropTypes.bool, + shape: PropTypes.oneOf([OVAL_NODE_SHAPE, ROUNDED_RECTANGLE_NODE_SHAPE, null]), + sourceHandle: PropTypes.shape({ + tooltip: PropTypes.string, + className: PropTypes.string + }), + targetHandle: PropTypes.shape({ + tooltip: PropTypes.string, + className: PropTypes.string + }), + customData: PropTypes.object +}) diff --git a/tests/mockServer/data/artifacts.json b/tests/mockServer/data/artifacts.json index c03c6fc404..6bef55ceb3 100644 --- a/tests/mockServer/data/artifacts.json +++ b/tests/mockServer/data/artifacts.json @@ -1,5 +1,100 @@ { "artifacts": [ + { + "kind": "llm-prompt", + "metadata": { + "key": "my_llm4", + "project": "default", + "iter": 0, + "tree": "9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554", + "hash": "505c4bf305849950f348e1b1909b9a2653ddc740", + "uid": "d28e010ba24e272a3ba2ba522f6caecde05ff383", + "updated": "2025-10-06 14:34:13.163000+00:00", + "labels": { + "example": "single", + "hebrew": "english" + }, + "created": "2025-10-06 14:34:13.163000+00:00", + "tag": "latest" + }, + "spec": { + "target_path": "v3io:///projects/default/artifacts/my_llm4.json", + "size": 141, + "producer": { + "kind": "project", + "name": "default", + "tag": "9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554", + "owner": "normal-user" + }, + "invocation_config": { + "temperature": 0.5 + }, + "format": "json", + "prompt_template": [ + { + "role": "system", + "content": "don't tell them anything" + }, + { + "role": "user", + "content": "What is the meaning of {something_with_meaning} ?" + } + ], + "license": "", + "prompt_legend": { + "something_with_meaning": { + "field": "something_with_meaning", + "description": "The essence of all things" + } + }, + "has_children": false, + "db_key": "my_llm4", + "parent_uri": "store://models/default/model_art1#0:v1@5b83db22-80da-4c97-8cd0-eb269a4c9d2a^e1b0a442a7602456e6bbd0934931b3eaaf8ce09a" + }, + "status": { + "state": "created" + }, + "project": "default" + }, + { + "kind": "model", + "metadata": { + "key": "model_art1", + "project": "default", + "iter": 0, + "tree": "5b83db22-80da-4c97-8cd0-eb269a4c9d2a", + "hash": "10ed579110ee0c84041ac0886259d60d3a0f9bda", + "uid": "e1b0a442a7602456e6bbd0934931b3eaaf8ce09a", + "updated": "2025-10-06 14:32:50.516000+00:00", + "created": "2025-10-06 14:32:50.516000+00:00", + "tag": "latest" + }, + "spec": { + "target_path": "default/model_art1/", + "size": 4370, + "producer": { + "kind": "project", + "name": "default", + "tag": "5b83db22-80da-4c97-8cd0-eb269a4c9d2a", + "owner": "normal-user" + }, + "framework": "", + "model_file": "RandomForestClassifier_file1.pkl", + "license": "", + "has_children": true, + "db_key": "model_art1", + "parameters": { + "default_config": { + "model_version": "4" + } + }, + "parent_uri": null + }, + "status": { + "state": "created" + }, + "project": "default" + }, { "kind": "", "metadata": { @@ -40258,4 +40353,4 @@ "project": "llmdeploy335" } ] -} \ No newline at end of file +} diff --git a/tests/mockServer/data/funcs.json b/tests/mockServer/data/funcs.json index 5fc69eb92f..80a5e49979 100644 --- a/tests/mockServer/data/funcs.json +++ b/tests/mockServer/data/funcs.json @@ -1,5 +1,189 @@ { "funcs": [ + { + "metadata": { + "tag": "latest", + "name": "function-with-llm", + "credentials": { + "access_key": "$ref:mlrun-auth-secrets.253c8a6e4c3595da61cbc90b60036ec928934dd6826298fcc3b5e3c3" + }, + "project": "default", + "hash": "a87f91c90d26cdc8d03bb3fcb1423d0ea005b00e", + "updated": "2025-10-06T14:36:35.053000+00:00" + }, + "spec": { + "base_image_pull": false, + "default_handler": "", + "function_kind": "serving_v2", + "preemption_mode": "prevent", + "function_handler": "function-with-llm-nuclio:handler", + "max_replicas": 4, + "min_replicas": 1, + "description": "", + "source": "", + "graph": { + "steps": { + "model-runner": { + "class_args": { + "model_selector": [ + null, + null + ], + "execution_mechanism_by_model_name": { + "my-endpoint": "shared_executor" + }, + "models": { + "my-endpoint": [ + "mlrun.serving.Model", + { + "name": "my-endpoint", + "shared_runnable_name": "model-deployment", + "artifact_uri": "store://llm-prompts/default/my_llm4#0@9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554^d28e010ba24e272a3ba2ba522f6caecde05ff383" + } + ] + }, + "monitoring_data": { + "my-endpoint": { + "inputs": [ ], + "outputs": [ ], + "input_path": null, + "result_path": null, + "creation_strategy": "inplace", + "labels": null, + "model_path": "store://llm-prompts/default/my_llm4#0@9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554^d28e010ba24e272a3ba2ba522f6caecde05ff383", + "model_class": "MyLLM", + "model_endpoint_uid": "c3e9308aaab54e53b1013ecda9234e43" + } + } + }, + "responder": true, + "kind": "model_runner", + "endpoint_type": 1, + "model_endpoint_creation_strategy": "skip", + "class_name": "mlrun.serving.ModelRunner", + "raise_exception": true, + "_shared_proxy_mapping": { + "model-deployment": { + "my-endpoint": "store://llm-prompts/default/my_llm4#0:latest@9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554^d28e010ba24e272a3ba2ba522f6caecde05ff383" + } + }, + "shape": "folder" + }, + "track_models": true + }, + "shared_models": { + "model-deployment": [ + "MyLLM", + { + "name": "model-deployment", + "artifact_uri": "store://models/default/model_art1#0@5b83db22-80da-4c97-8cd0-eb269a4c9d2a^e1b0a442a7602456e6bbd0934931b3eaaf8ce09a", + "inputs": [ ], + "outputs": [ ], + "input_path": null, + "result_path": null + } + ] + }, + "engine": "async", + "track_models": false, + "model_endpoints_names": [ + "my-endpoint" + ], + "shared_models_mechanism": { + "model-deployment": "naive" + } + }, + "build": { + "functionSourceCode": "IyBDb3B5cmlnaHQgMjAyNSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAojCiMgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQojIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiMgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAojIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgoKZnJvbSBtbHJ1bi5zZXJ2aW5nIGltcG9ydCBMTE1vZGVsCgoKY2xhc3MgTXlMTE0oTExNb2RlbCk6CiAgICBkZWYgcHJlZGljdChzZWxmLCBib2R5LCBtZXNzYWdlcywgbW9kZWxfY29uZmlndXJhdGlvbik6CiAgICAgICAgYm9keVsidXJsIl0gPSBzZWxmLm1vZGVsX2FydGlmYWN0Lm1vZGVsX3VybAogICAgICAgIGJvZHlbImRlZmF1bHRfY29uZmlnIl0gPSBzZWxmLm1vZGVsX2FydGlmYWN0LmRlZmF1bHRfY29uZmlnCiAgICAgICAgYm9keVsicHJvbXB0Il0gPSBtZXNzYWdlcwogICAgICAgIHJldHVybiBib2R5CmZyb20gbWxydW4ucnVudGltZXMgaW1wb3J0IG51Y2xpb19pbml0X2hvb2sKZGVmIGluaXRfY29udGV4dChjb250ZXh0KToKICAgIG51Y2xpb19pbml0X2hvb2soY29udGV4dCwgZ2xvYmFscygpLCAnc2VydmluZ192MicpCgpkZWYgaGFuZGxlcihjb250ZXh0LCBldmVudCk6CiAgICByZXR1cm4gY29udGV4dC5tbHJ1bl9oYW5kbGVyKGNvbnRleHQsIGV2ZW50KQoKZnJvbSBtbHJ1bi5zZXJ2aW5nLnN0YXRlcyBpbXBvcnQgTExNb2RlbAo=", + "code_origin": "./function_with_llm.py", + "origin_filename": "./function_with_llm.py", + "secret": "" + }, + "command": "http://default-function-with-llm.default-tenant.app.vmdev82.lab.iguazeng.com/", + "disable_auto_mount": true, + "priority_class_name": "igz-workload-medium", + "filename": "./function_with_llm.py", + "image": "mlrun/mlrun", + "node_selector": { }, + "env": [ + { + "name": "MLRUN_HTTPDB__NUCLIO__EXPLICIT_ACK", + "value": "enabled" + }, + { + "name": "V3IO_API", + "value": "v3io-webapi.default-tenant.svc:8081" + }, + { + "name": "V3IO_USERNAME", + "value": "normal-user" + }, + { + "name": "V3IO_FRAMESD", + "value": "framesd:8081" + }, + { + "name": "V3IO_ACCESS_KEY", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.89488b129fafa22ca44076258f6b1cb249d3120f9c66d699ce6d4b68" + } + } + }, + { + "name": "MLRUN_AUTH_SESSION", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.253c8a6e4c3595da61cbc90b60036ec928934dd6826298fcc3b5e3c3" + } + } + } + ], + "volumes": [ + { + "name": "serving-conf", + "configMap": { + "name": "serving-conf-default-function-with-llm" + } + } + ], + "affinity": null, + "resources": { + "requests": { + "memory": "1Mi", + "cpu": "25m" + }, + "limits": { + "memory": "20Gi", + "cpu": "2" + } + }, + "tolerations": null, + "volume_mounts": [ + { + "name": "serving-conf", + "mountPath": "/tmp/mlrun/serving-conf", + "readOnly": true + } + ] + }, + "verbose": false, + "status": { + "address": "default-function-with-llm.default-tenant.app.vmdev82.lab.iguazeng.com/", + "external_invocation_urls": [ + "default-function-with-llm.default-tenant.app.vmdev82.lab.iguazeng.com/" + ], + "nuclio_name": "default-function-with-llm", + "container_image": "docker-registry.default-tenant.app.vmdev82.lab.iguazeng.com:80/nuclio/default-default-function-with-llm-processor:latest", + "internal_invocation_urls": [ + "nuclio-default-function-with-llm.default-tenant.svc.cluster.local:8080" + ], + "state": "ready" + }, + "kind": "serving" + }, { "kind": "job", "metadata": { diff --git a/tests/mockServer/data/modelEndpoints.json b/tests/mockServer/data/modelEndpoints.json index ed9bc50487..6c8b119d92 100644 --- a/tests/mockServer/data/modelEndpoints.json +++ b/tests/mockServer/data/modelEndpoints.json @@ -1,5 +1,54 @@ { "endpoints": [ + { + "kind": "model-endpoint", + "metadata": { + "name": "my-endpoint", + "project": "default", + "tag": null, + "labels": { + "example": "single", + "hebrew": "english" + }, + "updated": "2025-10-06T14:34:14.015000", + "created": "2025-09-30T19:45:05.516000", + "uid": "c3e9308aaab54e53b1013ecda9234e43", + "endpoint_type": 1, + "mode": 0 + }, + "spec": { + "model_class": "MyLLM", + "function_name": "function-with-llm", + "function_tag": "latest", + "model_path": "store://llm-prompts/default/my_llm4#0@be464b11-8bff-4d57-9ad5-89d7d641f35e^5523a661476a8ab1ba573c704308f036e62b8d17", + "model_name": "my_llm4", + "model_tags": [ + "latest" + ], + "feature_names": [], + "label_names": [], + "feature_stats": {}, + "function_uri": "default/function-with-llm@unversioned-latest", + "model_uri": "store://llm-prompts/default/my_llm4#0@9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554^d28e010ba24e272a3ba2ba522f6caecde05ff383", + "children": null, + "children_uids": null, + "monitoring_feature_set_uri": "" + }, + "status": { + "state": "ready", + "first_request": null, + "monitoring_mode": "disabled", + "sampling_percentage": 100, + "last_request": null, + "result_status": -1, + "avg_latency": null, + "error_count": 0, + "current_stats": {}, + "current_stats_timestamp": null, + "drift_measures": {}, + "drift_measures_timestamp": null + } + }, { "kind": "model-endpoint", "metadata": { From 846adaaddae544958cb2a62fa0816a17fecb3864 Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Mon, 3 Nov 2025 08:15:23 +0100 Subject: [PATCH 206/228] Tests [QA] v1.10.0-rc33 (#3485) --- tests/features/common-tools/common-consts.js | 5 +- .../features/common/actions/common.action.js | 7 + .../page-objects/interactive-popup.po.js | 3 +- .../common/page-objects/llm-prompts.po.js | 4 +- .../common/page-objects/projects.po.js | 50 +++++- tests/features/jobsAndWorkflows.feature | 2 +- tests/features/jobsMonitoring.feature | 115 +++++-------- tests/features/llmPrompts.feature | 160 ++++++++++++++++++ tests/features/projectsPage.feature | 48 ++++++ tests/features/step-definitions/steps.js | 11 ++ tests/mockServer/data/alerts.json | 8 +- tests/mockServer/data/artifacts.json | 9 +- tests/mockServer/mock.js | 4 +- 13 files changed, 334 insertions(+), 92 deletions(-) diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index 2061db0cc6..1bdd7adea9 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -309,6 +309,7 @@ export default { 'Metrics:' ], Overview_Producer_Headers: ['Name:', 'Kind:', 'URI:', 'Owner:', 'Workflow:', 'UID:'], + Overview_Producer_Headers_Kind_Project: ['Name:', 'Kind:', 'Tag:', 'Owner:', 'UID:'], Overview_Sources_Headers: ['Name:', 'Path:'] }, Models_Endpoints_Info_Pane: { @@ -421,6 +422,7 @@ export default { Auto_Refresh: 'Uncheck Auto Refresh to view more results', FilterBy_Button: 'Filter', FilterBy_Button_1: 'Filter (1)', + FilterBy_Button_2: 'Filter (2)', Argument: 'The essence of all things', Show_All_Versions: 'Show all versions', Open_Metrics: 'Open metrics', @@ -794,8 +796,9 @@ export default { /No data matches the filter: "Start time: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, Common_Message_Monitor_Jobs_Name: /No data matches the filter: "Name: (.+?)"/, Common_Message_LLM_Prompt_Name: /No data matches the filter: "Name: (.+?), LLM prompt version tag: (.+?), Show best iteration only: (.+?)"/, - Common_Message_LLM_Prompt_Label: /No data matches the filter: "Name: (.+?), LLM prompt version tag: (.+?), Labels: (.+?), Show best iteration only: (.+?)"/, + Common_Message_LLM_Prompt_Label: /No data matches the filter: "Name: (.+?), LLM prompt version tag: (.+?), Labels: (.+?), Show best iteration only: (.+?), Model name: (.+?), Model version tag: (.+?)"/, Common_Message_LLM_Prompt_Tag: /No data matches the filter: "LLM prompt version tag: (.+?), Show best iteration only: (.+?)"/, + Common_Message_LLM_Prompt_Model_Name_Tag: /No data matches the filter: "LLM prompt version tag: (.+?), Show best iteration only: (.+?)"/, Common_Message_Artifact_Tag: /No data matches the filter: "Version tag: (.+?), Show best iteration only: (.+?)"/, Common_Message_Jobs_Monitoring_Workflow_Project: /No data matches the filter: "Created at: \d{2}\/\d{2}\/\d{4} \d{2}:\d{2} - \d{2}\/\d{2}\/\d{4} \d{2}:\d{2}, Project: (.+?)"/, diff --git a/tests/features/common/actions/common.action.js b/tests/features/common/actions/common.action.js index b076d146f8..15e7ae4a37 100644 --- a/tests/features/common/actions/common.action.js +++ b/tests/features/common/actions/common.action.js @@ -106,6 +106,13 @@ export const verifyClassDisabled = async (driver, component) => { expect(flag).equal(true) } +export const verifyClassEnabled = async (driver, component) => { + const inputField = await driver.findElement(component) + const attributes = await inputField.getAttribute('class') + const flag = attributes.includes('form-field__wrapper-disabled') + expect(flag).equal(false) +} + export const verifyElementDisabled = async (driver, component) => { const element = await driver.findElement(component) const flag = await element.getAttribute('disabled') diff --git a/tests/features/common/page-objects/interactive-popup.po.js b/tests/features/common/page-objects/interactive-popup.po.js index 0333ae1ac7..5a83c9f103 100644 --- a/tests/features/common/page-objects/interactive-popup.po.js +++ b/tests/features/common/page-objects/interactive-popup.po.js @@ -813,7 +813,8 @@ export default { Logs_Refresh_Button: By.css('#overlay_container .table__item .logs-refresh'), Requested_Features_Table: By.css('.item-info .item-requested-features__table'), Returned_Features_Table: By.css('.item-info .details-metadata__table'), - Statistics_Table: By.css('.item-info #DETAILS_STATISTICS_TABLE_ID') + Statistics_Table: By.css('.item-info #DETAILS_STATISTICS_TABLE_ID'), + Pop_Out_Button: By.css('[data-testid="details-preview-tooltip-wrapper"]') }, modalWizardForm: { Title: By.css('.modal .modal__header-title'), diff --git a/tests/features/common/page-objects/llm-prompts.po.js b/tests/features/common/page-objects/llm-prompts.po.js index 372510628a..9e86b42f1d 100644 --- a/tests/features/common/page-objects/llm-prompts.po.js +++ b/tests/features/common/page-objects/llm-prompts.po.js @@ -82,7 +82,9 @@ const overallTable = { componentType: actionMenu, structure: actionMenuStructure }, - preview: '.table-body__cell:nth-of-type(8) [data-testid="quick-link-artifact-preview"]' + preview: '.table-body__cell:nth-of-type(8) [data-testid="quick-link-artifact-preview"]', + model_name: '[data-testid="modelName"] .model-name .link', + model_tag: '[data-testid="modelName"] .item-tag .link-subtext' } } } diff --git a/tests/features/common/page-objects/projects.po.js b/tests/features/common/page-objects/projects.po.js index 6b0d2832c4..7d1782c2fa 100644 --- a/tests/features/common/page-objects/projects.po.js +++ b/tests/features/common/page-objects/projects.po.js @@ -118,7 +118,7 @@ const projectsTabSelector = { export default { Projects_Tab_Selector: commonTable(projectsTabSelector), Retrieving_Projects_Message: By.css('[data-testid=no-data]'), - No_Archived_Projects_Message: By.css('.no-filtered-data'), + No_Archived_Projects_Message: By.css('[data-testid="no-data"] h3'), New_Project_Button: By.css( '.projects__wrapper .projects-content-header-item .page-actions-container .btn_register' ), @@ -150,12 +150,18 @@ export default { Monitoring_Container_Title: By.css( '.projects-monitoring-container .page-header__title' ), + Monitoring_Artifacts_Box: By.css( + '.projects-monitoring-container .projects-monitoring-stats.projects-monitoring-stats_wide > div:nth-child(1)' + ), Monitoring_Jobs_Box: By.css( - '.projects-monitoring-container .projects-monitoring-stats .stats-card:nth-of-type(1)' + '.projects-monitoring-container .projects-monitoring-stats .stats-card:nth-of-type(2)' ), Monitoring_Workflows_Box: By.css( '.projects-monitoring-container .projects-monitoring-stats .stats-card:nth-of-type(2)' ), + Monitoring_Models_Box: By.css( + '.projects-monitoring-container .projects-monitoring-stats .card__small-container' + ), Monitoring_Scheduled_Box: By.css( '.projects-monitoring-container .projects-monitoring-stats .stats-card:nth-of-type(3)' ), @@ -163,6 +169,38 @@ export default { '.projects-monitoring-container .projects-monitoring-stats .stats-card:nth-of-type(3)' ) }, + Monitoring_Artifacts_Box: { + Monitoring_Artifacts_Box_Title: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats-card__row .stats-card__title .tooltip-wrapper' + ), + Total_Counter_Number: By.css( + '.projects-monitoring-stats > div:nth-child(1) [data-testid="artifacts_total_counter"]' + ), + Counter_Datasets_Number: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats__details .stats-card__row:nth-of-type(1) .stats__counter' + ), + Counter_Datasets_Subtitle: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(1) .stats__subtitle' + ), + Counter_Documents_Number: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats__details .stats-card__row:nth-of-type(2) .stats__counter' + ), + Counter_Documents_Subtitle: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(2) .stats__subtitle' + ), + Counter_LLM_Prompt_Number: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats__details .stats-card__row:nth-of-type(3) .stats__counter' + ), + Counter_LLM_Prompt_Subtitle: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(3) .stats__subtitle' + ), + Counter_Other_Artifacts_Number: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats__details .stats-card__row:nth-of-type(4) .stats__counter' + ), + Counter_Other_Artifacts_Subtitle: By.css( + '.projects-monitoring-stats > div:nth-child(1) .stats-card__row:nth-of-type(4) .stats__subtitle' + ) + }, Monitoring_Jobs_Box: { Monitoring_Jobs_Box_Title: By.css( '.projects-monitoring-stats > div:nth-child(2) .stats-card__title .tooltip-wrapper' @@ -259,6 +297,14 @@ export default { '.projects-monitoring-stats > div:nth-child(4) [data-testid="scheduled_total_counter"]' ) }, + Monitoring_Models_Box: { + Monitoring_Models_Title: By.css( + '.projects-monitoring-stats .card__small-container .stats-card__row .stats-card__title .tooltip-wrapper' + ), + Total_Counter_Number: By.css( + '.projects-monitoring-stats .card__small-container [data-testid="models_total_counter"]' + ) + }, Monitoring_Alerts_Box: { Monitoring_Alerts_Box_Title: By.css( '.projects-monitoring-stats .alerts-card .stats-card__title .data-ellipsis' diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index c7ae1bedd5..355055a0e7 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -283,7 +283,6 @@ Feature: Jobs and workflows And wait load page When pick up "Custom range" from "03/31/2014 10:30" to "03/21/2015 19:15" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard And wait load page - And wait load page Then verify from "03/31/2014 10:30" to "03/21/2015 19:15" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard When pick up "Custom range" from "03/31/2044 10:30" to "03/21/2015 19:15" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard And wait load page @@ -525,6 +524,7 @@ Feature: Jobs and workflows When click on cell with row index 1 in "name" column in "Jobs_Monitor_Table" table on "Jobs_Monitor_Tab" wizard And wait load page When pick up "Custom range" from "01/01/2021 00:00" to "01/01/2023 00:00" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitor_Tab" wizard + And wait load page Then verify from "01/01/2021 00:00" to "01/01/2023 00:00" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitor_Tab" wizard And wait load page When click on cell with row index 1 in "name" column in "Jobs_Monitor_Table" table on "Jobs_Monitor_Tab" wizard diff --git a/tests/features/jobsMonitoring.feature b/tests/features/jobsMonitoring.feature index 561ac2e71d..91a5c912db 100644 --- a/tests/features/jobsMonitoring.feature +++ b/tests/features/jobsMonitoring.feature @@ -754,26 +754,12 @@ Feature: Jobs Monitoring Page Then select "Terminate" option in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table at row with "main 2021-08-30 05-36-35" value in "name" column Then verify if "Confirm_Popup" popup dialog appears Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard - When click on "Delete_Button" element on "Confirm_Popup" wizard - And wait load page - Then verify if "Notification_Popup" popup dialog appears - Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" - Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard - Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard - When click on cell with row index 1 in "name" column in "Workflows_Table" table on "Jobs_Monitoring_Workflows_Tab" wizard - And wait load page - Then verify "Terminate_Button" element visibility on "Jobs_Monitoring_Workflows_Tab" wizard - Then "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" should contains "Terminate" value - Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled - Then click on "Arrow_Back" element on "Workflows_Monitor_Tab_Info_Pane" wizard - And wait load page - Then verify that in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "main 2021-08-30 05-36-35" value in "name" column "Terminate" option is disabled + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then verify that in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "main 2021-08-30 05-36-35" value in "name" column "Terminate" option is enabled And wait load page @MLJM @smoke - # !!! restart mock is required Scenario: MLJM018 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status on workflow runs graph view Given open url And wait load page @@ -809,22 +795,11 @@ Feature: Jobs Monitoring Page Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard Then verify if "Confirm_Popup" popup dialog appears Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard - When click on "Delete_Button" element on "Confirm_Popup" wizard - And wait load page - Then verify if "Notification_Popup" popup dialog appears - Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" - Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard - Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard - Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled - Then click on "Arrow_Back" element on "Workflows_Monitor_Tab_Info_Pane" wizard - And wait load page - Then verify that in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "main 2021-08-30 05-36-35" value in "name" column "Terminate" option is disabled - And wait load page + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is enabled @MLJM @smoke - # !!! restart mock is required Scenario: MLJM019 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status on workflow runs list view Given open url And wait load page @@ -867,22 +842,11 @@ Feature: Jobs Monitoring Page Then click on "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard Then verify if "Confirm_Popup" popup dialog appears Then verify "Delete_Button" element visibility on "Confirm_Popup" wizard - When click on "Delete_Button" element on "Confirm_Popup" wizard - And wait load page - Then verify if "Notification_Popup" popup dialog appears - Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard - Then "Notification_Pop_Up" component on "Notification_Popup" should contains "Jobs_And_Workflows"."Workflows_Trigger_Termination_Message" - Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard - Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard - Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is disabled - Then click on "Arrow_Back" element on "Workflows_Monitor_Tab_Info_Pane" wizard - And wait load page - Then verify that in action menu on "Jobs_Monitoring_Workflows_Tab" wizard in "Workflows_Table" table with "main 2021-08-30 05-36-35" value in "name" column "Terminate" option is disabled - And wait load page + When click on "Cancel_Button" element on "Confirm_Popup" wizard + Then verify "Terminate_Button" element on "Jobs_Monitoring_Workflows_Tab" wizard is enabled @MLJM @smoke - # !!! restart mock is required Scenario: MLJM020 - Check the Terminate functionality on Workflows tab of Jobs monitoring page with running status with run detail pane Given open url And wait load page @@ -1082,8 +1046,8 @@ Feature: Jobs Monitoring Page Then "Title" element on "FilterBy_Popup" should contains "Filter by" value Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" - Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Type_Filter_Dropdown_Schedule" element visibility on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page Then "Type_All_Checkbox" element should be checked on "FilterBy_Popup" wizard @@ -1095,7 +1059,7 @@ Feature: Jobs Monitoring Page Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page - Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" + Then verify "Type_Filter_Dropdown_Schedule" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard @@ -1129,8 +1093,8 @@ Feature: Jobs Monitoring Page Then "Title" element on "FilterBy_Popup" should contains "Filter by" value Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" - Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + Then verify "Type_Filter_Dropdown_Schedule" element visibility on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard @@ -1142,7 +1106,7 @@ Feature: Jobs Monitoring Page Then "Type_Databricks_Checkbox" element should be checked on "FilterBy_Popup" wizard Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page - Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" + Then verify "Type_Filter_Dropdown_Schedule" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard @@ -1171,8 +1135,8 @@ Feature: Jobs Monitoring Page Then "Title" element on "FilterBy_Popup" should contains "Filter by" value Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" - Then verify "Type_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" + Then verify "Type_Filter_Dropdown_Schedule" element visibility on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page Then "Type_All_Checkbox" element should be unchecked on "FilterBy_Popup" wizard @@ -1184,7 +1148,7 @@ Feature: Jobs Monitoring Page Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page - Then verify "Type_Filter_Dropdown" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" + Then verify "Type_Filter_Dropdown_Schedule" dropdown element on "FilterBy_Popup" wizard should contains "Dropdown_Options"."Scheduled_Type_Filter_Options" Then verify "Table_Label_Filter_Input" element visibility on "FilterBy_Popup" wizard Then verify "Clear_Button" element visibility on "FilterBy_Popup" wizard Then verify "Apply_Button" element visibility on "FilterBy_Popup" wizard @@ -1272,7 +1236,6 @@ Feature: Jobs Monitoring Page Then verify that 8 row elements are displayed in "Scheduled_Table" on "Jobs_Monitoring_Scheduled_Tab" wizard When pick up "Custom range" from "09/03/2024 00:00" to "09/04/2024 00:00" in "Date_Time_Picker" via "Date_Picker_Filter_Dropdown" on "Jobs_Monitoring_Scheduled_Tab" wizard And wait load page - And wait load page Then verify from "09/03/2024 00:00" to "09/04/2024 00:00" filter band in "Custom_Range_Filter_Dropdown" filter dropdown on "Jobs_Monitoring_Scheduled_Tab" wizard And wait load page @@ -1285,7 +1248,7 @@ Feature: Jobs Monitoring Page And wait load page Then verify redirection to "projects/*/jobs-monitoring/scheduled?type=all&dates=next24hours" Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page Then "Type_All_Checkbox" element should be checked on "FilterBy_Popup" wizard @@ -1297,7 +1260,7 @@ Feature: Jobs Monitoring Page Then "Type_Databricks_Checkbox" element should be unchecked on "FilterBy_Popup" wizard Then click on "Type_Filter_Element" element on "FilterBy_Popup" wizard And wait load page - When select "Job" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + When select "Job" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard And wait load page Then click on "Title" element on "FilterBy_Popup" wizard And wait load page @@ -1322,10 +1285,10 @@ Feature: Jobs Monitoring Page Then click on "Cross_Cancel_Button" element on "View_YAML" wizard And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Job" - When select "Job" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "Job" + When select "Job" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - When select "Workflow" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + When select "Workflow" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page @@ -1348,7 +1311,7 @@ Feature: Jobs Monitoring Page Then click on "Cross_Cancel_Button" element on "View_YAML" wizard And wait load page Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "Workflow" @MLJM @smoke @@ -1361,40 +1324,40 @@ Feature: Jobs Monitoring Page Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard Then verify "Project_Name_Filter_Dropdown" element visibility on "FilterBy_Popup" wizard Then verify "Project_Name_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" - When select "Databricks" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "Databricks" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Databricks" - When select "Dask" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "Databricks" + When select "Dask" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Dask, Databricks" - When select "Horovod" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "Dask, Databricks" + When select "Horovod" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "3 items selected" - When select "Spark" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "3 items selected" + When select "Spark" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "4 items selected" - When select "Workflow" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "4 items selected" + When select "Workflow" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" - When select "Job" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "5 items selected" + When select "Job" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "All" Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page Then verify "Scheduled_Table" element visibility on "Jobs_Monitoring_Scheduled_Tab" wizard Then click on "Table_FilterBy_Button" element on "Jobs_Monitoring_Scheduled_Tab" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "All" - When select "Spark" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "All" + When select "Spark" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - When select "Horovod" option in "Type_Filter_Dropdown" filter dropdown on "FilterBy_Popup" wizard + When select "Horovod" option in "Type_Filter_Dropdown_Schedule" filter dropdown on "FilterBy_Popup" wizard Then click on "Title" element on "FilterBy_Popup" wizard - Then verify "Type_Filter_Dropdown" dropdown on "FilterBy_Popup" wizard selected option value "Spark, Horovod" + Then verify "Type_Filter_Dropdown_Schedule" dropdown on "FilterBy_Popup" wizard selected option value "Spark, Horovod" Then click on "Apply_Button" element on "FilterBy_Popup" wizard And wait load page And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard diff --git a/tests/features/llmPrompts.feature b/tests/features/llmPrompts.feature index f2224ccb03..d257cf7607 100644 --- a/tests/features/llmPrompts.feature +++ b/tests/features/llmPrompts.feature @@ -866,3 +866,163 @@ Feature: LLM prompts Page Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + + @MLLP + @smoke + Scenario: MLLP014 - Verify prompt filtering by model name and tag + Given open url + And wait load page + And click on row root with value "auto-generated-data" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "auto-generated-data" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/auto-generated-data/llm-prompts?bePage=1&fePage=1" + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then verify "Model_Name_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Model_Version_Tag_Filter_Input" element visibility on "FilterBy_Popup" wizard + Then verify "Model_Version_Tag_Filter_Field" element on "FilterBy_Popup" wizard is disabled by class name + Then type value "model_8" to "Model_Name_Filter_Input" field on "FilterBy_Popup" wizard + Then verify "Model_Version_Tag_Filter_Field" element on "FilterBy_Popup" wizard is enabled by class name + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then value in "model_name" column with "text" in "LLMPrompts_Table" on "LLM_Prompts" wizard should contains "model_8" + And wait load page + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then type value "v1" to "Model_Version_Tag_Filter_Input" field on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_2" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then value in "model_tag" column with "text" in "LLMPrompts_Table" on "LLM_Prompts" wizard should contains "v1" + And wait load page + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then type value "" to "Model_Name_Filter_Input" field on "FilterBy_Popup" wizard + Then verify "Model_Version_Tag_Filter_Field" element on "FilterBy_Popup" wizard is disabled by class name + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button" + And wait load page + And select "project" with "llmdeploy332" value in breadcrumbs menu + And wait load page + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then type value "model_art1" to "Model_Name_Filter_Input" field on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + Then verify "Table_FilterBy_Button" element on "LLM_Prompts" wizard should display hover tooltip "Common_Tooltips"."FilterBy_Button_1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + Then value in "model_name" column with "text" in "LLMPrompts_Table" on "LLM_Prompts" wizard should contains "model_art1" + And wait load page + Then click on "Table_FilterBy_Button" element on "LLM_Prompts" wizard + Then type value "model_art1" to "Model_Name_Filter_Input" field on "FilterBy_Popup" wizard + Then type value "v2" to "Model_Version_Tag_Filter_Input" field on "FilterBy_Popup" wizard + Then click on "Apply_Button" element on "FilterBy_Popup" wizard + And wait load page + And verify "No_Data_Message" element visibility on "commonPagesHeader" wizard + Then "No_Data_Message" component on "commonPagesHeader" should be equal "No_Data_Message"."Common_Message_LLM_Prompt_Model_Name_Tag" + + @MLLP + @smoke + Scenario: MLLP015 - Verify model detail popup from the LLM promts table list + Given open url + And wait load page + And click on row root with value "llmdeploy332" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Project monitoring" value + Then verify breadcrumbs "project" label should be equal "llmdeploy332" value + And hover "Project_Navigation_Toggler" component on "commonPagesHeader" wizard + And click on cell with value "LLM prompts" in "link" column in "General_Info_Quick_Links" table on "commonPagesHeader" wizard + And hover "MLRun_Logo" component on "commonPagesHeader" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "LLM prompts" value + Then verify redirection to "projects/llmdeploy332/llm-prompts?bePage=1&fePage=1" + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard + When click on cell with value "model_art1" in "model_name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then verify if "Modal_Transition_Popup" popup dialog appears + Then verify "Title" element visibility on "Modal_Transition_Popup" wizard + Then "Title" element on "Modal_Transition_Popup" should contains "model_art1" value + Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard + Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard + Then verify "Refresh_Button" element on "Modal_Transition_Popup" wizard should display hover tooltip "Common_Tooltips"."Refresh_Button" + Then click on "Refresh_Button" element on "Modal_Transition_Popup" wizard + And wait load page + Then verify "Refresh_Button" element visibility on "Modal_Transition_Popup" wizard + Then verify "Action_Menu" element visibility on "Modal_Transition_Popup" wizard + Then verify "Action_Menu" dropdown element on "Modal_Transition_Popup" wizard should contains "Common_Lists"."Action_Menu_List_Dataset_Transition_Popup" + Then select "View YAML" option in action menu on "Modal_Transition_Popup" wizard + And wait load page + Then verify if "View_YAML" popup dialog appears + Then verify "Cross_Cancel_Button" element visibility on "View_YAML" wizard + Then verify "YAML_Modal_Container" element visibility on "View_YAML" wizard + Then click on "Cross_Cancel_Button" element on "View_YAML" wizard + And wait load page + Then select "Copy URI" option in action menu on "Modal_Transition_Popup" wizard + And wait load page + Then verify if "Notification_Popup" popup dialog appears + Then verify "Notification_Pop_Up" element visibility on "Notification_Popup" wizard + Then "Notification_Pop_Up" element on "Notification_Popup" should contains "Copied to clipboard successfully" value + Then verify "Notification_Pop_Up_Cross_Close_Button" element visibility on "Notification_Popup" wizard + Then click on "Notification_Pop_Up_Cross_Close_Button" element on "Notification_Popup" wizard + Then select "Download" option in action menu on "Modal_Transition_Popup" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then verify "Tab_Selector" element visibility on "Modal_Transition_Popup" wizard + Then verify "Tab_Selector" on "Modal_Transition_Popup" wizard should contains "Models_Info_Pane"."Tab_List_Two_Tabs" + Then verify "Overview" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify "Overview_General_Headers" on "Modal_Transition_Popup" wizard should contains "Models_Info_Pane"."Overview_General_Headers" + Then verify "Overview_Producer_Headers" on "Modal_Transition_Popup" wizard should contains "Models_Info_Pane"."Overview_Producer_Headers_Kind_Project" + And select "Preview" tab in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify "Preview" tab is active in "Tab_Selector" on "Modal_Transition_Popup" wizard + Then verify "Pop_Out_Button" element visibility on "Modal_Transition_Popup" wizard + Then click on "Pop_Out_Button" element on "Modal_Transition_Popup" wizard + And wait load page + Then verify "Preview_Table" element visibility on "Preview_Popup" wizard + Then verify visibility of header column "name" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Name" header value in "name" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "path" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Path" header value in "path" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "size" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Size" header value in "size" column in "Preview_Table" table on "Preview_Popup" wizard + Then verify visibility of header column "updated" in "Preview_Table" table on "Preview_Popup" wizard + Then check "Updated" header value in "updated" column in "Preview_Table" table on "Preview_Popup" wizard + Then value in "name" column with "text" in "Preview_Table" on "Preview_Popup" wizard should contains "model_art1" + Then verify "Cross_Cancel_Button" element visibility on "Preview_Popup" wizard + Then verify "Download_Button" element visibility on "Preview_Popup" wizard + Then click on "Download_Button" element on "Preview_Popup" wizard + And wait load page + And wait load page + Then verify "Download_Pop_Up" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Download_Pop_Up_Cross_Cancel_Button" element visibility on "Downloads_Popup" wizard + And wait load page + Then verify "Header_Download_Pop_Up" element visibility on "Downloads_Popup" wizard + Then "Header_Download_Pop_Up" element on "Downloads_Popup" should contains "Downloads" value + Then click on "Download_Pop_Up_Cross_Cancel_Button" element on "Downloads_Popup" wizard + Then click on "Cross_Cancel_Button" element on "Preview_Popup" wizard + Then verify "Cross_Close_Button" element visibility on "Modal_Transition_Popup" wizard + Then click on "Cross_Close_Button" element on "Modal_Transition_Popup" wizard + And wait load page + When click on cell with value "model_art1" in "model_name" column in "LLMPrompts_Table" table on "LLM_Prompts" wizard + And wait load page + Then verify if "Modal_Transition_Popup" popup dialog appears + Then verify "Title" element visibility on "Modal_Transition_Popup" wizard + Then "Title" element on "Modal_Transition_Popup" should contains "model_art1" value + Then click on "Cross_Close_Button" element on "Modal_Transition_Popup" wizard + And wait load page + Then verify "LLMPrompts_Table" element visibility on "LLM_Prompts" wizard diff --git a/tests/features/projectsPage.feature b/tests/features/projectsPage.feature index 2ef665505c..0f434d3502 100644 --- a/tests/features/projectsPage.feature +++ b/tests/features/projectsPage.feature @@ -358,8 +358,10 @@ Feature: Projects Page Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Container_Title" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then "Monitoring_Container_Title" element in "Projects_Monitoring_Container" on "Projects" should contains "Monitoring" value + Then verify "Monitoring_Artifacts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Jobs_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Workflows_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Models_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Scheduled_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Alerts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard @@ -369,8 +371,10 @@ Feature: Projects Page Then navigate back And wait load page Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Artifacts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Jobs_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Workflows_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Models_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Scheduled_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Alerts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard @@ -379,11 +383,42 @@ Feature: Projects Page Then click on breadcrumbs "projectsPage" label on "commonPagesHeader" wizard And wait load page Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Artifacts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Jobs_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Workflows_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Models_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Scheduled_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Alerts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + @MLPr + @smoke + Scenario: MLPr022 - Check the components in the Artifacts and Models counter boxes + Given open url + And wait load page + Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Container_Title" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then "Monitoring_Container_Title" element in "Projects_Monitoring_Container" on "Projects" should contains "Monitoring" value + Then verify "Monitoring_Artifacts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Artifacts_Box_Title" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Monitoring_Artifacts_Box_Title" element in "Monitoring_Artifacts_Box" on "Projects" should contains "Artifacts" value + Then verify "Total_Counter_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then verify "Counter_Datasets_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then verify "Counter_Datasets_Subtitle" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Counter_Datasets_Subtitle" element in "Monitoring_Artifacts_Box" on "Projects" should contains "Datasets" value + Then verify "Counter_Documents_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then verify "Counter_Documents_Subtitle" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Counter_Documents_Subtitle" element in "Monitoring_Artifacts_Box" on "Projects" should contains "Documents" value + Then verify "Counter_LLM_Prompt_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then verify "Counter_LLM_Prompt_Subtitle" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Counter_LLM_Prompt_Subtitle" element in "Monitoring_Artifacts_Box" on "Projects" should contains "LLM prompt artifacts" value + Then verify "Counter_Other_Artifacts_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then verify "Counter_Other_Artifacts_Subtitle" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Counter_Other_Artifacts_Subtitle" element in "Monitoring_Artifacts_Box" on "Projects" should contains "Other artifacts" value + Then verify "Monitoring_Models_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Models_Title" element visibility in "Monitoring_Models_Box" on "Projects" wizard + Then "Monitoring_Models_Title" element in "Monitoring_Models_Box" on "Projects" should contains "Models" value + Then verify "Total_Counter_Number" element visibility in "Monitoring_Models_Box" on "Projects" wizard + @MLPr @smoke Scenario: MLPr016 - Check components on Jobs counter box @@ -612,6 +647,16 @@ Feature: Projects Page Then verify "Monitoring_Container" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Container_Title" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then "Monitoring_Container_Title" element in "Projects_Monitoring_Container" on "Projects" should contains "Monitoring" value + Then verify "Monitoring_Artifacts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then "Total_Counter_Number" element in "Monitoring_Artifacts_Box" on "Projects" should contains "13,145" value + Then verify "Counter_Datasets_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Counter_Datasets_Number" element in "Monitoring_Artifacts_Box" on "Projects" should contains "34" value + Then verify "Counter_Documents_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Counter_Documents_Number" element in "Monitoring_Artifacts_Box" on "Projects" should contains "23" value + Then verify "Counter_LLM_Prompt_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Counter_LLM_Prompt_Number" element in "Monitoring_Artifacts_Box" on "Projects" should contains "58" value + Then verify "Counter_Other_Artifacts_Number" element visibility in "Monitoring_Artifacts_Box" on "Projects" wizard + Then "Counter_Other_Artifacts_Number" element in "Monitoring_Artifacts_Box" on "Projects" should contains "13,030" value Then verify "Monitoring_Jobs_Box_Title" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard Then "Monitoring_Jobs_Box_Title" element in "Monitoring_Jobs_Box" on "Projects" should contains "Runs" value Then verify "Total_Counter_Number" element visibility in "Monitoring_Jobs_Box" on "Projects" wizard @@ -639,6 +684,9 @@ Feature: Projects Page Then "Total_Workflows_Counter_Number" element in "Monitoring_Scheduled_Box" on "Projects" should contains "1" value Then verify "Total_Scheduled_Number" element visibility in "Monitoring_Scheduled_Box" on "Projects" wizard Then "Total_Scheduled_Number" element in "Monitoring_Scheduled_Box" on "Projects" should contains "8" value + Then verify "Monitoring_Models_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard + Then verify "Monitoring_Models_Title" element visibility in "Monitoring_Models_Box" on "Projects" wizard + Then "Total_Counter_Number" element in "Monitoring_Models_Box" on "Projects" should contains "13,019" value Then verify "Monitoring_Alerts_Box" element visibility in "Projects_Monitoring_Container" on "Projects" wizard Then verify "Monitoring_Alerts_Box_Title" element visibility in "Monitoring_Alerts_Box" on "Projects" wizard Then "Monitoring_Alerts_Box_Title" element in "Monitoring_Alerts_Box" on "Projects" should contains "Alerts" value diff --git a/tests/features/step-definitions/steps.js b/tests/features/step-definitions/steps.js index 54b9ec9d90..8acef5ff23 100644 --- a/tests/features/step-definitions/steps.js +++ b/tests/features/step-definitions/steps.js @@ -50,6 +50,7 @@ import { generatePath, determineFileAccess, verifyClassDisabled, + verifyClassEnabled, checkComponentHintTextWithHover, putToTestContextElementValue } from '../common/actions/common.action' @@ -422,6 +423,16 @@ Then( } ) +Then( + 'verify {string} element on {string} wizard is enabled by class name', + async function(inputField, wizardName) { + await verifyClassEnabled( + this.driver, + pageObjects[wizardName][inputField] + ) + } +) + When( 'type searchable fragment {string} into {string} on {string} wizard', async function(subName, inputGroup, wizard) { diff --git a/tests/mockServer/data/alerts.json b/tests/mockServer/data/alerts.json index 370caa6124..463e99522f 100644 --- a/tests/mockServer/data/alerts.json +++ b/tests/mockServer/data/alerts.json @@ -317,7 +317,7 @@ "name": "alert-name-uqbxb-proj-default", "project": "default", "severity": "high", - "activation_time": "2025-09-22T15:50:55.190000+00:00", + "activation_time": "2025-10-22T15:50:55.190000+00:00", "entity_id": "a7c95783e6a726a1a233e581ea898ba33fa7e342.rujmfi.result.data_drift_test", "entity_kind": "model-endpoint-result", "criteria": { @@ -343,7 +343,7 @@ "name": "alert-name-jukmn-proj-default", "project": "default", "severity": "high", - "activation_time": "2025-09-22T15:50:54.207000+00:00", + "activation_time": "2025-10-22T15:50:54.207000+00:00", "entity_id": "a7c95783e6a726a1a233e581ea898ba33fa7e342.hskoyl.result.data_drift_test", "entity_kind": "model-endpoint-result", "criteria": { @@ -369,7 +369,7 @@ "name": "alert-name-uqbxb-proj-default", "project": "default", "severity": "high", - "activation_time": "2025-09-22T15:48:57.907000+00:00", + "activation_time": "2025-10-22T15:48:57.907000+00:00", "entity_id": "a7c95783e6a726a1a233e581ea898ba33fa7e342.rujmfi.result.data_drift_test", "entity_kind": "model-endpoint-result", "criteria": { @@ -395,7 +395,7 @@ "name": "alert-name-jukmn-proj-default", "project": "default", "severity": "high", - "activation_time": "2025-09-22T15:48:56.440000+00:00", + "activation_time": "2025-10-22T15:48:56.440000+00:00", "entity_id": "a7c95783e6a726a1a233e581ea898ba33fa7e342.hskoyl.result.data_drift_test", "entity_kind": "model-endpoint-result", "criteria": { diff --git a/tests/mockServer/data/artifacts.json b/tests/mockServer/data/artifacts.json index 6bef55ceb3..771fe51a2b 100644 --- a/tests/mockServer/data/artifacts.json +++ b/tests/mockServer/data/artifacts.json @@ -40202,10 +40202,11 @@ "tag": "latest" }, "spec": { - "target_path": "llmdeploy332/model_art1/", + "target_path": "v3io:///projects/llmdeploy332/artifacts/model_art1/0/model/", "size": 4370, "license": "", - "framework": "", + "framework": "sklearn", + "algorithm": "RandomForestClassifier", "producer": { "kind": "project", "name": "llmdeploy332", @@ -40241,7 +40242,7 @@ "tag": "v1" }, "spec": { - "target_path": "llmdeploy332/model_art1/", + "target_path": "v3io:///projects/llmdeploy332/artifacts/model_art1/0/model/", "size": 4370, "license": "", "framework": "", @@ -40327,7 +40328,7 @@ "tag": "latest" }, "spec": { - "target_path": "llmdeploy335/model_art1/", + "target_path": "v3io:///projects/llmdeploy332/artifacts/model_art1/0/model/", "size": 4370, "framework": "", "has_children": true, diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index 8be1a9b777..ab2f83bdd5 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -1531,13 +1531,13 @@ function getArtifacts(req, res) { /^store:\/\/(?.+?)\/(?.+?)\/(?.+?)(#(?.+?))?(:(?.+?))?(@(?[^^]+))?(\^(?.+))?$/ ) - return match && match.groups.key.startsWith(key) && match.groups.tag === tag + return match && match.groups.key.includes(key) && match.groups.tag.includes(tag) }) } else { collectedArtifacts = collectedArtifacts.filter(artifact => artifact.spec?.parent_uri ?.match(/^store:\/\/[^/]+\/[^/]+\/([^#/]+)/)?.[1] - ?.startsWith(req.query['parent']) + ?.includes(req.query['parent']) ) } } From d75b685ca089b5c60ae5951271f20f2ffbe39f48 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:53:14 +0200 Subject: [PATCH 207/228] Fix [UI] Block mounting invalid secret names when running functions (#3488) --- .../EditableVolumesRow/EditableVolumesRow.jsx | 17 +++++++- .../AddEnvironmentVariablesRow.jsx | 8 ++++ .../EditableEnvironmentVariablesRow.jsx | 9 ++++ .../EnvironmentVariablesView.jsx | 1 + .../FormEnvironmentVariablesRow.jsx | 8 +++- .../FormVolumesRow/FormVolumesRow.jsx | 6 ++- .../FormVolumesTable/formVolumesTable.util.js | 10 ++++- src/elements/VolumesTable/VolumesTable.jsx | 1 + .../VolumesTable/VolumesTableView.jsx | 23 ++++++++-- src/utils/getSecretNameValidator.js | 42 +++++++++++++++++++ 10 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 src/utils/getSecretNameValidator.js diff --git a/src/elements/EditableVolumesRow/EditableVolumesRow.jsx b/src/elements/EditableVolumesRow/EditableVolumesRow.jsx index 2cfec90af4..7efe59889f 100644 --- a/src/elements/EditableVolumesRow/EditableVolumesRow.jsx +++ b/src/elements/EditableVolumesRow/EditableVolumesRow.jsx @@ -20,6 +20,7 @@ such restriction. import React, { useMemo, useState } from 'react' import PropTypes from 'prop-types' import { forEach } from 'lodash' +import { useParams } from 'react-router-dom' import Input from '../../common/Input/Input' import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' @@ -30,12 +31,15 @@ import { isPathNotUnique, V3IO } from '../VolumesTable/volumesTable.util' +import { SECRET_VOLUME_TYPE } from '../../constants' +import { getValidationRules } from 'igz-controls/utils/validation.util' +import { getSecretNameValidator } from '../../utils/getSecretNameValidator' import Checkmark from 'igz-controls/images/checkmark.svg?react' import './editableVolumesRow.scss' -const EditableVolumesRow = ({ content, handleEdit, selectedVolume, setSelectedVolume }) => { +const EditableVolumesRow = ({ content, handleEdit, selectedVolume, setSelectedVolume, volume }) => { const [validation, setValidation] = useState({ isNameValid: true, isTypeValid: true, @@ -43,6 +47,7 @@ const EditableVolumesRow = ({ content, handleEdit, selectedVolume, setSelectedVo isPathValid: true, isAccessKeyValid: true }) + const { projectName } = useParams() const volumeTypeInput = useMemo( () => getVolumeTypeInput(selectedVolume.type.value), [selectedVolume.type.value] @@ -140,6 +145,13 @@ const EditableVolumesRow = ({ content, handleEdit, selectedVolume, setSelectedVo required={selectedVolume.type.value !== V3IO} requiredText="This field is invalid" setInvalid={value => setValidation(state => ({ ...state, isTypeNameValid: value }))} + validationRules={ + selectedVolume?.type?.value?.toLowerCase() === SECRET_VOLUME_TYPE + ? getValidationRules('environmentVariables.secretName', [ + getSecretNameValidator(projectName, volume?.secret?.secretName) + ]) + : [] + } type="text" value={selectedVolume.type.name} /> @@ -213,7 +225,8 @@ EditableVolumesRow.propTypes = { content: PropTypes.array.isRequired, handleEdit: PropTypes.func.isRequired, selectedVolume: PropTypes.object.isRequired, - setSelectedVolume: PropTypes.func.isRequired + setSelectedVolume: PropTypes.func.isRequired, + volume: PropTypes.object.isRequired } export default EditableVolumesRow diff --git a/src/elements/EnvironmentVariables/AddEnvironmentVariablesRow.jsx b/src/elements/EnvironmentVariables/AddEnvironmentVariablesRow.jsx index 2c1dc1be9e..4724f07bb1 100644 --- a/src/elements/EnvironmentVariables/AddEnvironmentVariablesRow.jsx +++ b/src/elements/EnvironmentVariables/AddEnvironmentVariablesRow.jsx @@ -19,6 +19,7 @@ such restriction. */ import React from 'react' import PropTypes from 'prop-types' +import { useParams } from 'react-router-dom' import Input from '../../common/Input/Input' import Select from '../../common/Select/Select' @@ -31,6 +32,8 @@ import { selectTypeOptions } from './environmentVariables.util' import { ENV_VARIABLE_TYPE_SECRET } from '../../constants' +import { getValidationRules } from 'igz-controls/utils/validation.util' +import { getSecretNameValidator } from '../../utils/getSecretNameValidator' import Delete from 'igz-controls/images/delete.svg?react' import Plus from 'igz-controls/images/plus.svg?react' @@ -44,6 +47,8 @@ const AddEnvironmentVariablesRow = ({ setValidation, validation }) => { + const { projectName } = useParams() + return (
      @@ -96,6 +101,9 @@ const AddEnvironmentVariablesRow = ({ label="Secret Name" onChange={secretName => setNewEnvVariable(state => ({ ...state, secretName }))} pattern="^(?=[\S\s]{1,253}$)[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?)*$" + validationRules={getValidationRules('environmentVariables.secretName', [ + getSecretNameValidator(projectName) + ])} required setInvalid={value => setValidation(state => ({ diff --git a/src/elements/EnvironmentVariables/EditableEnvironmentVariablesRow.jsx b/src/elements/EnvironmentVariables/EditableEnvironmentVariablesRow.jsx index 5ac600ca7f..efbb7a075a 100644 --- a/src/elements/EnvironmentVariables/EditableEnvironmentVariablesRow.jsx +++ b/src/elements/EnvironmentVariables/EditableEnvironmentVariablesRow.jsx @@ -19,6 +19,7 @@ such restriction. */ import React, { useEffect, useState } from 'react' import PropTypes from 'prop-types' +import { useParams } from 'react-router-dom' import Input from '../../common/Input/Input' import Select from '../../common/Select/Select' @@ -31,12 +32,15 @@ import { selectTypeOptions } from './environmentVariables.util' import { ENV_VARIABLE_TYPE_SECRET, ENV_VARIABLE_TYPE_VALUE } from '../../constants' +import { getValidationRules } from 'igz-controls/utils/validation.util' +import { getSecretNameValidator } from '../../utils/getSecretNameValidator' import Checkmark from 'igz-controls/images/checkmark.svg?react' const EditableEnvironmentVariablesRow = ({ editEnvVariable, envVariables, + envVariable, selectedEnvVariable, setSelectedEnvVariable }) => { @@ -48,6 +52,7 @@ const EditableEnvironmentVariablesRow = ({ isSecretNameValid: true, isSecretKeyValid: true }) + const { projectName } = useParams() useEffect(() => { if (selectedEnvVariable.type === ENV_VARIABLE_TYPE_SECRET) { @@ -117,6 +122,9 @@ const EditableEnvironmentVariablesRow = ({ label="Secret Name" onChange={secretName => setSelectedEnvVariable(state => ({ ...state, secretName }))} pattern="^(?=[\S\s]{1,253}$)[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?)*$" + validationRules={getValidationRules('environmentVariables.secretName', [ + getSecretNameValidator(projectName, envVariable?.value?.split?.(':')?.[0]) + ])} required setInvalid={value => setValidation(state => ({ ...state, isSecretNameValid: value }))} tip={secretNameValidationTip} @@ -162,6 +170,7 @@ const EditableEnvironmentVariablesRow = ({ EditableEnvironmentVariablesRow.propTypes = { editEnvVariable: PropTypes.func.isRequired, envVariables: PropTypes.array.isRequired, + envVariable: PropTypes.object.isRequired, selectedEnvVariable: PropTypes.object.isRequired, setSelectedEnvVariable: PropTypes.func.isRequired } diff --git a/src/elements/EnvironmentVariables/EnvironmentVariablesView.jsx b/src/elements/EnvironmentVariables/EnvironmentVariablesView.jsx index aae6798674..ca1a4c0624 100644 --- a/src/elements/EnvironmentVariables/EnvironmentVariablesView.jsx +++ b/src/elements/EnvironmentVariables/EnvironmentVariablesView.jsx @@ -79,6 +79,7 @@ const EnvironmentVariablesView = ({ { const [fieldData, setFieldData] = useState(fields.value[index]) + const { projectName } = useParams() const tableRowClassNames = classnames( 'form-table__row', @@ -130,7 +133,10 @@ const FormEnvironmentVariablesRow = ({ name={`${rowPath}.data.secretName`} placeholder="Secret Name" required - validationRules={getValidationRules('environmentVariables.secretName')} + validationRules={ + (getValidationRules('environmentVariables.secretName'), + [getSecretNameValidator(projectName, editingItem?.data?.typeName) ]) + } /> { @@ -69,10 +71,10 @@ const FormVolumesRow = ({ useLayoutEffect(() => { setFieldRowData( - generateVolumeInputsData(fields.value[index], fields, editingItem, accessKeyFocusHandler) + generateVolumeInputsData(fields.value[index], fields, editingItem, accessKeyFocusHandler, projectName) ) setFieldData(fields.value[index]) - }, [accessKeyFocusHandler, editingItem, fields, index]) + }, [accessKeyFocusHandler, editingItem, fields, index, projectName]) const handleTypeChange = useCallback(() => { if (isCurrentRowEditing(rowPath)) { diff --git a/src/elements/FormVolumesTable/formVolumesTable.util.js b/src/elements/FormVolumesTable/formVolumesTable.util.js index e28f836fd3..8961396ea7 100644 --- a/src/elements/FormVolumesTable/formVolumesTable.util.js +++ b/src/elements/FormVolumesTable/formVolumesTable.util.js @@ -20,6 +20,7 @@ such restriction. import { isNil, map } from 'lodash' import { getValidationRules } from 'igz-controls/utils/validation.util' import { isCommunityEdition } from '../../utils/helper' +import { getSecretNameValidator } from '../../utils/getSecretNameValidator' import { V3IO_VOLUME_TYPE, @@ -52,7 +53,8 @@ export const generateVolumeInputsData = ( selectedItem, fields, editingItem, - accessKeyFocusHandler + accessKeyFocusHandler, + projectName ) => { const editingItemIndex = editingItem?.ui?.index const selectedType = selectedItem.data.type @@ -170,7 +172,11 @@ export const generateVolumeInputsData = ( textHidden: true, type: 'input', validationRules: - selectedType === SECRET_VOLUME_TYPE ? getValidationRules('project.secrets.key') : [] + selectedType === SECRET_VOLUME_TYPE + ? getValidationRules('environmentVariables.secretName', [ + getSecretNameValidator(projectName, editingItem?.data?.typeName) + ]) + : [] } default: return null diff --git a/src/elements/VolumesTable/VolumesTable.jsx b/src/elements/VolumesTable/VolumesTable.jsx index 6ffc4ce357..24176a8547 100644 --- a/src/elements/VolumesTable/VolumesTable.jsx +++ b/src/elements/VolumesTable/VolumesTable.jsx @@ -262,6 +262,7 @@ export const VolumesTable = ({ setValidation={setValidation} showAddNewVolumeRow={showAddNewVolumeRow} validation={validation} + volumes={volumes} /> ) } diff --git a/src/elements/VolumesTable/VolumesTableView.jsx b/src/elements/VolumesTable/VolumesTableView.jsx index de5fe997a5..c79fb09145 100644 --- a/src/elements/VolumesTable/VolumesTableView.jsx +++ b/src/elements/VolumesTable/VolumesTableView.jsx @@ -21,6 +21,7 @@ import React, { useMemo } from 'react' import { find, has, map } from 'lodash' import classnames from 'classnames' import PropTypes from 'prop-types' +import { useParams } from 'react-router-dom' import EditableVolumesRow from '../EditableVolumesRow/EditableVolumesRow' import Input from '../../common/Input/Input' @@ -36,6 +37,9 @@ import { V3IO } from './volumesTable.util' import { joinDataOfArrayOrObject } from 'igz-controls/utils/string.util' +import { SECRET_VOLUME_TYPE } from '../../constants' +import { getValidationRules } from 'igz-controls/utils/validation.util' +import { getSecretNameValidator } from '../../utils/getSecretNameValidator' import Plus from 'igz-controls/images/plus.svg?react' import Delete from 'igz-controls/images/delete.svg?react' @@ -57,7 +61,8 @@ const VolumesTableView = ({ setShowAddNewVolumeRow, setValidation, showAddNewVolumeRow, - validation + validation, + volumes }) => { const volumeTypeInput = useMemo(() => getVolumeTypeInput(newVolume.type), [newVolume.type]) const tableClassNames = classnames( @@ -70,6 +75,7 @@ const VolumesTableView = ({ 'input-row-wrapper', newVolume.type === V3IO && 'no-border' ) + const { projectName } = useParams() const addVolumeButtonClassNames = classnames(isPanelEditMode && 'disabled', 'add-input') @@ -96,6 +102,7 @@ const VolumesTableView = ({ key={index} selectedVolume={selectedVolume} setSelectedVolume={setSelectedVolume} + volume={volumes?.[index]} /> ) } else { @@ -140,7 +147,8 @@ const VolumesTableView = ({ onClick={type => { setNewVolume(state => ({ ...state, - type: find(selectTypeOptions.volumeType, ['id', type]).id + type: find(selectTypeOptions.volumeType, ['id', type]).id, + typeName: '' })) setValidation(state => ({ ...state, @@ -187,6 +195,7 @@ const VolumesTableView = ({
      setValidation(state => ({ ...state, isTypeNameValid: value }))} tip={volumeTypeInput.tip} type="text" + validationRules={ + newVolume.type?.toLowerCase() === SECRET_VOLUME_TYPE + ? getValidationRules('environmentVariables.secretName', [ + getSecretNameValidator(projectName) + ]) + : [] + } /> {newVolume.type === V3IO && ( { + return { + name: 'secretProhibitedNames', + label: 'Secret does not reference an MLRun secret defined in another project', + pattern: secretName => { + // if prohibited secret was set before (we get it from BE) we accept it as valid + if (secretName && secretName === initialSecretName) return true + + if (secretName.startsWith('mlrun-auth-secrets.')) return false + + const correctPatternBeginning = 'mlrun-project-secrets-' // mlrun-project-secrets-{project-name} + + if (secretName.startsWith(correctPatternBeginning)) { + const secretProjectName = secretName.slice(correctPatternBeginning.length) + + return secretProjectName === projectName + } + + return true + } + } +} + From 4154bf1fc0605a3167bc112d5625d8773847c1a0 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:56:33 +0200 Subject: [PATCH 208/228] Fix [Monitoring app] Date picker selection not preserved between pages (#3487) --- package.json | 2 +- .../MonitoringApplications/MonitoringApplications.jsx | 6 +++++- .../MonitoringApplicationsPage.jsx | 3 ++- src/utils/createApplicationContent.jsx | 7 ++++++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index baa2a750cd..e03b666a93 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "3.2.0", + "iguazio.dashboard-react-controls": "3.2.2", "is-wsl": "^1.1.0", "js-base64": "^2.6.4", "js-yaml": "^4.1.0", diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx index a53bfbbe02..c475bfe699 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications.jsx @@ -36,6 +36,7 @@ import { removeMonitoringApplications, removeMEPWithDetections } from '../../../reducers/monitoringApplicationsReducer' +import { saveAndTransformSearchParams } from 'igz-controls/utils/filter.util' import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' @@ -59,7 +60,10 @@ const MonitoringApplications = () => { icon: , onClick: data => navigate( - `/projects/${params.projectName}/${MONITORING_APP_PAGE}/${data.name}/${MODEL_ENDPOINTS_TAB}${window.location.search}` + `/projects/${params.projectName}/${MONITORING_APP_PAGE}/${data.name}/${MODEL_ENDPOINTS_TAB}${saveAndTransformSearchParams( + window.location.search, + true + )}` ) } ] diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index 7077180c27..f1eecdc3cd 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -38,6 +38,7 @@ import { fetchArtifacts } from '../../reducers/artifactsReducer' import { getFiltersConfig } from './MonitoringApplicationsPage.util' import { showErrorNotification } from 'igz-controls/utils/notification.util' import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' +import { getSavedSearchParams } from 'igz-controls/utils/filter.util' import PresentMetricsIcon from 'igz-controls/images/present-metrics-icon.svg?react' @@ -147,7 +148,7 @@ const MonitoringApplicationsPage = () => { {params.name && ( )} diff --git a/src/utils/createApplicationContent.jsx b/src/utils/createApplicationContent.jsx index 290df160ca..1291299b7b 100644 --- a/src/utils/createApplicationContent.jsx +++ b/src/utils/createApplicationContent.jsx @@ -21,6 +21,8 @@ import { capitalize } from 'lodash' import { formatDatetime } from 'igz-controls/utils/datetime.util' import { generateNuclioLink } from './parseUri' +import { saveAndTransformSearchParams } from 'igz-controls/utils/filter.util' +import { MONITORING_APP_PAGE } from '../constants' export const createApplicationContent = (application, projectName) => { const identifierUnique = 'identifierUnique.' + application.name + application.application_class @@ -45,7 +47,10 @@ export const createApplicationContent = (application, projectName) => { headerLabel: 'Name', value: application.name, className: 'table-cell-name', - getLink: () => application.name + getLink: () => `/projects/${projectName}/${MONITORING_APP_PAGE}/${application.name}${saveAndTransformSearchParams( + window.location.search, + true + )}` }, { id: `lag.${identifierUnique}`, From 0f3eec32be22e8b83bcd4cf679733464d7c3aad4 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:11:50 +0200 Subject: [PATCH 209/228] Impl [UI] align with MM REST API changes (#3425) --- src/api/modelEndpoints-api.js | 2 +- tests/mockServer/mock.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/modelEndpoints-api.js b/src/api/modelEndpoints-api.js index d28f4c92e6..34ca0b436a 100644 --- a/src/api/modelEndpoints-api.js +++ b/src/api/modelEndpoints-api.js @@ -23,7 +23,7 @@ import { BATCH_FILTER, FILTER_ALL_ITEMS, ME_MODE_FILTER, REAL_TIME_FILTER } from const modelEndpointsApi = { getModelEndpoint: (project, name, uid) => mainHttpClient.get( - `/projects/${project}/model-endpoints/${name}?endpoint_id=${uid}&feature_analysis=true` + `/projects/${project}/model-endpoints/${name}?endpoint-id=${uid}&feature-analysis=true` ), getModelEndpoints: (project, filters, config = {}, params = {}) => { const modesMap = { diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index ab2f83bdd5..c052302d8d 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -2380,7 +2380,7 @@ function putTags(req, res) { ) }) - // handle existing artifacts with same name and tag + // handle existing artifacts with same name and tag collectedArtifactsWithSameName.forEach(artifact => { if (artifact.metadata?.tag === tagName) { if ( @@ -2659,9 +2659,9 @@ function getModelEndpoints(req, res) { ) } - if (req.query['endpoint_id']) { + if (req.query['endpoint-id']) { const modelEndpoint = collectedEndpoints.find( - endpoint => endpoint.metadata.uid === req.query.endpoint_id + endpoint => endpoint.metadata.uid === req.query.endpoint-id ) return res.send(modelEndpoint) From 5439c13cc8d304e88c962b7c665befab4fd6cbdb Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:16:07 +0200 Subject: [PATCH 210/228] Cleanup [UI] Move all states to the constants (#3435) --- src/api/workflow-api.js | 6 ++- src/components/Alerts/alerts.util.js | 3 +- .../ArtifactsPreview/ArtifactsPreviewView.jsx | 4 +- .../Details/DetailsHeader/DetailsHeader.jsx | 19 +++++++-- src/components/Details/details.util.js | 3 +- src/components/DetailsPods/DetailsPods.jsx | 5 ++- .../FilterMenu/filterMenu.settings.js | 35 +++++++++------- .../FunctionsPage/functions.util.jsx | 4 +- .../FunctionsPageOld/functionsOld.util.jsx | 4 +- .../monitorWorkflows.util.jsx | 6 ++- src/components/Jobs/jobs.util.js | 26 +++++++++--- .../monitoringApplicationCounters.util.jsx | 12 +++--- .../ProjectSettings/ProjectSettings.jsx | 7 +++- .../ProjectSettings/projectSettings.util.jsx | 2 - src/constants.js | 9 ++++- .../featureValidatior.utils.js | 2 +- src/elements/JobsTable/JobsTable.jsx | 5 ++- src/elements/ProjectCard/projectCard.util.js | 9 +++-- .../ProjectFunctions/ProjectFunctions.jsx | 27 ++++++++----- src/elements/ProjectJobs/projectJobs.utils.js | 24 ++++++----- .../ProjectStatistics/ProjectStatistics.jsx | 26 +++++++++--- .../WorkflowsTable/WorkflowsTable.jsx | 5 ++- src/hooks/useJobsPageData.js | 19 ++++----- src/utils/createAlertsContent.jsx | 8 ++-- src/utils/createArtifactPreviewContent.js | 4 +- src/utils/createJobsContent.js | 11 ++--- src/utils/generateMonitoringData.js | 40 ++++++++++++------- src/utils/generatePods.jsx | 6 ++- src/utils/getArtifactPreview.jsx | 12 ++++-- src/utils/poll.util.js | 8 ++-- 30 files changed, 230 insertions(+), 121 deletions(-) diff --git a/src/api/workflow-api.js b/src/api/workflow-api.js index 846a67971a..09b412947d 100644 --- a/src/api/workflow-api.js +++ b/src/api/workflow-api.js @@ -20,7 +20,7 @@ such restriction. import { capitalize, set } from 'lodash' import { mainHttpClient } from '../httpClient' -import { GROUP_BY_WORKFLOW, FILTER_ALL_ITEMS } from '../constants' +import { GROUP_BY_WORKFLOW, FILTER_ALL_ITEMS, COMPLETED_STATE } from '../constants' const generateQueryParams = (project, filter) => { // Generating encoded JSON query string to send as a value to the filter query param @@ -56,7 +56,9 @@ const generateQueryParams = (project, filter) => { key: 'status', op: 8, string_values: { - values: stateFilter.map(state => (state === 'completed' ? 'Succeeded' : capitalize(state))) + values: stateFilter.map(state => + state === COMPLETED_STATE ? 'Succeeded' : capitalize(state) + ) } }) } diff --git a/src/components/Alerts/alerts.util.js b/src/components/Alerts/alerts.util.js index 9c99aee72c..9eb008079e 100644 --- a/src/components/Alerts/alerts.util.js +++ b/src/components/Alerts/alerts.util.js @@ -31,6 +31,7 @@ import { ENTITY_ID, ENTITY_TYPE, EVENT_TYPE, + FAILED_STATE, FE_PAGE, FILTER_ALL_ITEMS, JOB, @@ -141,7 +142,7 @@ export const filterAlertsSeverityOptions = [ const alertsEventTypeOptions = [ { label: upperFirst(FILTER_ALL_ITEMS), id: FILTER_ALL_ITEMS }, - { label: 'Job failed', id: 'failed', ENTITY_TYPE: JOB_KIND_JOB }, + { label: 'Job failed', id: FAILED_STATE, ENTITY_TYPE: JOB_KIND_JOB }, { label: 'Data drift detected', id: 'data-drift-detected', ENTITY_TYPE: MODEL_ENDPOINT_RESULT }, { label: 'Data drift suspected', id: 'data-drift-suspected', ENTITY_TYPE: MODEL_ENDPOINT_RESULT }, { diff --git a/src/components/ArtifactsPreview/ArtifactsPreviewView.jsx b/src/components/ArtifactsPreview/ArtifactsPreviewView.jsx index 3b9b2fcb4a..85a61ba9ec 100644 --- a/src/components/ArtifactsPreview/ArtifactsPreviewView.jsx +++ b/src/components/ArtifactsPreview/ArtifactsPreviewView.jsx @@ -26,7 +26,7 @@ import PreviewError from './PreviewError/PreviewError' import { Tooltip, TextTooltipTemplate } from 'igz-controls/components' import WarningMessage from '../../common/WarningMessage/WarningMessage' -import { ARTIFACT_PREVIEW_TABLE_ROW_LIMIT, ERROR_STATE } from '../../constants' +import { ARTIFACT_PREVIEW_TABLE_ROW_LIMIT, ERROR_STATE, UNKNOWN_STATE } from '../../constants' import './artifactsPreview.scss' @@ -145,7 +145,7 @@ const ArtifactsPreviewView = ({ className, preview, setShowErrorBody, showErrorB alt="preview" /> )} - {preview?.type === 'unknown' && ( + {preview?.type === UNKNOWN_STATE && (

      {preview?.data?.content ? preview?.data.content : 'No preview'}

      diff --git a/src/components/Details/DetailsHeader/DetailsHeader.jsx b/src/components/Details/DetailsHeader/DetailsHeader.jsx index c0d452b33e..e65244c818 100644 --- a/src/components/Details/DetailsHeader/DetailsHeader.jsx +++ b/src/components/Details/DetailsHeader/DetailsHeader.jsx @@ -27,7 +27,12 @@ import Select from '../../../common/Select/Select' import { Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' import { ACTIONS_MENU } from 'igz-controls/types' -import { DETAILS_ARTIFACTS_TAB, DETAILS_LOGS_TAB, JOBS_PAGE } from '../../../constants' +import { + ABORTED_STATE, + DETAILS_ARTIFACTS_TAB, + DETAILS_LOGS_TAB, + JOBS_PAGE +} from '../../../constants' import { formatDatetime } from 'igz-controls/utils/datetime.util' import { generateUrlFromRouterPath } from 'igz-controls/utils/common.util' import { getDefaultCloseDetailsLink } from '../../../utils/link-helper.util' @@ -149,7 +154,7 @@ const DetailsHeader = ({ !selectedItem?.updated ? formatDatetime( selectedItem?.startTime, - state.value === 'aborted' ? 'N/A' : 'Not yet started' + state.value === ABORTED_STATE ? 'N/A' : 'Not yet started' ) : selectedItem?.updated ? formatDatetime(selectedItem?.updated, 'N/A') @@ -260,7 +265,15 @@ const DetailsHeader = ({ default: return null } - }, [params.tab, detailsStore.iteration, detailsStore.iterationOptions, detailsStore.runAttempt, detailsStore.runAttemptOptions, isDetailsPopUp, dispatch]) + }, [ + params.tab, + detailsStore.iteration, + detailsStore.iterationOptions, + detailsStore.runAttempt, + detailsStore.runAttemptOptions, + isDetailsPopUp, + dispatch + ]) return ( { startTime: { value: formatDatetime( selectedItem.startTime, - selectedItem.state?.value === 'aborted' ? 'N/A' : 'Not yet started' + selectedItem.state?.value === ABORTED_STATE ? 'N/A' : 'Not yet started' ) }, updated: { diff --git a/src/components/DetailsPods/DetailsPods.jsx b/src/components/DetailsPods/DetailsPods.jsx index b947d8b8bd..ae07539d5a 100644 --- a/src/components/DetailsPods/DetailsPods.jsx +++ b/src/components/DetailsPods/DetailsPods.jsx @@ -30,8 +30,9 @@ import { Tooltip, TextTooltipTemplate, Loader } from 'igz-controls/components' import { generatePods } from './detailsPods.util' import './detailsPods.scss' +import { PENDING_STATE } from '../../constants' -const DetailsPods = ({ isDetailsPopUp = false, noDataMessage = ''}) => { +const DetailsPods = ({ isDetailsPopUp = false, noDataMessage = '' }) => { const [selectedPod, setSelectedPod] = useState(null) const [table, setTable] = useState([]) const params = useParams() @@ -71,7 +72,7 @@ const DetailsPods = ({ isDetailsPopUp = false, noDataMessage = ''}) => { selectedPod?.value === row.value && 'row_active' ) const podStatus = - row.status?.phase?.toLowerCase() === 'pending' + row.status?.phase?.toLowerCase() === PENDING_STATE ? 'pending...' : (row.status?.phase?.toLowerCase() ?? '') diff --git a/src/components/FilterMenu/filterMenu.settings.js b/src/components/FilterMenu/filterMenu.settings.js index 406fe98cf3..ac05705cee 100644 --- a/src/components/FilterMenu/filterMenu.settings.js +++ b/src/components/FilterMenu/filterMenu.settings.js @@ -44,27 +44,34 @@ import { TAG_FILTER_ALL_ITEMS, TAG_FILTER_LATEST, REAL_TIME_FILTER, - BATCH_FILTER + BATCH_FILTER, + PENDING_STATE, + RUNNING_STATE, + COMPLETED_STATE, + ABORTED_STATE, + ABORTING_STATE, + PENDING_RETRY_STATE, + TERMINATING_STATE } from '../../constants' export const jobsStatuses = [ { label: 'All', id: FILTER_ALL_ITEMS, status: FILTER_ALL_ITEMS }, - { label: 'Aborted', id: 'aborted', status: 'aborted' }, - { label: 'Aborting', id: 'aborting', status: 'aborting' }, - { label: 'Completed', id: 'completed', status: 'completed' }, + { label: 'Aborted', id: ABORTED_STATE, status: ABORTED_STATE }, + { label: 'Aborting', id: ABORTING_STATE, status: ABORTING_STATE }, + { label: 'Completed', id: COMPLETED_STATE, status: COMPLETED_STATE }, { label: 'Error', id: ERROR_STATE, status: ERROR_STATE }, - { label: 'Running', id: 'running', status: 'running' }, - { label: 'Pending', id: 'pending', status: 'pending' }, - { label: 'Pending retry', id: 'pendingRetry', status: 'pendingRetry' } + { label: 'Running', id: RUNNING_STATE, status: RUNNING_STATE }, + { label: 'Pending', id: PENDING_STATE, status: PENDING_STATE }, + { label: 'Pending retry', id: PENDING_RETRY_STATE, status: PENDING_RETRY_STATE } ] export const workflowsStatuses = [ { label: 'All', id: FILTER_ALL_ITEMS, status: FILTER_ALL_ITEMS }, { label: 'Error', id: ERROR_STATE, status: ERROR_STATE }, { label: 'Failed', id: FAILED_STATE, status: FAILED_STATE }, - { label: 'Running', id: 'running', status: 'running' }, - { label: 'Completed', id: 'completed', status: 'completed' }, - { label: 'Terminating', id: 'terminating', status: 'terminating' } + { label: 'Running', id: RUNNING_STATE, status: RUNNING_STATE }, + { label: 'Completed', id: COMPLETED_STATE, status: COMPLETED_STATE }, + { label: 'Terminating', id: TERMINATING_STATE, status: TERMINATING_STATE } ] export const generateStatusFilter = useFailedStatus => { @@ -72,11 +79,11 @@ export const generateStatusFilter = useFailedStatus => { return [ { label: 'All', id: FILTER_ALL_ITEMS, status: FILTER_ALL_ITEMS }, - { label: 'Completed', id: 'completed', status: 'completed' }, - { label: 'Running', id: 'running', status: 'running' }, - { label: 'Pending', id: 'pending', status: 'pending' }, + { label: 'Completed', id: COMPLETED_STATE, status: COMPLETED_STATE }, + { label: 'Running', id: RUNNING_STATE, status: RUNNING_STATE }, + { label: 'Pending', id: PENDING_STATE, status: PENDING_STATE }, { label: 'Error', id: status, status: status }, - { label: 'Aborted', id: 'aborted', status: 'aborted' } + { label: 'Aborted', id: ABORTED_STATE, status: ABORTED_STATE } ] } diff --git a/src/components/FunctionsPage/functions.util.jsx b/src/components/FunctionsPage/functions.util.jsx index d62bf3880b..40206dcc51 100644 --- a/src/components/FunctionsPage/functions.util.jsx +++ b/src/components/FunctionsPage/functions.util.jsx @@ -25,7 +25,7 @@ import { FUNCTION_CREATING_STATE, ERROR_STATE, FUNCTION_INITIALIZED_STATE, - FUNCTION_PENDINDG_STATE, + FUNCTION_PENDING_STATE, FUNCTION_READY_STATE, FUNCTION_RUN_KINDS, FUNCTION_RUNNING_STATE, @@ -95,7 +95,7 @@ export const infoHeaders = [ { label: 'Image', id: 'image' }, { label: 'Description', id: 'description' } ] -export const TRANSIENT_FUNCTION_STATUSES = [FUNCTION_PENDINDG_STATE, FUNCTION_RUNNING_STATE] +export const TRANSIENT_FUNCTION_STATUSES = [FUNCTION_PENDING_STATE, FUNCTION_RUNNING_STATE] const handleFetchFunctionLogs = ( dispatch, diff --git a/src/components/FunctionsPageOld/functionsOld.util.jsx b/src/components/FunctionsPageOld/functionsOld.util.jsx index 737016b51b..b2a6f81a6a 100644 --- a/src/components/FunctionsPageOld/functionsOld.util.jsx +++ b/src/components/FunctionsPageOld/functionsOld.util.jsx @@ -25,7 +25,7 @@ import { FUNCTION_CREATING_STATE, ERROR_STATE, FUNCTION_INITIALIZED_STATE, - FUNCTION_PENDINDG_STATE, + FUNCTION_PENDING_STATE, FUNCTION_READY_STATE, FUNCTION_RUN_KINDS, FUNCTION_RUNNING_STATE, @@ -89,7 +89,7 @@ export const infoHeaders = [ { label: 'Image', id: 'image' }, { label: 'Description', id: 'description' } ] -export const TRANSIENT_FUNCTION_STATUSES = [FUNCTION_PENDINDG_STATE, FUNCTION_RUNNING_STATE] +export const TRANSIENT_FUNCTION_STATUSES = [FUNCTION_PENDING_STATE, FUNCTION_RUNNING_STATE] const handleFetchFunctionLogs = ( dispatch, diff --git a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx index c0b96812b1..f60ad19256 100644 --- a/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx +++ b/src/components/Jobs/MonitorWorkflows/monitorWorkflows.util.jsx @@ -27,7 +27,9 @@ import { GROUP_BY_WORKFLOW, JOBS_PAGE, PENDING_STATE, - UNKNOWN_STATE + UNKNOWN_STATE, + RUNNING_STATE, + TERMINATING_STATE } from '../../../constants' import { getJobsDetailsMenu, @@ -146,7 +148,7 @@ export const generateActionsMenu = ( ] } else { const accessKeyExists = !isNil(job?.access_key) - const runningStates = ['running', 'pending', 'terminating'] + const runningStates = [RUNNING_STATE, PENDING_STATE, TERMINATING_STATE] return [ [ diff --git a/src/components/Jobs/jobs.util.js b/src/components/Jobs/jobs.util.js index ca49f9f85e..7ed7908b12 100644 --- a/src/components/Jobs/jobs.util.js +++ b/src/components/Jobs/jobs.util.js @@ -35,7 +35,13 @@ import { JOB_KIND_SPARK, JOB_KIND_LOCAL, ERROR_STATE, - FAILED_STATE + FAILED_STATE, + PENDING_STATE, + RUNNING_STATE, + COMPLETED_STATE, + ABORTED_STATE, + ABORTING_STATE, + PENDING_RETRY_STATE } from '../../constants' import { abortJob, @@ -74,8 +80,16 @@ export const getInfoHeaders = (isSpark, selectedJob) => { { label: 'Log level', id: LOG_LEVEL_ID }, { label: 'Output path', id: 'outputPath' }, { label: 'Total iterations', id: 'iterations' }, - { label: 'Attempt count', id: 'retryCountWithInitialAttempt', tip: 'Number of attempts to run Kubernetes jobs' }, - { label: 'Maximum attempts', id: 'maxRetriesWithInitialAttempt', tip: 'Maximum number of attempts to run Kubernetes jobs' } + { + label: 'Attempt count', + id: 'retryCountWithInitialAttempt', + tip: 'Number of attempts to run Kubernetes jobs' + }, + { + label: 'Maximum attempts', + id: 'maxRetriesWithInitialAttempt', + tip: 'Maximum number of attempts to run Kubernetes jobs' + } ] if (isSpark) { @@ -90,8 +104,8 @@ export const getInfoHeaders = (isSpark, selectedJob) => { } export const actionButtonHeader = 'Batch run' -export const JOB_STEADY_STATES = ['completed', ERROR_STATE, 'aborted', FAILED_STATE] -export const JOB_RUNNING_STATES = ['running', 'pending', 'pendingRetry'] +export const JOB_STEADY_STATES = [COMPLETED_STATE, ERROR_STATE, ABORTED_STATE, FAILED_STATE] +export const JOB_RUNNING_STATES = [RUNNING_STATE, PENDING_STATE, PENDING_RETRY_STATE] export const getJobsDetailsMenu = (job = {}) => { return [ @@ -136,7 +150,7 @@ export const isJobKindAbortable = (job, abortableFunctionKinds) => .some(kindLabel => job?.labels?.includes(kindLabel)) export const isJobAborting = (currentJob = {}) => { - return currentJob?.state?.value === 'aborting' + return currentJob?.state?.value === ABORTING_STATE } export const isJobKindDask = (jobLabels = []) => { diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index 41f863fbd7..48c308b72b 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -24,10 +24,12 @@ import { aggregateApplicationStatuses } from '../../../../utils/applications.uti import { formatMinutesToString } from '../../../../utils/measureTime' import { BATCH_FILTER, + FAILED_STATE, ME_MODE_FILTER, MODEL_ENDPOINTS_TAB, MODELS_PAGE, - REAL_TIME_FILTER + REAL_TIME_FILTER, + RUNNING_STATE } from '../../../../constants' export const generateCountersContent = (params, monitoringApplicationsStore) => { @@ -58,21 +60,21 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => title: 'Apps Status', counterData: [ { - id: 'running', + id: RUNNING_STATE, title: appReady, tooltipText: 'Running', subtitle: 'Running', - subtitleStatus: 'running' + subtitleStatus: RUNNING_STATE }, { + id: FAILED_STATE, counterClassName: classNames({ stats__failed: appError > 0 }), - id: 'failed', title: appError, tooltipText: 'Error, Unhealthy', subtitle: 'Failed', - subtitleStatus: 'failed' + subtitleStatus: FAILED_STATE } ] }, diff --git a/src/components/ProjectSettings/ProjectSettings.jsx b/src/components/ProjectSettings/ProjectSettings.jsx index a728678c98..5d75f70f82 100644 --- a/src/components/ProjectSettings/ProjectSettings.jsx +++ b/src/components/ProjectSettings/ProjectSettings.jsx @@ -29,7 +29,6 @@ import ContentMenu from '../../elements/ContentMenu/ContentMenu' import { Button, ConfirmDialog, Loader } from 'igz-controls/components' import { - COMPLETED_STATE, generateMembers, isProjectMembersTabShown, page, @@ -43,7 +42,11 @@ import { } from '../../elements/MembersPopUp/membersReducer' import projectsIguazioApi from '../../api/projects-iguazio-api' import { DANGER_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' -import { PROJECTS_SETTINGS_MEMBERS_TAB, PROJECTS_SETTINGS_SECRETS_TAB } from '../../constants' +import { + COMPLETED_STATE, + PROJECTS_SETTINGS_MEMBERS_TAB, + PROJECTS_SETTINGS_SECRETS_TAB +} from '../../constants' import { fetchProjects } from '../../reducers/projectReducer' import { onDeleteProject } from '../ProjectsPage/projects.util' import { setNotification } from 'igz-controls/reducers/notificationReducer' diff --git a/src/components/ProjectSettings/projectSettings.util.jsx b/src/components/ProjectSettings/projectSettings.util.jsx index 942b69cf62..81f7bd982d 100644 --- a/src/components/ProjectSettings/projectSettings.util.jsx +++ b/src/components/ProjectSettings/projectSettings.util.jsx @@ -38,8 +38,6 @@ import Secrets from 'igz-controls/images/lock-icon.svg?react' import User from 'igz-controls/images/user.svg?react' import Users from 'igz-controls/images/users.svg?react' -export const COMPLETED_STATE = 'completed' - export const tabs = projectMembershipIsEnabled => [ { id: PROJECTS_SETTINGS_GENERAL_TAB, diff --git a/src/constants.js b/src/constants.js index 261f4e389f..6080bcd63e 100644 --- a/src/constants.js +++ b/src/constants.js @@ -46,10 +46,17 @@ export const CANCEL_REQUEST_TIMEOUT = 120000 export const PROJECT_ONLINE_STATUS = 'online' +export const ABORTED_STATE = 'aborted' +export const ABORTING_STATE = 'aborting' +export const COMPLETED_STATE = 'completed' export const ERROR_STATE = 'error' export const FAIL_STATE = 'fail' export const FAILED_STATE = 'failed' export const PENDING_STATE = 'pending' +export const PENDING_RETRY_STATE = 'pendingRetry' +export const RUNNING_STATE = 'running' +export const SUCCEEDED_STATE = 'succeeded' +export const TERMINATING_STATE = 'terminating' export const UNHEALTHY_STATE = 'unhealthy' export const UNKNOWN_STATE = 'unknown' @@ -276,7 +283,7 @@ export const FUNCTION_FAILED_TO_DELETE_STATE = 'failedToDelete' export const FUNCTION_ERROR_STATE = 'error' export const FUNCTION_INITIALIZED_STATE = 'initialized' export const FUNCTION_READY_STATE = 'ready' -export const FUNCTION_PENDINDG_STATE = 'pending' +export const FUNCTION_PENDING_STATE = 'pending' export const FUNCTION_RUNNING_STATE = 'running' export const FUNCTION_DEFAULT_HANDLER = 'handler' export const FUNCTION_RUN_KINDS = [FUNCTION_TYPE_JOB] diff --git a/src/elements/FeatureValidator/featureValidatior.utils.js b/src/elements/FeatureValidator/featureValidatior.utils.js index 517936e76f..ceccb76422 100644 --- a/src/elements/FeatureValidator/featureValidatior.utils.js +++ b/src/elements/FeatureValidator/featureValidatior.utils.js @@ -21,7 +21,7 @@ such restriction. import { ERROR_STATE, FAIL_STATE } from '../../constants' export const validatorStates = { - [ERROR_STATE]: 'error', + [ERROR_STATE]: ERROR_STATE, info: 'info', warn: 'warning', warning: 'warning', diff --git a/src/elements/JobsTable/JobsTable.jsx b/src/elements/JobsTable/JobsTable.jsx index b370fec0ca..538991c4fa 100644 --- a/src/elements/JobsTable/JobsTable.jsx +++ b/src/elements/JobsTable/JobsTable.jsx @@ -31,6 +31,7 @@ import Table from '../../components/Table/Table' import { Loader } from 'igz-controls/components' import { + ABORTING_STATE, JOB_KIND_JOB, JOBS_MONITORING_JOBS_TAB, JOBS_PAGE, @@ -144,7 +145,7 @@ const JobsTable = React.forwardRef( setSelectedJob(state => ({ ...state, abortTaskId: task, - state: getState('aborting', JOBS_PAGE, JOB_KIND_JOB) + state: getState(ABORTING_STATE, JOBS_PAGE, JOB_KIND_JOB) })) } @@ -152,7 +153,7 @@ const JobsTable = React.forwardRef( state.map(aJob => { if (aJob.uid === job.uid) { aJob.abortTaskId = task - aJob.state = getState('aborting', JOBS_PAGE, JOB_KIND_JOB) + aJob.state = getState(ABORTING_STATE, JOBS_PAGE, JOB_KIND_JOB) } return aJob diff --git a/src/elements/ProjectCard/projectCard.util.js b/src/elements/ProjectCard/projectCard.util.js index f23a61cce2..f665e5ae66 100644 --- a/src/elements/ProjectCard/projectCard.util.js +++ b/src/elements/ProjectCard/projectCard.util.js @@ -20,7 +20,7 @@ such restriction. import { isEmpty } from 'lodash' import { groupByUniqName } from '../../utils/groupByUniqName' -import { ERROR_STATE } from '../../constants' +import { ERROR_STATE, FAILED_STATE, FUNCTION_READY_STATE, RUNNING_STATE } from '../../constants' export const generateProjectStatistic = ( projectSummary = {}, @@ -32,7 +32,8 @@ export const generateProjectStatistic = ( ) => { const grouppedNuclioFunctions = groupByUniqName(nuclioFunctions, 'metadata.name') const runningNuclioFunctions = Object.values(grouppedNuclioFunctions).reduce( - (prev, curr) => (curr.status.state === 'ready' && !curr.spec.disable ? (prev += 1) : prev), + (prev, curr) => + curr.status.state === FUNCTION_READY_STATE && !curr.spec.disable ? (prev += 1) : prev, 0 ) const failedNuclioFunctions = Object.values(grouppedNuclioFunctions).reduce( @@ -46,7 +47,7 @@ export const generateProjectStatistic = ( !fetchProjectsSummaryFailure && !fetchNuclioFunctionsFailure && projectSummary?.runs_running_count + runningNuclioFunctions > 0 - ? 'running' + ? RUNNING_STATE : 'default', counterTooltip: 'ML jobs and Nuclio functions', label: 'Running', @@ -63,7 +64,7 @@ export const generateProjectStatistic = ( !fetchProjectsSummaryFailure && !fetchNuclioFunctionsFailure && projectSummary.runs_failed_recent_count + failedNuclioFunctions > 0 - ? 'failed' + ? FAILED_STATE : 'default', counterTooltip: 'Failed ML jobs and nuclio functions in the last 24 hours', label: 'Failed', diff --git a/src/elements/ProjectFunctions/ProjectFunctions.jsx b/src/elements/ProjectFunctions/ProjectFunctions.jsx index c9526f5ffd..0ea8104a3c 100644 --- a/src/elements/ProjectFunctions/ProjectFunctions.jsx +++ b/src/elements/ProjectFunctions/ProjectFunctions.jsx @@ -27,7 +27,13 @@ import { useDispatch, useSelector } from 'react-redux' import ProjectDataCard from '../ProjectDataCard/ProjectDataCard' -import { ERROR_STATE, REQUEST_CANCELED } from '../../constants' +import { + ERROR_STATE, + FAILED_STATE, + FUNCTION_READY_STATE, + REQUEST_CANCELED, + RUNNING_STATE +} from '../../constants' import { fetchApiGateways, fetchNuclioFunctions } from '../../reducers/nuclioReducer' import { generateNuclioLink } from '../../utils' import { groupByUniqName } from '../../utils/groupByUniqName' @@ -73,7 +79,8 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { ) const functionsRunning = groupeFunctionsRunning.reduce( - (prev, curr) => (!curr.spec.disable && curr.status.state === 'ready' ? (prev += 1) : prev), + (prev, curr) => + !curr.spec.disable && curr.status.state === FUNCTION_READY_STATE ? (prev += 1) : prev, 0 ) const functionsFailed = groupeFunctionsRunning.reduce( @@ -86,8 +93,8 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { counterTooltip: 'Running', value: functionsRunning, label: 'Running', - className: 'running', - status: 'running', + className: RUNNING_STATE, + status: RUNNING_STATE, href: generateNuclioLink(`/projects/${params.projectName}/functions`), loading: nuclioStore.loading }, @@ -95,15 +102,15 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { counterTooltip: 'Error, Unhealthy', value: functionsFailed, label: 'Failed', - status: 'failed', - className: functionsFailed > 0 ? 'failed' : 'running', + status: FAILED_STATE, + className: functionsFailed > 0 ? FAILED_STATE : RUNNING_STATE, href: generateNuclioLink(`/projects/${params.projectName}/functions`), loading: nuclioStore.loading }, apiGateways: { value: nuclioStore.apiGateways, label: 'API gateways', - className: 'running', + className: RUNNING_STATE, href: generateNuclioLink(`/projects/${params.projectName}/api-gateways`), loading: nuclioStore.loading }, @@ -113,7 +120,7 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { ? 'N/A' : (Object.keys(nuclioStore.v3ioStreams.data).length ?? 0), label: 'Consumer groups', - className: 'running', + className: RUNNING_STATE, link: `/projects/${params.projectName}/monitor${ !isNuclioModeDisabled ? '/consumer-groups' : '' }`, @@ -159,9 +166,9 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { }, status: { value: - func?.status?.state === 'ready' && !func?.spec?.disable + func?.status?.state === FUNCTION_READY_STATE && !func?.spec?.disable ? 'Running' - : func?.status?.state === 'ready' && func?.spec?.disable + : func?.status?.state === FUNCTION_READY_STATE && func?.spec?.disable ? 'Standby' : [ERROR_STATE, 'unhealthy', 'imported', 'scaledToZero'].includes( func?.status?.state diff --git a/src/elements/ProjectJobs/projectJobs.utils.js b/src/elements/ProjectJobs/projectJobs.utils.js index e609236316..408a30d833 100644 --- a/src/elements/ProjectJobs/projectJobs.utils.js +++ b/src/elements/ProjectJobs/projectJobs.utils.js @@ -20,7 +20,13 @@ such restriction. import { orderBy } from 'lodash' import { measureTime } from '../../utils/measureTime' -import { MONITOR_JOBS_TAB } from '../../constants' +import { + ABORTED_STATE, + FAILED_STATE, + MONITOR_JOBS_TAB, + RUNNING_STATE, + SUCCEEDED_STATE +} from '../../constants' import { formatDatetime } from 'igz-controls/utils/datetime.util' import { typesOfJob } from '../../utils/jobs.util' @@ -29,8 +35,8 @@ export const getJobsStatistics = (projectCounter, projectName) => { running: { value: projectCounter.error ? 'N/A' : projectCounter?.data?.runs_running_count, label: 'In Process', - className: 'running', - status: 'running', + className: RUNNING_STATE, + status: RUNNING_STATE, link: `/projects/${projectName}/jobs/${MONITOR_JOBS_TAB}`, counterTooltip: 'Aborting, Pending, Pending retry, Running', loading: projectCounter.loading @@ -40,9 +46,9 @@ export const getJobsStatistics = (projectCounter, projectName) => { label: 'Failed', className: projectCounter.error || projectCounter?.data?.runs_failed_recent_count === 0 - ? 'running' - : 'failed', - status: 'failed', + ? RUNNING_STATE + : FAILED_STATE, + status: FAILED_STATE, link: `/projects/${projectName}/jobs/${MONITOR_JOBS_TAB}`, counterTooltip: 'Aborted, Error', loading: projectCounter.loading @@ -50,8 +56,8 @@ export const getJobsStatistics = (projectCounter, projectName) => { succeeded: { value: projectCounter.error ? 'N/A' : projectCounter?.data?.runs_completed_recent_count, label: 'Succeeded', - status: 'succeeded', - className: 'running', + status: SUCCEEDED_STATE, + className: RUNNING_STATE, link: `/projects/${projectName}/jobs/${MONITOR_JOBS_TAB}`, counterTooltip: 'Completed', loading: projectCounter.loading @@ -82,7 +88,7 @@ export const getJobsTableData = (jobs, projectName) => { startTime: { value: formatDatetime( job[0].status.start_time, - job[0].status.state === 'aborted' ? 'N/A' : 'Not yet started' + job[0].status.state === ABORTED_STATE ? 'N/A' : 'Not yet started' ), className: 'table-cell_big' }, diff --git a/src/elements/ProjectStatistics/ProjectStatistics.jsx b/src/elements/ProjectStatistics/ProjectStatistics.jsx index ea047fd523..17d81d01ad 100644 --- a/src/elements/ProjectStatistics/ProjectStatistics.jsx +++ b/src/elements/ProjectStatistics/ProjectStatistics.jsx @@ -24,7 +24,19 @@ import PropTypes from 'prop-types' import ProjectStatisticsCounter from '../ProjectStatisticsCounter/ProjectStatisticsCounter' import { ANY_TIME_DATE_OPTION, PAST_24_HOUR_DATE_OPTION } from '../../utils/datePicker.util' -import { DATES_FILTER, FAILED_STATE, STATUS_FILTER } from '../../constants' +import { + ABORTED_STATE, + ABORTING_STATE, + COMPLETED_STATE, + DATES_FILTER, + ERROR_STATE, + FAILED_STATE, + PENDING_RETRY_STATE, + PENDING_STATE, + RUNNING_STATE, + STATUS_FILTER, + SUCCEEDED_STATE +} from '../../constants' import './projectStatistics.scss' @@ -34,21 +46,23 @@ const ProjectStatistics = ({ statistics }) => { const onNavigate = (statistic, key) => { let filters = {} - if (['running', 'workflows'].includes(key)) { + if ([RUNNING_STATE, 'workflows'].includes(key)) { filters = { [DATES_FILTER]: ANY_TIME_DATE_OPTION, [STATUS_FILTER]: - key === 'workflows' ? ['running'] : ['running', 'pending', 'pendingRetry', 'aborting'] + key === 'workflows' + ? [RUNNING_STATE] + : [RUNNING_STATE, PENDING_STATE, PENDING_RETRY_STATE, ABORTING_STATE] } } else if (key === FAILED_STATE) { filters = { [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION, - [STATUS_FILTER]: ['error', 'aborted'] + [STATUS_FILTER]: [ERROR_STATE, ABORTED_STATE] } - } else if (key === 'succeeded') { + } else if (key === SUCCEEDED_STATE) { filters = { [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION, - [STATUS_FILTER]: ['completed'] + [STATUS_FILTER]: [COMPLETED_STATE] } } diff --git a/src/elements/WorkflowsTable/WorkflowsTable.jsx b/src/elements/WorkflowsTable/WorkflowsTable.jsx index 8a69eb466c..9920630629 100644 --- a/src/elements/WorkflowsTable/WorkflowsTable.jsx +++ b/src/elements/WorkflowsTable/WorkflowsTable.jsx @@ -31,6 +31,7 @@ import Workflow from '../../components/Workflow/Workflow' import { Loader } from 'igz-controls/components' import { + ABORTING_STATE, ERROR_STATE, FAILED_STATE, JOB_KIND_JOB, @@ -234,7 +235,7 @@ const WorkflowsTable = React.forwardRef( const handlePollAbortingJob = useCallback( (jobRun, refresh) => { - if (jobRun.abortTaskId && jobRun.state.value === 'aborting') { + if (jobRun.abortTaskId && jobRun.state.value === ABORTING_STATE) { const abortingJob = { [jobRun.abortTaskId]: { uid: jobRun.uid, @@ -337,7 +338,7 @@ const WorkflowsTable = React.forwardRef( setSelectedJob(state => ({ ...state, abortTaskId: task, - state: getState('aborting', JOBS_PAGE, JOB_KIND_JOB) + state: getState(ABORTING_STATE, JOBS_PAGE, JOB_KIND_JOB) })) }, [setSelectedJob] diff --git a/src/hooks/useJobsPageData.js b/src/hooks/useJobsPageData.js index 75de737b40..d4a6c7a730 100644 --- a/src/hooks/useJobsPageData.js +++ b/src/hooks/useJobsPageData.js @@ -25,14 +25,15 @@ import { isEmpty } from 'lodash' import { monitorJob, pollAbortingJobs, rerunJob } from '../components/Jobs/jobs.util' import { - BE_PAGE, - BE_PAGE_SIZE, - FILTER_ALL_ITEMS, - GROUP_BY_WORKFLOW, - JOBS_MONITORING_JOBS_TAB, - JOBS_MONITORING_PAGE, - MONITOR_JOBS_TAB, - SCHEDULE_TAB + ABORTING_STATE, + BE_PAGE, + BE_PAGE_SIZE, + FILTER_ALL_ITEMS, + GROUP_BY_WORKFLOW, + JOBS_MONITORING_JOBS_TAB, + JOBS_MONITORING_PAGE, + MONITOR_JOBS_TAB, + SCHEDULE_TAB } from '../constants' import { usePagination } from './usePagination.hook' import { parseJob } from '../utils/parseJob' @@ -142,7 +143,7 @@ export const useJobsPageData = (initialTabData, selectedTab) => { if (response?.runs) { const parsedJobs = response.runs.map(job => parseJob(job)) const responseAbortingJobs = parsedJobs.reduce((acc, job) => { - if (job.state.value === 'aborting' && job.abortTaskId) { + if (job.state.value === ABORTING_STATE && job.abortTaskId) { acc[job.abortTaskId] = { uid: job.uid, name: job.name diff --git a/src/utils/createAlertsContent.jsx b/src/utils/createAlertsContent.jsx index 12631f785d..0b8ab00c8b 100644 --- a/src/utils/createAlertsContent.jsx +++ b/src/utils/createAlertsContent.jsx @@ -47,7 +47,9 @@ import { SEVERITY_CRITICAL, SEVERITY_HIGH, SEVERITY_LOW, - SEVERITY_MEDIUM + SEVERITY_MEDIUM, + FAIL_STATE, + FAILED_STATE } from '../constants' const getEntityTypeData = entityType => { @@ -177,7 +179,7 @@ const getNotificationData = notifications => return { icon: (
      {alertsNotifications[notification.kind]} @@ -189,7 +191,7 @@ const getNotificationData = notifications =>
      ), tooltip: upperFirst( - `${notification.kind}: ${notification.summary.succeeded} success, ${notification.summary.failed} failed` + `${notification.kind}: ${notification.summary.succeeded} success, ${notification.summary.failed} ${FAILED_STATE}` ), kind: notification.kind, succeeded: notification.summary.succeeded, diff --git a/src/utils/createArtifactPreviewContent.js b/src/utils/createArtifactPreviewContent.js index 67a476d8de..404973f5d6 100644 --- a/src/utils/createArtifactPreviewContent.js +++ b/src/utils/createArtifactPreviewContent.js @@ -19,6 +19,8 @@ such restriction. */ import { has, isString } from 'lodash' +import { UNKNOWN_STATE } from '../constants' + const splitStringToArray = str => { return str.split(/,(?! )/g) } @@ -85,7 +87,7 @@ export const createArtifactPreviewContent = ( content: URL.createObjectURL(res.data) } } else { - artifact.type = 'unknown' + artifact.type = UNKNOWN_STATE if (path && artifactName) { artifact.data = { diff --git a/src/utils/createJobsContent.js b/src/utils/createJobsContent.js index 6045864965..d2444f8b0d 100644 --- a/src/utils/createJobsContent.js +++ b/src/utils/createJobsContent.js @@ -31,7 +31,8 @@ import { MONITOR_JOBS_TAB, MONITOR_WORKFLOWS_TAB, NAME_FILTER, - PROJECT_FILTER + PROJECT_FILTER, + RUNNING_STATE } from '../constants' import { openPopUp } from 'igz-controls/utils/common.util' import { @@ -119,7 +120,7 @@ export const createJobsMonitorTabContent = (jobs, jobName, isStagingMode) => { id: `duration.${identifierUnique}`, value: measureTime( job.startTime || new Date(job.created_at), - (job.state?.value !== 'running' && job.updated) || + (job.state?.value !== RUNNING_STATE && job.updated) || (job.state?.value !== ERROR_STATE && new Date(job.finished_at)) ), className: 'table-cell-1', @@ -331,7 +332,7 @@ export const createJobsWorkflowsTabContent = (jobs, projectName, isStagingMode, id: `duration.${identifierUnique}`, value: measureTime( job.startTime || new Date(job.created_at), - (job.state?.value !== 'running' && job.updated) || + (job.state?.value !== RUNNING_STATE && job.updated) || (job.state?.value !== ERROR_STATE && new Date(job.finished_at)) ), className: 'table-cell-1', @@ -529,7 +530,7 @@ export const createJobsMonitoringContent = (jobs, jobName, isStagingMode) => { id: `duration.${identifierUnique}`, value: measureTime( job.startTime || new Date(job.created_at), - (job.state?.value !== 'running' && job.updated) || + (job.state?.value !== RUNNING_STATE && job.updated) || (job.state?.value !== ERROR_STATE && new Date(job.finished_at)) ), className: 'table-cell-1', @@ -747,7 +748,7 @@ export const createWorkflowsMonitoringContent = (jobs, isStagingMode, isSelected id: `duration.${identifierUnique}`, value: measureTime( job.startTime || new Date(job.created_at), - (job.state?.value !== 'running' && job.updated) || + (job.state?.value !== RUNNING_STATE && job.updated) || (job.state?.value !== ERROR_STATE && new Date(job.finished_at)) ), className: 'table-cell-1', diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index e5ad8409ba..97d5ce3f3b 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -35,7 +35,14 @@ import { MONITORING_APP_PAGE, MONITOR_WORKFLOWS_TAB, STATUS_FILTER, - TYPE_FILTER + TYPE_FILTER, + PENDING_STATE, + RUNNING_STATE, + COMPLETED_STATE, + ABORTED_STATE, + ABORTING_STATE, + PENDING_RETRY_STATE, + TERMINATING_STATE } from '../constants' import { ANY_TIME_DATE_OPTION, @@ -81,10 +88,15 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ - [STATUS_FILTER]: ['running', 'pending', 'pendingRetry', 'aborting'], + [STATUS_FILTER]: [ + RUNNING_STATE, + PENDING_STATE, + PENDING_RETRY_STATE, + ABORTING_STATE + ], [DATES_FILTER]: ANY_TIME_DATE_OPTION }), - statusClass: 'running', + statusClass: RUNNING_STATE, tooltip: 'Aborting, Pending, Pending retry, Running', label: IN_PROCESS }, @@ -93,10 +105,10 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ - [STATUS_FILTER]: [ERROR_STATE, 'aborted'], + [STATUS_FILTER]: [ERROR_STATE, ABORTED_STATE], [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION }), - statusClass: 'failed', + statusClass: FAILED_STATE, tooltip: 'Aborted, Error', label: FAILED, counterClassName: classNames({ @@ -108,10 +120,10 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ - [STATUS_FILTER]: ['completed'], + [STATUS_FILTER]: [COMPLETED_STATE], [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION }), - statusClass: 'completed', + statusClass: COMPLETED_STATE, tooltip: 'Completed', label: SUCCEEDED } @@ -132,11 +144,11 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { counter: data.running || 0, link: () => navigateToJobsMonitoringPage({ - [STATUS_FILTER]: ['running', 'terminating'], + [STATUS_FILTER]: [RUNNING_STATE, TERMINATING_STATE], [DATES_FILTER]: ANY_TIME_DATE_OPTION }), className: classNames('stats__link', 'stats__line'), - statusClass: 'running', + statusClass: RUNNING_STATE, tooltip: 'Running, Terminating', label: IN_PROCESS }, @@ -148,7 +160,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { [STATUS_FILTER]: [ERROR_STATE, FAILED_STATE], [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION }), - statusClass: 'failed', + statusClass: FAILED_STATE, tooltip: 'Error, Failed', label: FAILED, counterClassName: classNames({ @@ -160,10 +172,10 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ - [STATUS_FILTER]: ['completed'], + [STATUS_FILTER]: [COMPLETED_STATE], [DATES_FILTER]: PAST_24_HOUR_DATE_OPTION }), - statusClass: 'completed', + statusClass: COMPLETED_STATE, tooltip: 'Completed', label: SUCCEEDED } @@ -221,7 +233,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { counter: data.running || 0, className: classNames(projectName && 'stats__link'), link: () => navigateToTab(projectName, MONITORING_APP_PAGE), - statusClass: 'running', + statusClass: RUNNING_STATE, label: RUNNING, popUpClassName: classNames({ 'card-popup_text_link': projectName }), tooltip: RUNNING @@ -232,7 +244,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { stats__failed: data.failed > 0 }), link: () => navigateToTab(projectName, MONITORING_APP_PAGE), - statusClass: 'failed', + statusClass: FAILED_STATE, label: FAILED, popUpClassName: classNames({ 'card-popup_text_link': projectName }), tooltip: 'Error, Unhealthy' diff --git a/src/utils/generatePods.jsx b/src/utils/generatePods.jsx index 250a0274f6..91bd7b0b4c 100644 --- a/src/utils/generatePods.jsx +++ b/src/utils/generatePods.jsx @@ -19,17 +19,19 @@ such restriction. */ import React from 'react' +import { PENDING_STATE } from '../constants' + export const generatePods = (project, uid, pods) => { const podsList = pods?.[project]?.[uid]?.pod_resources ?? [] const podsTooltip = podsList.map((value, index) => (

      {value?.name} - {value?.status?.phase?.toLowerCase?.() === 'pending' + {value?.status?.phase?.toLowerCase?.() === PENDING_STATE ? ' (pending...)' : (value?.status?.phase?.toLowerCase ?? '')}

      )) - const podsPending = podsList.filter(pod => pod?.status?.phase?.toLowerCase?.() === 'pending') + const podsPending = podsList.filter(pod => pod?.status?.phase?.toLowerCase?.() === PENDING_STATE) return { podsList, diff --git a/src/utils/getArtifactPreview.jsx b/src/utils/getArtifactPreview.jsx index d9d8ca787d..6cdce1792c 100644 --- a/src/utils/getArtifactPreview.jsx +++ b/src/utils/getArtifactPreview.jsx @@ -22,7 +22,13 @@ import Download from '../common/Download/Download' import api from '../api/artifacts-api' import { createArtifactPreviewContent } from './createArtifactPreviewContent' -import { ARTIFACT_MAX_CHUNK_SIZE, DEFAULT_ABORT_MSG, REQUEST_CANCELED } from '../constants' +import { + ARTIFACT_MAX_CHUNK_SIZE, + DEFAULT_ABORT_MSG, + ERROR_STATE, + REQUEST_CANCELED, + UNKNOWN_STATE +} from '../constants' const fileSizes = { '100KB': 102400, @@ -164,7 +170,7 @@ export const fetchArtifactPreviewFromPath = async ( : 'preview, use the download option instead' }` }, - type: 'unknown' + type: UNKNOWN_STATE } ]) } else { @@ -195,7 +201,7 @@ export const fetchArtifactPreviewFromPath = async ( body: err.response ? JSON.stringify(err.response, null, 2) : '' }, content: [], - type: 'error' + type: ERROR_STATE } ]) } diff --git a/src/utils/poll.util.js b/src/utils/poll.util.js index 7b55e7cb74..58bebc9d37 100644 --- a/src/utils/poll.util.js +++ b/src/utils/poll.util.js @@ -19,9 +19,11 @@ such restriction. */ import { constant, chain, isNil, overSome, isNaN, isFinite } from 'lodash' -export const BG_TASK_RUNNING = 'running' -export const BG_TASK_FAILED = 'failed' -export const BG_TASK_SUCCEEDED = 'succeeded' +import { FAILED_STATE, RUNNING_STATE, SUCCEEDED_STATE } from '../constants' + +export const BG_TASK_RUNNING = RUNNING_STATE +export const BG_TASK_FAILED = FAILED_STATE +export const BG_TASK_SUCCEEDED = SUCCEEDED_STATE /** * Polls by calling `pollMethod` and then invoking `isDone` method with `pollMethod`'s result. Stops polling From 5255661af7692ed6173624e2d96bf12c7ee520b3 Mon Sep 17 00:00:00 2001 From: Ilank <63646693+ilan7empest@users.noreply.github.com> Date: Wed, 5 Nov 2025 12:25:24 +0200 Subject: [PATCH 211/228] Fix [UI] when fail to unarchive a project there no indication for the user that it failed (#3491) --- src/components/ProjectsPage/Projects.jsx | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/components/ProjectsPage/Projects.jsx b/src/components/ProjectsPage/Projects.jsx index 9dc4ce2894..4724f383fa 100644 --- a/src/components/ProjectsPage/Projects.jsx +++ b/src/components/ProjectsPage/Projects.jsx @@ -39,7 +39,7 @@ import { BG_TASK_RUNNING } from '../../utils/poll.util' import { PROJECT_ONLINE_STATUS } from '../../constants' import { ConfirmDialog } from 'igz-controls/components' import { openPopUp } from 'igz-controls/utils/common.util' -import { FORBIDDEN_ERROR_STATUS_CODE, PRIMARY_BUTTON } from 'igz-controls/constants' +import { FORBIDDEN_ERROR_STATUS_CODE, NOTFOUND_ERROR_STATUS_CODE, PRIMARY_BUTTON } from 'igz-controls/constants' import { fetchBackgroundTasks } from '../../reducers/tasksReducer' import { setNotification } from 'igz-controls/reducers/notificationReducer' import { showErrorNotification } from 'igz-controls/utils/notification.util' @@ -110,7 +110,7 @@ const Projects = () => { project => { return filterByName.length > 0 ? project.metadata.name.toLocaleLowerCase().includes(filterByName.toLocaleLowerCase()) && - isValidProjectState(project) + isValidProjectState(project) : isValidProjectState(project) }, [filterByName, isValidProjectState] @@ -144,7 +144,7 @@ const Projects = () => { generateAlerts(result, dispatch) } }) - .catch(() => {}) + .catch(() => { }) if (!isEmpty(deletingProjectsRef.current)) { dispatch(fetchBackgroundTasks({})) @@ -211,7 +211,7 @@ const Projects = () => { .catch(error => { const customErrorMsg = error.response?.status === FORBIDDEN_ERROR_STATUS_CODE - ? `You don't have rights to archive project ${project.metadata.name}` + ? `You do not have permission to archive project ${project.metadata.name}` : `Failed to archive project ${project.metadata.name}` showErrorNotification(dispatch, error, '', customErrorMsg, () => @@ -232,6 +232,17 @@ const Projects = () => { .then(() => { fetchMinimalProjects() }) + .catch(error => { + const customErrorMsg = error.response?.status === NOTFOUND_ERROR_STATUS_CODE + ? `Failed to unarchive project ${project.metadata.name}. The project was not found.` + : error.response?.status === FORBIDDEN_ERROR_STATUS_CODE + ? `You do not have permission to unarchive project ${project.metadata.name}` + : `Failed to unarchive project ${project.metadata.name}` + + showErrorNotification(dispatch, error, '', customErrorMsg, () => + handleUnarchiveProject(project) + ) + }) }, [dispatch, fetchMinimalProjects] ) @@ -420,7 +431,7 @@ const Projects = () => { ) } }) - .catch(() => {}) + .catch(() => { }) } return ( From f6f33181c9edc65a26c786349a8be52dd545d0cf Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Sun, 9 Nov 2025 12:58:00 +0200 Subject: [PATCH 212/228] Fix [Monitoring app UI ] test_id for go_back for Application not correct (#3493) --- .../FormEnvironmentVariablesRow.jsx | 9 ++++----- src/elements/TableTop/TableTop.jsx | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx b/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx index e5b8bc2295..b0e7ccdf0d 100644 --- a/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx +++ b/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx @@ -56,7 +56,7 @@ const FormEnvironmentVariablesRow = ({ uniquenessValidator }) => { const [fieldData, setFieldData] = useState(fields.value[index]) - const { projectName } = useParams() + const { projectName } = useParams() const tableRowClassNames = classnames( 'form-table__row', @@ -133,10 +133,9 @@ const FormEnvironmentVariablesRow = ({ name={`${rowPath}.data.secretName`} placeholder="Secret Name" required - validationRules={ - (getValidationRules('environmentVariables.secretName'), - [getSecretNameValidator(projectName, editingItem?.data?.typeName) ]) - } + validationRules={getValidationRules('environmentVariables.secretName', [ + getSecretNameValidator(projectName, editingItem?.data?.typeName) + ])} /> {
      - + From 1b44fa761a5e5f20616730e1d407772775785c6b Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Thu, 13 Nov 2025 12:36:18 +0200 Subject: [PATCH 213/228] Fix [Real-time pipelines] Monitoring icon isn't displayed (#3500) --- src/components/Pipeline/Pipeline.jsx | 2 +- tests/mockServer/data/funcs.json | 1229 +++++++++++++------------- tests/mockServer/mock.js | 9 +- 3 files changed, 623 insertions(+), 617 deletions(-) diff --git a/src/components/Pipeline/Pipeline.jsx b/src/components/Pipeline/Pipeline.jsx index 08a5baf14a..421881cc06 100644 --- a/src/components/Pipeline/Pipeline.jsx +++ b/src/components/Pipeline/Pipeline.jsx @@ -210,7 +210,7 @@ const Pipeline = ({ content }) => { label: stepName, subLabel: subLabel, isSelectable: true, - customData: step + customData: { ...step, track_models: graph.track_models } }, className: classnames(selectedStep.id === stepName && 'selected'), position: { x: 0, y: 0 } diff --git a/tests/mockServer/data/funcs.json b/tests/mockServer/data/funcs.json index 80a5e49979..74a6b50dd7 100644 --- a/tests/mockServer/data/funcs.json +++ b/tests/mockServer/data/funcs.json @@ -44,10 +44,13 @@ }, "monitoring_data": { "my-endpoint": { - "inputs": [ ], - "outputs": [ ], - "input_path": null, - "result_path": null, + "inputs": [], + "outputs": [ + "output1", + "output2" + ], + "input_path": "input_path", + "result_path": "result_path", "creation_strategy": "inplace", "labels": null, "model_path": "store://llm-prompts/default/my_llm4#0@9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554^d28e010ba24e272a3ba2ba522f6caecde05ff383", @@ -68,8 +71,7 @@ } }, "shape": "folder" - }, - "track_models": true + } }, "shared_models": { "model-deployment": [ @@ -77,15 +79,15 @@ { "name": "model-deployment", "artifact_uri": "store://models/default/model_art1#0@5b83db22-80da-4c97-8cd0-eb269a4c9d2a^e1b0a442a7602456e6bbd0934931b3eaaf8ce09a", - "inputs": [ ], - "outputs": [ ], + "inputs": [], + "outputs": [], "input_path": null, "result_path": null } ] }, "engine": "async", - "track_models": false, + "track_models": true, "model_endpoints_names": [ "my-endpoint" ], @@ -104,7 +106,7 @@ "priority_class_name": "igz-workload-medium", "filename": "./function_with_llm.py", "image": "mlrun/mlrun", - "node_selector": { }, + "node_selector": {}, "env": [ { "name": "MLRUN_HTTPDB__NUCLIO__EXPLICIT_ACK", @@ -161,6 +163,7 @@ } }, "tolerations": null, + "track_models": true, "volume_mounts": [ { "name": "serving-conf", @@ -8012,26 +8015,26 @@ "verbose": false }, { - "kind": "serving", - "metadata": { + "kind": "serving", + "metadata": { "name": "model-monitoring-stream", "tag": "latest", "project": "default", "categories": [], "credentials": { - "access_key": "$ref:mlrun-auth-secrets.36ade9f8ae7bddc0fc42b8c701469b8d23268177977bd695c36ed51c" + "access_key": "$ref:mlrun-auth-secrets.36ade9f8ae7bddc0fc42b8c701469b8d23268177977bd695c36ed51c" }, "hash": "85957751e571a92e07213781f5e0c35bfbe42c64", "updated": "2022-07-04T06:37:28.324783+00:00" - }, - "spec": { + }, + "spec": { "command": "", "args": [], "image": "mlrun/mlrun", "build": { - "commands": [], - "code_origin": "/mlrun/mlrun/model_monitoring/stream_processing_fs.py", - "origin_filename": "/mlrun/mlrun/model_monitoring/stream_processing_fs.py" + "commands": [], + "code_origin": "/mlrun/mlrun/model_monitoring/stream_processing_fs.py", + "origin_filename": "/mlrun/mlrun/model_monitoring/stream_processing_fs.py" }, "description": "", "default_handler": "", @@ -8039,657 +8042,657 @@ "volumes": [], "volume_mounts": [], "env": [ - { - "name": "MODEL_MONITORING_ACCESS_KEY", - "valueFrom": { - "secretKeyRef": { - "key": "mlrun.model-monitoring.MODEL_MONITORING_ACCESS_KEY", - "name": "mlrun-project-secrets-default" - } - } + { + "name": "MODEL_MONITORING_ACCESS_KEY", + "valueFrom": { + "secretKeyRef": { + "key": "mlrun.model-monitoring.MODEL_MONITORING_ACCESS_KEY", + "name": "mlrun-project-secrets-default" + } + } + }, + { + "name": "V3IO_API", + "value": "http://v3io-webapi:8081" + }, + { + "name": "V3IO_USERNAME", + "value": "pipelines" + }, + { + "name": "V3IO_ACCESS_KEY", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.27111631aff0f77b2ca9e3f972065f482a58b63645f0afd8d231028f" + } + } + }, + { + "name": "V3IO_FRAMESD", + "value": "http://framesd:8080" + }, + { + "name": "MLRUN_AUTH_SESSION", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.36ade9f8ae7bddc0fc42b8c701469b8d23268177977bd695c36ed51c" + } + } + }, + { + "name": "MLRUN_K8S_SECRET__AZURE_RESOURCE_GROUP", + "valueFrom": { + "secretKeyRef": { + "key": "AZURE_RESOURCE_GROUP", + "name": "mlrun-project-secrets-azureml-admin" + } + } + }, + { + "name": "MLRUN_K8S_SECRET__AZURE_SERVICE_PRINCIPAL_ID", + "valueFrom": { + "secretKeyRef": { + "key": "AZURE_SERVICE_PRINCIPAL_ID", + "name": "mlrun-project-secrets-azureml-admin" + } + } + }, + { + "name": "MLRUN_K8S_SECRET__AZURE_SERVICE_PRINCIPAL_PASSWORD", + "valueFrom": { + "secretKeyRef": { + "key": "AZURE_SERVICE_PRINCIPAL_PASSWORD", + "name": "mlrun-project-secrets-azureml-admin" + } + } + }, + { + "name": "MLRUN_K8S_SECRET__AZURE_STORAGE_CONNECTION_STRING", + "valueFrom": { + "secretKeyRef": { + "key": "AZURE_STORAGE_CONNECTION_STRING", + "name": "mlrun-project-secrets-azureml-admin" + } + } + }, + { + "name": "MLRUN_K8S_SECRET__AZURE_SUBSCRIPTION_ID", + "valueFrom": { + "secretKeyRef": { + "key": "AZURE_SUBSCRIPTION_ID", + "name": "mlrun-project-secrets-azureml-admin" + } + } + }, + { + "name": "MLRUN_K8S_SECRET__AZURE_TENANT_ID", + "valueFrom": { + "secretKeyRef": { + "key": "AZURE_TENANT_ID", + "name": "mlrun-project-secrets-azureml-admin" + } + } + }, + { + "name": "MLRUN_K8S_SECRET__AZURE_WORKSPACE_NAME", + "valueFrom": { + "secretKeyRef": { + "key": "AZURE_WORKSPACE_NAME", + "name": "mlrun-project-secrets-azureml-admin" + } + } + } + ], + "resources": { + "requests": { + "memory": "1Mi", + "cpu": "25m" + }, + "limits": { + "memory": "20Gi", + "cpu": "2" + } + }, + "priority_class_name": "igz-workload-medium", + "preemption_mode": "prevent", + "min_replicas": 1, + "max_replicas": 1, + "config": { + "spec.triggers.monitoring_stream_trigger": { + "kind": "v3ioStream", + "url": "http://v3io-webapi:8081", + "attributes": { + "containerName": "users", + "streamPath": "pipelines/default/model-endpoints/stream", + "consumerGroup": "serving", + "sequenceNumberCommitInterval": "1s", + "workerAllocationMode": "pool", + "sessionTimeout": "10s", + "heartbeatInterval": "3s", + "seekTo": "earliest", + "readBatchSize": 256, + "pollingIntervalMs": 500 }, - { + "name": "monitoring_stream_trigger", + "maxWorkers": 1, + "password": "76ceea19-4b10-47d9-afbb-f687c91b9231" + }, + "metadata.labels.mlrun/class": "serving", + "spec.runtime": "python:3.7", + "spec.serviceType": "ClusterIP", + "spec.resources": { + "requests": { + "memory": "1Mi", + "cpu": "25m" + }, + "limits": { + "memory": "20Gi", + "cpu": "2" + } + }, + "spec.PreemptionMode": "prevent", + "spec.priorityClassName": "igz-workload-medium", + "spec.minReplicas": 1, + "spec.maxReplicas": 1 + }, + "base_spec": { + "apiVersion": "nuclio.io/v1", + "kind": "Function", + "metadata": { + "name": "default-model-monitoring-stream", + "labels": { + "mlrun/class": "serving", + "nuclio.io/project-name": "default" + }, + "annotations": { + "nuclio.io/generated_by": "function generated from /mlrun/mlrun/model_monitoring/stream_processing_fs.py" + } + }, + "spec": { + "runtime": "python:3.7", + "handler": "stream_processing_fs:handler", + "env": [ + { "name": "V3IO_API", "value": "http://v3io-webapi:8081" - }, - { + }, + { "name": "V3IO_USERNAME", "value": "pipelines" - }, - { - "name": "V3IO_ACCESS_KEY", - "valueFrom": { - "secretKeyRef": { - "key": "accessKey", - "name": "mlrun-auth-secrets.27111631aff0f77b2ca9e3f972065f482a58b63645f0afd8d231028f" - } - } - }, - { + }, + { "name": "V3IO_FRAMESD", "value": "http://framesd:8080" - }, - { + }, + { + "name": "MLRUN_DEFAULT_PROJECT", + "value": "azureml-admin" + }, + { + "name": "MLRUN_DBPATH", + "value": "http://mlrun-api:8080" + }, + { + "name": "MLRUN_NAMESPACE", + "value": "default-tenant" + }, + { "name": "MLRUN_AUTH_SESSION", "valueFrom": { - "secretKeyRef": { - "key": "accessKey", - "name": "mlrun-auth-secrets.36ade9f8ae7bddc0fc42b8c701469b8d23268177977bd695c36ed51c" - } + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.36ade9f8ae7bddc0fc42b8c701469b8d23268177977bd695c36ed51c" + } } - }, - { + }, + { + "name": "SERVING_SPEC_ENV", + "value": "{\"function_uri\": \"azureml-admin/model-monitoring-stream\", \"version\": \"v2\", \"parameters\": {\"infer_options\": 0, \"overwrite\": null, \"featureset\": \"store://feature-sets/azureml-admin/monitoring\", \"source\": {\"kind\": \"http\", \"online\": true}, \"targets\": [{\"name\": \"parquet\", \"kind\": \"parquet\", \"path\": \"v3io:///projects/azureml-admin/model-endpoints/parquet\", \"after_step\": \"ProcessBeforeParquet\", \"attributes\": {\"infer_columns_from_data\": true}, \"partitioned\": true, \"key_bucketing_number\": 0, \"time_partitioning_granularity\": \"hour\", \"max_events\": 10000, \"flush_after_seconds\": 1800, \"storage_options\": {\"v3io_access_key\": \"55a0d13c-7d9a-44ab-a556-dd213d8c7165\", \"v3io_api\": \"http://v3io-webapi:8081\"}}]}, \"graph\": {\"steps\": {\"ProcessEndpointEvent\": {\"kind\": \"task\", \"class_name\": \"ProcessEndpointEvent\", \"class_args\": {\"kv_container\": \"users\", \"kv_path\": \"pipelines/azureml-admin/model-endpoints/endpoints/\", \"v3io_access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\"}, \"full_event\": true}, \"filter_none\": {\"kind\": \"task\", \"class_name\": \"storey.Filter\", \"class_args\": {\"_fn\": \"(event is not None)\"}, \"after\": [\"ProcessEndpointEvent\"]}, \"flatten_events\": {\"kind\": \"task\", \"class_name\": \"storey.FlatMap\", \"class_args\": {\"_fn\": \"(event)\"}, \"after\": [\"filter_none\"]}, \"MapFeatureNames\": {\"kind\": \"task\", \"class_name\": \"MapFeatureNames\", \"class_args\": {\"kv_container\": \"users\", \"kv_path\": \"pipelines/azureml-admin/model-endpoints/endpoints/\", \"access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"infer_columns_from_data\": true}, \"after\": [\"flatten_events\"]}, \"Aggregates\": {\"kind\": \"task\", \"class_name\": \"storey.AggregateByKey\", \"class_args\": {\"aggregates\": [{\"name\": \"predictions\", \"column\": \"endpoint_id\", \"operations\": [\"count\"], \"windows\": [\"5m\", \"1h\"], \"period\": \"30s\"}, {\"name\": \"latency\", \"column\": \"latency\", \"operations\": [\"avg\"], \"windows\": [\"5m\", \"1h\"], \"period\": \"30s\"}], \"table\": \".\"}, \"after\": [\"MapFeatureNames\"]}, \"sample\": {\"kind\": \"task\", \"class_name\": \"storey.steps.SampleWindow\", \"class_args\": {\"window_size\": 10, \"key\": \"endpoint_id\"}, \"after\": [\"Aggregates\"]}, \"ProcessBeforeKV\": {\"kind\": \"task\", \"class_name\": \"ProcessBeforeKV\", \"after\": [\"sample\"]}, \"WriteToKV\": {\"kind\": \"task\", \"class_name\": \"WriteToKV\", \"class_args\": {\"container\": \"users\", \"table\": \"pipelines/azureml-admin/model-endpoints/endpoints/\"}, \"after\": [\"ProcessBeforeKV\"]}, \"InferSchema\": {\"kind\": \"task\", \"class_name\": \"InferSchema\", \"class_args\": {\"v3io_access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"v3io_framesd\": \"http://framesd:8080\", \"container\": \"users\", \"table\": \"pipelines/azureml-admin/model-endpoints/endpoints/\"}, \"after\": [\"WriteToKV\"]}, \"ProcessBeforeTSDB\": {\"kind\": \"task\", \"class_name\": \"ProcessBeforeTSDB\", \"after\": [\"sample\"]}, \"FilterAndUnpackKeys1\": {\"kind\": \"task\", \"class_name\": \"FilterAndUnpackKeys\", \"class_args\": {\"keys\": [\"base_metrics\"]}, \"after\": [\"ProcessBeforeTSDB\"]}, \"tsdb1\": {\"kind\": \"task\", \"class_name\": \"storey.TSDBTarget\", \"class_args\": {\"path\": \"users/pipelines/azureml-admin/model-endpoints/events/\", \"rate\": \"10/m\", \"time_col\": \"timestamp\", \"container\": \"users\", \"access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"v3io_frames\": \"http://framesd:8080\", \"index_cols\": [\"endpoint_id\", \"record_type\"], \"max_events\": 10, \"timeout_secs\": 300, \"key\": \"endpoint_id\"}, \"after\": [\"FilterAndUnpackKeys1\"]}, \"FilterAndUnpackKeys2\": {\"kind\": \"task\", \"class_name\": \"FilterAndUnpackKeys\", \"class_args\": {\"keys\": [\"endpoint_features\"]}, \"after\": [\"ProcessBeforeTSDB\"]}, \"tsdb2\": {\"kind\": \"task\", \"class_name\": \"storey.TSDBTarget\", \"class_args\": {\"path\": \"users/pipelines/azureml-admin/model-endpoints/events/\", \"rate\": \"10/m\", \"time_col\": \"timestamp\", \"container\": \"users\", \"access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"v3io_frames\": \"http://framesd:8080\", \"index_cols\": [\"endpoint_id\", \"record_type\"], \"max_events\": 10, \"timeout_secs\": 300, \"key\": \"endpoint_id\"}, \"after\": [\"FilterAndUnpackKeys2\"]}, \"FilterAndUnpackKeys3\": {\"kind\": \"task\", \"class_name\": \"FilterAndUnpackKeys\", \"class_args\": {\"keys\": [\"custom_metrics\"]}, \"after\": [\"ProcessBeforeTSDB\"]}, \"FilterNotNone\": {\"kind\": \"task\", \"class_name\": \"storey.Filter\", \"class_args\": {\"_fn\": \"(event is not None)\"}, \"after\": [\"FilterAndUnpackKeys3\"]}, \"tsdb3\": {\"kind\": \"task\", \"class_name\": \"storey.TSDBTarget\", \"class_args\": {\"path\": \"users/pipelines/azureml-admin/model-endpoints/events/\", \"rate\": \"10/m\", \"time_col\": \"timestamp\", \"container\": \"users\", \"access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"v3io_frames\": \"http://framesd:8080\", \"index_cols\": [\"endpoint_id\", \"record_type\"], \"max_events\": 10, \"timeout_secs\": 300, \"key\": \"endpoint_id\"}, \"after\": [\"FilterNotNone\"]}, \"ProcessBeforeParquet\": {\"kind\": \"task\", \"class_name\": \"ProcessBeforeParquet\", \"class_args\": {\"_fn\": \"(event)\"}, \"after\": [\"MapFeatureNames\"]}}, \"final_step\": \"ProcessBeforeParquet\"}, \"load_mode\": null, \"functions\": {}, \"graph_initializer\": \"mlrun.feature_store.ingestion.featureset_initializer\", \"error_stream\": null, \"track_models\": null, \"default_content_type\": null}" + }, + { + "name": "MODEL_MONITORING_ACCESS_KEY", + "valueFrom": { + "secretKeyRef": { + "key": "mlrun.model-monitoring.MODEL_MONITORING_ACCESS_KEY", + "name": "mlrun-project-secrets-default" + } + } + }, + { + "name": "V3IO_ACCESS_KEY", + "valueFrom": { + "secretKeyRef": { + "key": "accessKey", + "name": "mlrun-auth-secrets.27111631aff0f77b2ca9e3f972065f482a58b63645f0afd8d231028f" + } + } + }, + { "name": "MLRUN_K8S_SECRET__AZURE_RESOURCE_GROUP", "valueFrom": { - "secretKeyRef": { - "key": "AZURE_RESOURCE_GROUP", - "name": "mlrun-project-secrets-azureml-admin" - } + "secretKeyRef": { + "key": "AZURE_RESOURCE_GROUP", + "name": "mlrun-project-secrets-default" + } } - }, - { + }, + { "name": "MLRUN_K8S_SECRET__AZURE_SERVICE_PRINCIPAL_ID", "valueFrom": { - "secretKeyRef": { - "key": "AZURE_SERVICE_PRINCIPAL_ID", - "name": "mlrun-project-secrets-azureml-admin" - } + "secretKeyRef": { + "key": "AZURE_SERVICE_PRINCIPAL_ID", + "name": "mlrun-project-secrets-default" + } } - }, - { + }, + { "name": "MLRUN_K8S_SECRET__AZURE_SERVICE_PRINCIPAL_PASSWORD", "valueFrom": { - "secretKeyRef": { - "key": "AZURE_SERVICE_PRINCIPAL_PASSWORD", - "name": "mlrun-project-secrets-azureml-admin" - } + "secretKeyRef": { + "key": "AZURE_SERVICE_PRINCIPAL_PASSWORD", + "name": "mlrun-project-secrets-default" + } } - }, - { + }, + { "name": "MLRUN_K8S_SECRET__AZURE_STORAGE_CONNECTION_STRING", "valueFrom": { - "secretKeyRef": { - "key": "AZURE_STORAGE_CONNECTION_STRING", - "name": "mlrun-project-secrets-azureml-admin" - } + "secretKeyRef": { + "key": "AZURE_STORAGE_CONNECTION_STRING", + "name": "mlrun-project-secrets-default" + } } - }, - { + }, + { "name": "MLRUN_K8S_SECRET__AZURE_SUBSCRIPTION_ID", "valueFrom": { - "secretKeyRef": { - "key": "AZURE_SUBSCRIPTION_ID", - "name": "mlrun-project-secrets-azureml-admin" - } + "secretKeyRef": { + "key": "AZURE_SUBSCRIPTION_ID", + "name": "mlrun-project-secrets-default" + } } - }, - { + }, + { "name": "MLRUN_K8S_SECRET__AZURE_TENANT_ID", "valueFrom": { - "secretKeyRef": { - "key": "AZURE_TENANT_ID", - "name": "mlrun-project-secrets-azureml-admin" - } + "secretKeyRef": { + "key": "AZURE_TENANT_ID", + "name": "mlrun-project-secrets-default" + } } - }, - { + }, + { "name": "MLRUN_K8S_SECRET__AZURE_WORKSPACE_NAME", "valueFrom": { - "secretKeyRef": { - "key": "AZURE_WORKSPACE_NAME", - "name": "mlrun-project-secrets-azureml-admin" - } + "secretKeyRef": { + "key": "AZURE_WORKSPACE_NAME", + "name": "mlrun-project-secrets-default" + } } - } - ], - "resources": { - "requests": { - "memory": "1Mi", - "cpu": "25m" + } + ], + "volumes": [], + "build": { + "commands": [], + "noBaseImagesPull": true, + "functionSourceCode": "aW1wb3J0IGpzb24KaW1wb3J0IG9zCmZyb20gY29sbGVjdGlvbnMgaW1wb3J0IGRlZmF1bHRkaWN0CmZyb20gb3MgaW1wb3J0IGVudmlyb24KZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgRGljdCwgTGlzdCwgT3B0aW9uYWwsIFNldCwgVW5pb24KCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IHYzaW8KCiMgQ29uc3RhbnRzCmZyb20gc3RvcmV5IGltcG9ydCBFdmVudApmcm9tIHYzaW8uZGF0YXBsYW5lIGltcG9ydCBSYWlzZUZvclN0YXR1cwoKaW1wb3J0IG1scnVuLmZlYXR1cmVfc3RvcmUgYXMgZnMKZnJvbSBtbHJ1bi5jb25maWcgaW1wb3J0IGNvbmZpZwpmcm9tIG1scnVuLmRhdGFzdG9yZS50YXJnZXRzIGltcG9ydCBQYXJxdWV0VGFyZ2V0CmZyb20gbWxydW4uZmVhdHVyZV9zdG9yZS5zdGVwcyBpbXBvcnQgTWFwQ2xhc3MKZnJvbSBtbHJ1bi51dGlscyBpbXBvcnQgbG9nZ2VyCmZyb20gbWxydW4udXRpbHMubW9kZWxfbW9uaXRvcmluZyBpbXBvcnQgKAogICAgY3JlYXRlX21vZGVsX2VuZHBvaW50X2lkLAogICAgcGFyc2VfbW9kZWxfZW5kcG9pbnRfc3RvcmVfcHJlZml4LAopCmZyb20gbWxydW4udXRpbHMudjNpb19jbGllbnRzIGltcG9ydCBnZXRfZnJhbWVzX2NsaWVudCwgZ2V0X3YzaW9fY2xpZW50CgpJU09fODA2MV9VVEMgPSAiJVktJW0tJWQgJUg6JU06JVMuJWYleiIKRlVOQ1RJT05fVVJJID0gImZ1bmN0aW9uX3VyaSIKTU9ERUwgPSAibW9kZWwiClZFUlNJT04gPSAidmVyc2lvbiIKVkVSU0lPTkVEX01PREVMID0gInZlcnNpb25lZF9tb2RlbCIKTU9ERUxfQ0xBU1MgPSAibW9kZWxfY2xhc3MiClRJTUVTVEFNUCA9ICJ0aW1lc3RhbXAiCkVORFBPSU5UX0lEID0gImVuZHBvaW50X2lkIgpSRVFVRVNUX0lEID0gInJlcXVlc3RfaWQiCkxBQkVMUyA9ICJsYWJlbHMiClVOUEFDS0VEX0xBQkVMUyA9ICJ1bnBhY2tlZF9sYWJlbHMiCkxBVEVOQ1lfQVZHXzVNID0gImxhdGVuY3lfYXZnXzVtIgpMQVRFTkNZX0FWR18xSCA9ICJsYXRlbmN5X2F2Z18xaCIKUFJFRElDVElPTlNfUEVSX1NFQ09ORCA9ICJwcmVkaWN0aW9uc19wZXJfc2Vjb25kIgpQUkVESUNUSU9OU19DT1VOVF81TSA9ICJwcmVkaWN0aW9uc19jb3VudF81bSIKUFJFRElDVElPTlNfQ09VTlRfMUggPSAicHJlZGljdGlvbnNfY291bnRfMWgiCkZJUlNUX1JFUVVFU1QgPSAiZmlyc3RfcmVxdWVzdCIKTEFTVF9SRVFVRVNUID0gImxhc3RfcmVxdWVzdCIKRVJST1JfQ09VTlQgPSAiZXJyb3JfY291bnQiCkVOVElUSUVTID0gImVudGl0aWVzIgpGRUFUVVJFX05BTUVTID0gImZlYXR1cmVfbmFtZXMiCkxBQkVMX0NPTFVNTlMgPSAibGFiZWxfY29sdW1ucyIKTEFURU5DWSA9ICJsYXRlbmN5IgpSRUNPUkRfVFlQRSA9ICJyZWNvcmRfdHlwZSIKRkVBVFVSRVMgPSAiZmVhdHVyZXMiClBSRURJQ1RJT04gPSAicHJlZGljdGlvbiIKUFJFRElDVElPTlMgPSAicHJlZGljdGlvbnMiCk5BTUVEX0ZFQVRVUkVTID0gIm5hbWVkX2ZlYXR1cmVzIgpOQU1FRF9QUkVESUNUSU9OUyA9ICJuYW1lZF9wcmVkaWN0aW9ucyIKQkFTRV9NRVRSSUNTID0gImJhc2VfbWV0cmljcyIKQ1VTVE9NX01FVFJJQ1MgPSAiY3VzdG9tX21ldHJpY3MiCkVORFBPSU5UX0ZFQVRVUkVTID0gImVuZHBvaW50X2ZlYXR1cmVzIgpNRVRSSUNTID0gIm1ldHJpY3MiCkJBVENIX1RJTUVTVEFNUCA9ICJiYXRjaF90aW1lc3RhbXAiClRJTUVfRk9STUFUOiBzdHIgPSAiJVktJW0tJWQgJUg6JU06JVMuJWYiICAjIElTTyA4MDYxCgoKIyBTdHJlYW0gcHJvY2Vzc2luZyBjb2RlCmNsYXNzIEV2ZW50U3RyZWFtUHJvY2Vzc29yOgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgcHJvamVjdDogc3RyLAogICAgICAgIHBhcnF1ZXRfYmF0Y2hpbmdfbWF4X2V2ZW50czogaW50LAogICAgICAgIHNhbXBsZV93aW5kb3c6IGludCA9IDEwLAogICAgICAgIHRzZGJfYmF0Y2hpbmdfbWF4X2V2ZW50czogaW50ID0gMTAsCiAgICAgICAgdHNkYl9iYXRjaGluZ190aW1lb3V0X3NlY3M6IGludCA9IDYwICogNSwgICMgRGVmYXVsdCA1IG1pbnV0ZXMKICAgICAgICBwYXJxdWV0X2JhdGNoaW5nX3RpbWVvdXRfc2VjczogaW50ID0gMzAgKiA2MCwgICMgRGVmYXVsdCAzMCBtaW51dGVzCiAgICAgICAgYWdncmVnYXRlX2NvdW50X3dpbmRvd3M6IE9wdGlvbmFsW0xpc3Rbc3RyXV0gPSBOb25lLAogICAgICAgIGFnZ3JlZ2F0ZV9jb3VudF9wZXJpb2Q6IHN0ciA9ICIzMHMiLAogICAgICAgIGFnZ3JlZ2F0ZV9hdmdfd2luZG93czogT3B0aW9uYWxbTGlzdFtzdHJdXSA9IE5vbmUsCiAgICAgICAgYWdncmVnYXRlX2F2Z19wZXJpb2Q6IHN0ciA9ICIzMHMiLAogICAgICAgIHYzaW9fYWNjZXNzX2tleTogT3B0aW9uYWxbc3RyXSA9IE5vbmUsCiAgICAgICAgdjNpb19mcmFtZXNkOiBPcHRpb25hbFtzdHJdID0gTm9uZSwKICAgICAgICB2M2lvX2FwaTogT3B0aW9uYWxbc3RyXSA9IE5vbmUsCiAgICAgICAgbW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5OiBzdHIgPSBOb25lLAogICAgKToKICAgICAgICBzZWxmLnByb2plY3QgPSBwcm9qZWN0CiAgICAgICAgc2VsZi5zYW1wbGVfd2luZG93ID0gc2FtcGxlX3dpbmRvdwogICAgICAgIHNlbGYudHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzID0gdHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzCiAgICAgICAgc2VsZi50c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjcyA9IHRzZGJfYmF0Y2hpbmdfdGltZW91dF9zZWNzCiAgICAgICAgc2VsZi5wYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMgPSBwYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMKICAgICAgICBzZWxmLnBhcnF1ZXRfYmF0Y2hpbmdfdGltZW91dF9zZWNzID0gcGFycXVldF9iYXRjaGluZ190aW1lb3V0X3NlY3MKICAgICAgICBzZWxmLmFnZ3JlZ2F0ZV9jb3VudF93aW5kb3dzID0gYWdncmVnYXRlX2NvdW50X3dpbmRvd3Mgb3IgWyI1bSIsICIxaCJdCiAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfcGVyaW9kID0gYWdncmVnYXRlX2NvdW50X3BlcmlvZAogICAgICAgIHNlbGYuYWdncmVnYXRlX2F2Z193aW5kb3dzID0gYWdncmVnYXRlX2F2Z193aW5kb3dzIG9yIFsiNW0iLCAiMWgiXQogICAgICAgIHNlbGYuYWdncmVnYXRlX2F2Z19wZXJpb2QgPSBhZ2dyZWdhdGVfYXZnX3BlcmlvZAoKICAgICAgICBzZWxmLnYzaW9fZnJhbWVzZCA9IHYzaW9fZnJhbWVzZCBvciBjb25maWcudjNpb19mcmFtZXNkCiAgICAgICAgc2VsZi52M2lvX2FwaSA9IHYzaW9fYXBpIG9yIGNvbmZpZy52M2lvX2FwaQoKICAgICAgICBzZWxmLnYzaW9fYWNjZXNzX2tleSA9IHYzaW9fYWNjZXNzX2tleSBvciBlbnZpcm9uLmdldCgiVjNJT19BQ0NFU1NfS0VZIikKICAgICAgICBzZWxmLm1vZGVsX21vbml0b3JpbmdfYWNjZXNzX2tleSA9ICgKICAgICAgICAgICAgbW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5CiAgICAgICAgICAgIG9yIG9zLmVudmlyb24uZ2V0KCJNT0RFTF9NT05JVE9SSU5HX0FDQ0VTU19LRVkiKQogICAgICAgICAgICBvciBzZWxmLnYzaW9fYWNjZXNzX2tleQogICAgICAgICkKCiAgICAgICAgdGVtcGxhdGUgPSBjb25maWcubW9kZWxfZW5kcG9pbnRfbW9uaXRvcmluZy5zdG9yZV9wcmVmaXhlcy5kZWZhdWx0CgogICAgICAgIGt2X3BhdGggPSB0ZW1wbGF0ZS5mb3JtYXQocHJvamVjdD1wcm9qZWN0LCBraW5kPSJlbmRwb2ludHMiKQogICAgICAgIF8sIHNlbGYua3ZfY29udGFpbmVyLCBzZWxmLmt2X3BhdGggPSBwYXJzZV9tb2RlbF9lbmRwb2ludF9zdG9yZV9wcmVmaXgoa3ZfcGF0aCkKCiAgICAgICAgdHNkYl9wYXRoID0gdGVtcGxhdGUuZm9ybWF0KHByb2plY3Q9cHJvamVjdCwga2luZD0iZXZlbnRzIikKICAgICAgICBfLCBzZWxmLnRzZGJfY29udGFpbmVyLCBzZWxmLnRzZGJfcGF0aCA9IHBhcnNlX21vZGVsX2VuZHBvaW50X3N0b3JlX3ByZWZpeCgKICAgICAgICAgICAgdHNkYl9wYXRoCiAgICAgICAgKQogICAgICAgIHNlbGYudHNkYl9wYXRoID0gZiJ7c2VsZi50c2RiX2NvbnRhaW5lcn0ve3NlbGYudHNkYl9wYXRofSIKCiAgICAgICAgc2VsZi5wYXJxdWV0X3BhdGggPSAoCiAgICAgICAgICAgIGNvbmZpZy5tb2RlbF9lbmRwb2ludF9tb25pdG9yaW5nLnN0b3JlX3ByZWZpeGVzLnVzZXJfc3BhY2UuZm9ybWF0KAogICAgICAgICAgICAgICAgcHJvamVjdD1wcm9qZWN0LCBraW5kPSJwYXJxdWV0IgogICAgICAgICAgICApCiAgICAgICAgKQoKICAgICAgICBsb2dnZXIuaW5mbygKICAgICAgICAgICAgIkluaXRpYWxpemluZyBtb2RlbCBtb25pdG9yaW5nIGV2ZW50IHN0cmVhbSBwcm9jZXNzb3IiLAogICAgICAgICAgICBwYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHM9c2VsZi5wYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMsCiAgICAgICAgICAgIHYzaW9fYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgbW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5PXNlbGYubW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5LAogICAgICAgICAgICBkZWZhdWx0X3N0b3JlX3ByZWZpeD1jb25maWcubW9kZWxfZW5kcG9pbnRfbW9uaXRvcmluZy5zdG9yZV9wcmVmaXhlcy5kZWZhdWx0LAogICAgICAgICAgICB1c2VyX3NwYWNlX3N0b3JlX3ByZWZpeD1jb25maWcubW9kZWxfZW5kcG9pbnRfbW9uaXRvcmluZy5zdG9yZV9wcmVmaXhlcy51c2VyX3NwYWNlLAogICAgICAgICAgICB2M2lvX2FwaT1zZWxmLnYzaW9fYXBpLAogICAgICAgICAgICB2M2lvX2ZyYW1lc2Q9c2VsZi52M2lvX2ZyYW1lc2QsCiAgICAgICAgICAgIGt2X2NvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgIHRzZGJfY29udGFpbmVyPXNlbGYudHNkYl9jb250YWluZXIsCiAgICAgICAgICAgIHRzZGJfcGF0aD1zZWxmLnRzZGJfcGF0aCwKICAgICAgICAgICAgcGFycXVldF9wYXRoPXNlbGYucGFycXVldF9wYXRoLAogICAgICAgICkKCiAgICBkZWYgY3JlYXRlX2ZlYXR1cmVfc2V0KHNlbGYpOgogICAgICAgIGZlYXR1cmVfc2V0ID0gZnMuRmVhdHVyZVNldCgKICAgICAgICAgICAgIm1vbml0b3JpbmciLCBlbnRpdGllcz1bRU5EUE9JTlRfSURdLCB0aW1lc3RhbXBfa2V5PVRJTUVTVEFNUAogICAgICAgICkKICAgICAgICBmZWF0dXJlX3NldC5tZXRhZGF0YS5wcm9qZWN0ID0gc2VsZi5wcm9qZWN0CiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGgudG8oCiAgICAgICAgICAgICJQcm9jZXNzRW5kcG9pbnRFdmVudCIsCiAgICAgICAgICAgIGt2X2NvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgIHYzaW9fYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgZnVsbF9ldmVudD1UcnVlLAogICAgICAgICkudG8oInN0b3JleS5GaWx0ZXIiLCAiZmlsdGVyX25vbmUiLCBfZm49IihldmVudCBpcyBub3QgTm9uZSkiKS50bygKICAgICAgICAgICAgInN0b3JleS5GbGF0TWFwIiwgImZsYXR0ZW5fZXZlbnRzIiwgX2ZuPSIoZXZlbnQpIgogICAgICAgICkudG8oCiAgICAgICAgICAgICJNYXBGZWF0dXJlTmFtZXMiLAogICAgICAgICAgICBuYW1lPSJNYXBGZWF0dXJlTmFtZXMiLAogICAgICAgICAgICBrdl9jb250YWluZXI9c2VsZi5rdl9jb250YWluZXIsCiAgICAgICAgICAgIGt2X3BhdGg9c2VsZi5rdl9wYXRoLAogICAgICAgICAgICBhY2Nlc3Nfa2V5PXNlbGYudjNpb19hY2Nlc3Nfa2V5LAogICAgICAgICAgICBpbmZlcl9jb2x1bW5zX2Zyb21fZGF0YT1UcnVlLAogICAgICAgICkKICAgICAgICAjIGt2IGFuZCB0c2RiIGJyYW5jaAogICAgICAgIGZlYXR1cmVfc2V0LmFkZF9hZ2dyZWdhdGlvbigKICAgICAgICAgICAgRU5EUE9JTlRfSUQsCiAgICAgICAgICAgIFsiY291bnQiXSwKICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfd2luZG93cywKICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfcGVyaW9kLAogICAgICAgICAgICBuYW1lPVBSRURJQ1RJT05TLAogICAgICAgICAgICBhZnRlcj0iTWFwRmVhdHVyZU5hbWVzIiwKICAgICAgICAgICAgc3RlcF9uYW1lPSJBZ2dyZWdhdGVzIiwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuYWRkX2FnZ3JlZ2F0aW9uKAogICAgICAgICAgICBMQVRFTkNZLAogICAgICAgICAgICBbImF2ZyJdLAogICAgICAgICAgICBzZWxmLmFnZ3JlZ2F0ZV9hdmdfd2luZG93cywKICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfYXZnX3BlcmlvZCwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJzdG9yZXkuc3RlcHMuU2FtcGxlV2luZG93IiwKICAgICAgICAgICAgbmFtZT0ic2FtcGxlIiwKICAgICAgICAgICAgYWZ0ZXI9IkFnZ3JlZ2F0ZXMiLAogICAgICAgICAgICB3aW5kb3dfc2l6ZT1zZWxmLnNhbXBsZV93aW5kb3csCiAgICAgICAgICAgIGtleT1FTkRQT0lOVF9JRCwKICAgICAgICApCiAgICAgICAgIyBrdgogICAgICAgIGZlYXR1cmVfc2V0LmdyYXBoLmFkZF9zdGVwKAogICAgICAgICAgICAiUHJvY2Vzc0JlZm9yZUtWIiwgbmFtZT0iUHJvY2Vzc0JlZm9yZUtWIiwgYWZ0ZXI9InNhbXBsZSIKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJXcml0ZVRvS1YiLAogICAgICAgICAgICBuYW1lPSJXcml0ZVRvS1YiLAogICAgICAgICAgICBhZnRlcj0iUHJvY2Vzc0JlZm9yZUtWIiwKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICB0YWJsZT1zZWxmLmt2X3BhdGgsCiAgICAgICAgKQogICAgICAgIGZlYXR1cmVfc2V0LmdyYXBoLmFkZF9zdGVwKAogICAgICAgICAgICAiSW5mZXJTY2hlbWEiLAogICAgICAgICAgICBuYW1lPSJJbmZlclNjaGVtYSIsCiAgICAgICAgICAgIGFmdGVyPSJXcml0ZVRvS1YiLAogICAgICAgICAgICB2M2lvX2FjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgIHYzaW9fZnJhbWVzZD1zZWxmLnYzaW9fZnJhbWVzZCwKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICB0YWJsZT1zZWxmLmt2X3BhdGgsCiAgICAgICAgKQogICAgICAgICMgdHNkYgogICAgICAgIGZlYXR1cmVfc2V0LmdyYXBoLmFkZF9zdGVwKAogICAgICAgICAgICAiUHJvY2Vzc0JlZm9yZVRTREIiLCBuYW1lPSJQcm9jZXNzQmVmb3JlVFNEQiIsIGFmdGVyPSJzYW1wbGUiCiAgICAgICAgKQogICAgICAgIGZlYXR1cmVfc2V0LmdyYXBoLmFkZF9zdGVwKAogICAgICAgICAgICAiRmlsdGVyQW5kVW5wYWNrS2V5cyIsCiAgICAgICAgICAgIG5hbWU9IkZpbHRlckFuZFVucGFja0tleXMxIiwKICAgICAgICAgICAgYWZ0ZXI9IlByb2Nlc3NCZWZvcmVUU0RCIiwKICAgICAgICAgICAga2V5cz1bQkFTRV9NRVRSSUNTXSwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJzdG9yZXkuVFNEQlRhcmdldCIsCiAgICAgICAgICAgIG5hbWU9InRzZGIxIiwKICAgICAgICAgICAgYWZ0ZXI9IkZpbHRlckFuZFVucGFja0tleXMxIiwKICAgICAgICAgICAgcGF0aD1zZWxmLnRzZGJfcGF0aCwKICAgICAgICAgICAgcmF0ZT0iMTAvbSIsCiAgICAgICAgICAgIHRpbWVfY29sPVRJTUVTVEFNUCwKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYudHNkYl9jb250YWluZXIsCiAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgIHYzaW9fZnJhbWVzPXNlbGYudjNpb19mcmFtZXNkLAogICAgICAgICAgICBpbmRleF9jb2xzPVtFTkRQT0lOVF9JRCwgUkVDT1JEX1RZUEVdLAogICAgICAgICAgICBtYXhfZXZlbnRzPXNlbGYudHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzLAogICAgICAgICAgICB0aW1lb3V0X3NlY3M9c2VsZi50c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjcywKICAgICAgICAgICAga2V5PUVORFBPSU5UX0lELAogICAgICAgICkKICAgICAgICBmZWF0dXJlX3NldC5ncmFwaC5hZGRfc3RlcCgKICAgICAgICAgICAgIkZpbHRlckFuZFVucGFja0tleXMiLAogICAgICAgICAgICBuYW1lPSJGaWx0ZXJBbmRVbnBhY2tLZXlzMiIsCiAgICAgICAgICAgIGFmdGVyPSJQcm9jZXNzQmVmb3JlVFNEQiIsCiAgICAgICAgICAgIGtleXM9W0VORFBPSU5UX0ZFQVRVUkVTXSwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJzdG9yZXkuVFNEQlRhcmdldCIsCiAgICAgICAgICAgIG5hbWU9InRzZGIyIiwKICAgICAgICAgICAgYWZ0ZXI9IkZpbHRlckFuZFVucGFja0tleXMyIiwKICAgICAgICAgICAgcGF0aD1zZWxmLnRzZGJfcGF0aCwKICAgICAgICAgICAgcmF0ZT0iMTAvbSIsCiAgICAgICAgICAgIHRpbWVfY29sPVRJTUVTVEFNUCwKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYudHNkYl9jb250YWluZXIsCiAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgIHYzaW9fZnJhbWVzPXNlbGYudjNpb19mcmFtZXNkLAogICAgICAgICAgICBpbmRleF9jb2xzPVtFTkRQT0lOVF9JRCwgUkVDT1JEX1RZUEVdLAogICAgICAgICAgICBtYXhfZXZlbnRzPXNlbGYudHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzLAogICAgICAgICAgICB0aW1lb3V0X3NlY3M9c2VsZi50c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjcywKICAgICAgICAgICAga2V5PUVORFBPSU5UX0lELAogICAgICAgICkKICAgICAgICBmZWF0dXJlX3NldC5ncmFwaC5hZGRfc3RlcCgKICAgICAgICAgICAgIkZpbHRlckFuZFVucGFja0tleXMiLAogICAgICAgICAgICBuYW1lPSJGaWx0ZXJBbmRVbnBhY2tLZXlzMyIsCiAgICAgICAgICAgIGFmdGVyPSJQcm9jZXNzQmVmb3JlVFNEQiIsCiAgICAgICAgICAgIGtleXM9W0NVU1RPTV9NRVRSSUNTXSwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJzdG9yZXkuRmlsdGVyIiwKICAgICAgICAgICAgIkZpbHRlck5vdE5vbmUiLAogICAgICAgICAgICBhZnRlcj0iRmlsdGVyQW5kVW5wYWNrS2V5czMiLAogICAgICAgICAgICBfZm49IihldmVudCBpcyBub3QgTm9uZSkiLAogICAgICAgICkKICAgICAgICBmZWF0dXJlX3NldC5ncmFwaC5hZGRfc3RlcCgKICAgICAgICAgICAgInN0b3JleS5UU0RCVGFyZ2V0IiwKICAgICAgICAgICAgbmFtZT0idHNkYjMiLAogICAgICAgICAgICBhZnRlcj0iRmlsdGVyTm90Tm9uZSIsCiAgICAgICAgICAgIHBhdGg9c2VsZi50c2RiX3BhdGgsCiAgICAgICAgICAgIHJhdGU9IjEwL20iLAogICAgICAgICAgICB0aW1lX2NvbD1USU1FU1RBTVAsCiAgICAgICAgICAgIGNvbnRhaW5lcj1zZWxmLnRzZGJfY29udGFpbmVyLAogICAgICAgICAgICBhY2Nlc3Nfa2V5PXNlbGYudjNpb19hY2Nlc3Nfa2V5LAogICAgICAgICAgICB2M2lvX2ZyYW1lcz1zZWxmLnYzaW9fZnJhbWVzZCwKICAgICAgICAgICAgaW5kZXhfY29scz1bRU5EUE9JTlRfSUQsIFJFQ09SRF9UWVBFXSwKICAgICAgICAgICAgbWF4X2V2ZW50cz1zZWxmLnRzZGJfYmF0Y2hpbmdfbWF4X2V2ZW50cywKICAgICAgICAgICAgdGltZW91dF9zZWNzPXNlbGYudHNkYl9iYXRjaGluZ190aW1lb3V0X3NlY3MsCiAgICAgICAgICAgIGtleT1FTkRQT0lOVF9JRCwKICAgICAgICApCgogICAgICAgICMgcGFycXVldCBicmFuY2gKICAgICAgICBmZWF0dXJlX3NldC5ncmFwaC5hZGRfc3RlcCgKICAgICAgICAgICAgIlByb2Nlc3NCZWZvcmVQYXJxdWV0IiwKICAgICAgICAgICAgbmFtZT0iUHJvY2Vzc0JlZm9yZVBhcnF1ZXQiLAogICAgICAgICAgICBhZnRlcj0iTWFwRmVhdHVyZU5hbWVzIiwKICAgICAgICAgICAgX2ZuPSIoZXZlbnQpIiwKICAgICAgICApCiAgICAgICAgc3RvcmFnZV9vcHRpb25zID0gZGljdCgKICAgICAgICAgICAgdjNpb19hY2Nlc3Nfa2V5PXNlbGYubW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5LCB2M2lvX2FwaT1zZWxmLnYzaW9fYXBpCiAgICAgICAgKQoKICAgICAgICBwcV90YXJnZXQgPSBQYXJxdWV0VGFyZ2V0KAogICAgICAgICAgICBwYXRoPXNlbGYucGFycXVldF9wYXRoLAogICAgICAgICAgICBhZnRlcl9zdGVwPSJQcm9jZXNzQmVmb3JlUGFycXVldCIsCiAgICAgICAgICAgIGtleV9idWNrZXRpbmdfbnVtYmVyPTAsCiAgICAgICAgICAgIHRpbWVfcGFydGl0aW9uaW5nX2dyYW51bGFyaXR5PSJob3VyIiwKICAgICAgICAgICAgbWF4X2V2ZW50cz1zZWxmLnBhcnF1ZXRfYmF0Y2hpbmdfbWF4X2V2ZW50cywKICAgICAgICAgICAgZmx1c2hfYWZ0ZXJfc2Vjb25kcz1zZWxmLnBhcnF1ZXRfYmF0Y2hpbmdfdGltZW91dF9zZWNzLAogICAgICAgICAgICBzdG9yYWdlX29wdGlvbnM9c3RvcmFnZV9vcHRpb25zLAogICAgICAgICAgICBhdHRyaWJ1dGVzPXsiaW5mZXJfY29sdW1uc19mcm9tX2RhdGEiOiBUcnVlfSwKICAgICAgICApCgogICAgICAgIGZlYXR1cmVfc2V0LnNldF90YXJnZXRzKAogICAgICAgICAgICB0YXJnZXRzPVtwcV90YXJnZXRdLAogICAgICAgICAgICB3aXRoX2RlZmF1bHRzPUZhbHNlLAogICAgICAgICAgICBkZWZhdWx0X2ZpbmFsX3N0ZXA9IlByb2Nlc3NCZWZvcmVQYXJxdWV0IiwKICAgICAgICApCiAgICAgICAgcmV0dXJuIGZlYXR1cmVfc2V0CgoKY2xhc3MgUHJvY2Vzc0JlZm9yZUtWKE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQpOgogICAgICAgICMgY29tcHV0ZSBwcmVkaWN0aW9uIHBlciBzZWNvbmQKICAgICAgICBldmVudFtQUkVESUNUSU9OU19QRVJfU0VDT05EXSA9IGZsb2F0KGV2ZW50W1BSRURJQ1RJT05TX0NPVU5UXzVNXSkgLyAzMDAKICAgICAgICAjIEZpbHRlciByZWxldmFudCBrZXlzCiAgICAgICAgZSA9IHsKICAgICAgICAgICAgazogZXZlbnRba10KICAgICAgICAgICAgZm9yIGsgaW4gWwogICAgICAgICAgICAgICAgRlVOQ1RJT05fVVJJLAogICAgICAgICAgICAgICAgTU9ERUwsCiAgICAgICAgICAgICAgICBNT0RFTF9DTEFTUywKICAgICAgICAgICAgICAgIFRJTUVTVEFNUCwKICAgICAgICAgICAgICAgIEVORFBPSU5UX0lELAogICAgICAgICAgICAgICAgTEFCRUxTLAogICAgICAgICAgICAgICAgVU5QQUNLRURfTEFCRUxTLAogICAgICAgICAgICAgICAgTEFURU5DWV9BVkdfNU0sCiAgICAgICAgICAgICAgICBMQVRFTkNZX0FWR18xSCwKICAgICAgICAgICAgICAgIFBSRURJQ1RJT05TX1BFUl9TRUNPTkQsCiAgICAgICAgICAgICAgICBQUkVESUNUSU9OU19DT1VOVF81TSwKICAgICAgICAgICAgICAgIFBSRURJQ1RJT05TX0NPVU5UXzFILAogICAgICAgICAgICAgICAgRklSU1RfUkVRVUVTVCwKICAgICAgICAgICAgICAgIExBU1RfUkVRVUVTVCwKICAgICAgICAgICAgICAgIEVSUk9SX0NPVU5ULAogICAgICAgICAgICBdCiAgICAgICAgfQogICAgICAgICMgVW5wYWNrIGxhYmVscyBkaWN0aW9uYXJ5CiAgICAgICAgZSA9IHsqKmUsICoqZS5wb3AoVU5QQUNLRURfTEFCRUxTLCB7fSl9CiAgICAgICAgIyBXcml0ZSBsYWJlbHMgdG8ga3YgYXMganNvbiBzdHJpbmcgdG8gYmUgcHJlc2VudGFibGUgbGF0ZXIKICAgICAgICBlW0xBQkVMU10gPSBqc29uLmR1bXBzKGVbTEFCRUxTXSkKICAgICAgICByZXR1cm4gZQoKCmNsYXNzIFByb2Nlc3NCZWZvcmVUU0RCKE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQpOgogICAgICAgICMgY29tcHV0ZSBwcmVkaWN0aW9uIHBlciBzZWNvbmQKICAgICAgICBldmVudFtQUkVESUNUSU9OU19QRVJfU0VDT05EXSA9IGZsb2F0KGV2ZW50W1BSRURJQ1RJT05TX0NPVU5UXzVNXSkgLyAzMDAKICAgICAgICBiYXNlX2ZpZWxkcyA9IFtUSU1FU1RBTVAsIEVORFBPSU5UX0lEXQoKICAgICAgICBiYXNlX2V2ZW50ID0ge2s6IGV2ZW50W2tdIGZvciBrIGluIGJhc2VfZmllbGRzfQogICAgICAgIGJhc2VfZXZlbnRbVElNRVNUQU1QXSA9IHBkLnRvX2RhdGV0aW1lKAogICAgICAgICAgICBiYXNlX2V2ZW50W1RJTUVTVEFNUF0sIGZvcm1hdD1USU1FX0ZPUk1BVAogICAgICAgICkKCiAgICAgICAgYmFzZV9tZXRyaWNzID0gewogICAgICAgICAgICBSRUNPUkRfVFlQRTogQkFTRV9NRVRSSUNTLAogICAgICAgICAgICBQUkVESUNUSU9OU19QRVJfU0VDT05EOiBldmVudFtQUkVESUNUSU9OU19QRVJfU0VDT05EXSwKICAgICAgICAgICAgUFJFRElDVElPTlNfQ09VTlRfNU06IGV2ZW50W1BSRURJQ1RJT05TX0NPVU5UXzVNXSwKICAgICAgICAgICAgUFJFRElDVElPTlNfQ09VTlRfMUg6IGV2ZW50W1BSRURJQ1RJT05TX0NPVU5UXzFIXSwKICAgICAgICAgICAgTEFURU5DWV9BVkdfNU06IGV2ZW50W0xBVEVOQ1lfQVZHXzVNXSwKICAgICAgICAgICAgTEFURU5DWV9BVkdfMUg6IGV2ZW50W0xBVEVOQ1lfQVZHXzFIXSwKICAgICAgICAgICAgKipiYXNlX2V2ZW50LAogICAgICAgIH0KCiAgICAgICAgZW5kcG9pbnRfZmVhdHVyZXMgPSB7CiAgICAgICAgICAgIFJFQ09SRF9UWVBFOiBFTkRQT0lOVF9GRUFUVVJFUywKICAgICAgICAgICAgKipldmVudFtOQU1FRF9QUkVESUNUSU9OU10sCiAgICAgICAgICAgICoqZXZlbnRbTkFNRURfRkVBVFVSRVNdLAogICAgICAgICAgICAqKmJhc2VfZXZlbnQsCiAgICAgICAgfQoKICAgICAgICBwcm9jZXNzZWQgPSB7QkFTRV9NRVRSSUNTOiBiYXNlX21ldHJpY3MsIEVORFBPSU5UX0ZFQVRVUkVTOiBlbmRwb2ludF9mZWF0dXJlc30KCiAgICAgICAgaWYgZXZlbnRbTUVUUklDU106CiAgICAgICAgICAgIHByb2Nlc3NlZFtDVVNUT01fTUVUUklDU10gPSB7CiAgICAgICAgICAgICAgICBSRUNPUkRfVFlQRTogQ1VTVE9NX01FVFJJQ1MsCiAgICAgICAgICAgICAgICAqKmV2ZW50W01FVFJJQ1NdLAogICAgICAgICAgICAgICAgKipiYXNlX2V2ZW50LAogICAgICAgICAgICB9CgogICAgICAgIHJldHVybiBwcm9jZXNzZWQKCgpjbGFzcyBQcm9jZXNzQmVmb3JlUGFycXVldChNYXBDbGFzcyk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgKiprd2FyZ3MpOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKiprd2FyZ3MpCgogICAgZGVmIGRvKHNlbGYsIGV2ZW50KToKICAgICAgICBsb2dnZXIuaW5mbygiUHJvY2Vzc0JlZm9yZVBhcnF1ZXQxIiwgZXZlbnQ9ZXZlbnQpCiAgICAgICAgZm9yIGtleSBpbiBbVU5QQUNLRURfTEFCRUxTLCBGRUFUVVJFU106CiAgICAgICAgICAgIGV2ZW50LnBvcChrZXksIE5vbmUpCiAgICAgICAgdmFsdWUgPSBldmVudC5nZXQoImVudGl0aWVzIikKICAgICAgICBpZiB2YWx1ZSBpcyBub3QgTm9uZToKICAgICAgICAgICAgZXZlbnQgPSB7Kip2YWx1ZSwgKipldmVudH0KICAgICAgICBmb3Iga2V5IGluIFtMQUJFTFMsIE1FVFJJQ1MsIEVOVElUSUVTXToKICAgICAgICAgICAgaWYgbm90IGV2ZW50LmdldChrZXkpOgogICAgICAgICAgICAgICAgZXZlbnRba2V5XSA9IE5vbmUKICAgICAgICBsb2dnZXIuaW5mbygiUHJvY2Vzc0JlZm9yZVBhcnF1ZXQyIiwgZXZlbnQ9ZXZlbnQpCiAgICAgICAgcmV0dXJuIGV2ZW50CgoKY2xhc3MgUHJvY2Vzc0VuZHBvaW50RXZlbnQoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGt2X2NvbnRhaW5lcjogc3RyLCBrdl9wYXRoOiBzdHIsIHYzaW9fYWNjZXNzX2tleTogc3RyLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKICAgICAgICBzZWxmLmt2X2NvbnRhaW5lcjogc3RyID0ga3ZfY29udGFpbmVyCiAgICAgICAgc2VsZi5rdl9wYXRoOiBzdHIgPSBrdl9wYXRoCiAgICAgICAgc2VsZi52M2lvX2FjY2Vzc19rZXk6IHN0ciA9IHYzaW9fYWNjZXNzX2tleQogICAgICAgIHNlbGYuZmlyc3RfcmVxdWVzdDogRGljdFtzdHIsIHN0cl0gPSBkaWN0KCkKICAgICAgICBzZWxmLmxhc3RfcmVxdWVzdDogRGljdFtzdHIsIHN0cl0gPSBkaWN0KCkKICAgICAgICBzZWxmLmVycm9yX2NvdW50OiBEaWN0W3N0ciwgaW50XSA9IGRlZmF1bHRkaWN0KGludCkKICAgICAgICBzZWxmLmVuZHBvaW50czogU2V0W3N0cl0gPSBzZXQoKQoKICAgIGRlZiBkbyhzZWxmLCBmdWxsX2V2ZW50KToKICAgICAgICBldmVudCA9IGZ1bGxfZXZlbnQuYm9keQoKICAgICAgICAjIGNvZGUgdGhhdCBjYWxjdWxhdGVzIHRoZSBlbmRwcGludCBpZC4gc2hvdWxkIGJlCiAgICAgICAgZnVuY3Rpb25fdXJpID0gZXZlbnQuZ2V0KEZVTkNUSU9OX1VSSSkKICAgICAgICBpZiBub3QgaXNfbm90X25vbmUoZnVuY3Rpb25fdXJpLCBbRlVOQ1RJT05fVVJJXSk6CiAgICAgICAgICAgIHJldHVybiBOb25lCgogICAgICAgIG1vZGVsID0gZXZlbnQuZ2V0KE1PREVMKQogICAgICAgIGlmIG5vdCBpc19ub3Rfbm9uZShtb2RlbCwgW01PREVMXSk6CiAgICAgICAgICAgIHJldHVybiBOb25lCgogICAgICAgIHZlcnNpb24gPSBldmVudC5nZXQoVkVSU0lPTikKICAgICAgICB2ZXJzaW9uZWRfbW9kZWwgPSBmInttb2RlbH06e3ZlcnNpb259IiBpZiB2ZXJzaW9uIGVsc2UgZiJ7bW9kZWx9OmxhdGVzdCIKCiAgICAgICAgZW5kcG9pbnRfaWQgPSBjcmVhdGVfbW9kZWxfZW5kcG9pbnRfaWQoCiAgICAgICAgICAgIGZ1bmN0aW9uX3VyaT1mdW5jdGlvbl91cmksCiAgICAgICAgICAgIHZlcnNpb25lZF9tb2RlbD12ZXJzaW9uZWRfbW9kZWwsCiAgICAgICAgKQogICAgICAgIGVuZHBvaW50X2lkID0gc3RyKGVuZHBvaW50X2lkKQoKICAgICAgICBldmVudFtWRVJTSU9ORURfTU9ERUxdID0gdmVyc2lvbmVkX21vZGVsCiAgICAgICAgZXZlbnRbRU5EUE9JTlRfSURdID0gZW5kcG9pbnRfaWQKCiAgICAgICAgIyBJbiBjYXNlIHRoaXMgcHJvY2VzcyBmYWlscywgcmVzdW1lIHN0YXRlIGZyb20gZXhpc3RpbmcgcmVjb3JkCiAgICAgICAgc2VsZi5yZXN1bWVfc3RhdGUoZW5kcG9pbnRfaWQpCgogICAgICAgICMgSGFuZGxlIGVycm9ycyBjb21pbmcgZnJvbSBzdHJlYW0KICAgICAgICBmb3VuZF9lcnJvcnMgPSBzZWxmLmhhbmRsZV9lcnJvcnMoZW5kcG9pbnRfaWQsIGV2ZW50KQogICAgICAgIGlmIGZvdW5kX2Vycm9yczoKICAgICAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAgICAgIyBWYWxpZGF0ZSBldmVudCBmaWVsZHMKICAgICAgICBtb2RlbF9jbGFzcyA9IGV2ZW50LmdldCgibW9kZWxfY2xhc3MiKSBvciBldmVudC5nZXQoImNsYXNzIikKICAgICAgICB0aW1lc3RhbXAgPSBldmVudC5nZXQoIndoZW4iKQogICAgICAgIHJlcXVlc3RfaWQgPSBldmVudC5nZXQoInJlcXVlc3QiLCB7fSkuZ2V0KCJpZCIpIG9yIGV2ZW50LmdldCgicmVzcCIsIHt9KS5nZXQoCiAgICAgICAgICAgICJpZCIKICAgICAgICApCiAgICAgICAgbGF0ZW5jeSA9IGV2ZW50LmdldCgibWljcm9zZWMiKQogICAgICAgIGZlYXR1cmVzID0gZXZlbnQuZ2V0KCJyZXF1ZXN0Iiwge30pLmdldCgiaW5wdXRzIikKICAgICAgICBwcmVkaWN0aW9ucyA9IGV2ZW50LmdldCgicmVzcCIsIHt9KS5nZXQoIm91dHB1dHMiKQoKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgZW5kcG9pbnRfaWQsCiAgICAgICAgICAgIGlzX25vdF9ub25lLAogICAgICAgICAgICB0aW1lc3RhbXAsCiAgICAgICAgICAgIFsid2hlbiJdLAogICAgICAgICk6CiAgICAgICAgICAgIHJldHVybiBOb25lCgogICAgICAgIGlmIGVuZHBvaW50X2lkIG5vdCBpbiBzZWxmLmZpcnN0X3JlcXVlc3Q6CiAgICAgICAgICAgIHNlbGYuZmlyc3RfcmVxdWVzdFtlbmRwb2ludF9pZF0gPSB0aW1lc3RhbXAKICAgICAgICBzZWxmLmxhc3RfcmVxdWVzdFtlbmRwb2ludF9pZF0gPSB0aW1lc3RhbXAKCiAgICAgICAgaWYgbm90IHNlbGYuaXNfdmFsaWQoCiAgICAgICAgICAgIGVuZHBvaW50X2lkLAogICAgICAgICAgICBpc19ub3Rfbm9uZSwKICAgICAgICAgICAgcmVxdWVzdF9pZCwKICAgICAgICAgICAgWyJyZXF1ZXN0IiwgImlkIl0sCiAgICAgICAgKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgZW5kcG9pbnRfaWQsCiAgICAgICAgICAgIGlzX25vdF9ub25lLAogICAgICAgICAgICBsYXRlbmN5LAogICAgICAgICAgICBbIm1pY3Jvc2VjIl0sCiAgICAgICAgKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgZW5kcG9pbnRfaWQsCiAgICAgICAgICAgIGlzX25vdF9ub25lLAogICAgICAgICAgICBmZWF0dXJlcywKICAgICAgICAgICAgWyJyZXF1ZXN0IiwgImlucHV0cyJdLAogICAgICAgICk6CiAgICAgICAgICAgIHJldHVybiBOb25lCiAgICAgICAgaWYgbm90IHNlbGYuaXNfdmFsaWQoCiAgICAgICAgICAgIGVuZHBvaW50X2lkLAogICAgICAgICAgICBpc19ub3Rfbm9uZSwKICAgICAgICAgICAgcHJlZGljdGlvbnMsCiAgICAgICAgICAgIFsicmVzcCIsICJvdXRwdXRzIl0sCiAgICAgICAgKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAgICAgdW5wYWNrZWRfbGFiZWxzID0ge2YiX3trfSI6IHYgZm9yIGssIHYgaW4gZXZlbnQuZ2V0KExBQkVMUywge30pLml0ZW1zKCl9CgogICAgICAgICMgU2VwYXJhdGUgZWFjaCBtb2RlbCBpbnZvY2F0aW9uIGludG8gc3ViIGV2ZW50cwogICAgICAgIGV2ZW50cyA9IFtdCiAgICAgICAgZm9yIGksIChmZWF0dXJlLCBwcmVkaWN0aW9uKSBpbiBlbnVtZXJhdGUoemlwKGZlYXR1cmVzLCBwcmVkaWN0aW9ucykpOgogICAgICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgICAgIGVuZHBvaW50X2lkLAogICAgICAgICAgICAgICAgc2VsZi5pc19saXN0X29mX251bWVyaWNzLAogICAgICAgICAgICAgICAgZmVhdHVyZSwKICAgICAgICAgICAgICAgIFsicmVxdWVzdCIsICJpbnB1dHMiLCBmIlt7aX1dIl0sCiAgICAgICAgICAgICk6CiAgICAgICAgICAgICAgICByZXR1cm4gTm9uZQoKICAgICAgICAgICAgaWYgbm90IGlzaW5zdGFuY2UocHJlZGljdGlvbiwgbGlzdCk6CiAgICAgICAgICAgICAgICBwcmVkaWN0aW9uID0gW3ByZWRpY3Rpb25dCgogICAgICAgICAgICBldmVudHMuYXBwZW5kKAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIEZVTkNUSU9OX1VSSTogZnVuY3Rpb25fdXJpLAogICAgICAgICAgICAgICAgICAgIE1PREVMOiB2ZXJzaW9uZWRfbW9kZWwsCiAgICAgICAgICAgICAgICAgICAgTU9ERUxfQ0xBU1M6IG1vZGVsX2NsYXNzLAogICAgICAgICAgICAgICAgICAgIFRJTUVTVEFNUDogdGltZXN0YW1wLAogICAgICAgICAgICAgICAgICAgIEVORFBPSU5UX0lEOiBlbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgICAgICBSRVFVRVNUX0lEOiByZXF1ZXN0X2lkLAogICAgICAgICAgICAgICAgICAgIExBVEVOQ1k6IGxhdGVuY3ksCiAgICAgICAgICAgICAgICAgICAgRkVBVFVSRVM6IGZlYXR1cmUsCiAgICAgICAgICAgICAgICAgICAgUFJFRElDVElPTjogcHJlZGljdGlvbiwKICAgICAgICAgICAgICAgICAgICBGSVJTVF9SRVFVRVNUOiBzZWxmLmZpcnN0X3JlcXVlc3RbZW5kcG9pbnRfaWRdLAogICAgICAgICAgICAgICAgICAgIExBU1RfUkVRVUVTVDogc2VsZi5sYXN0X3JlcXVlc3RbZW5kcG9pbnRfaWRdLAogICAgICAgICAgICAgICAgICAgIEVSUk9SX0NPVU5UOiBzZWxmLmVycm9yX2NvdW50W2VuZHBvaW50X2lkXSwKICAgICAgICAgICAgICAgICAgICBMQUJFTFM6IGV2ZW50LmdldChMQUJFTFMsIHt9KSwKICAgICAgICAgICAgICAgICAgICBNRVRSSUNTOiBldmVudC5nZXQoTUVUUklDUywge30pLAogICAgICAgICAgICAgICAgICAgIEVOVElUSUVTOiBldmVudC5nZXQoInJlcXVlc3QiLCB7fSkuZ2V0KEVOVElUSUVTLCB7fSksCiAgICAgICAgICAgICAgICAgICAgVU5QQUNLRURfTEFCRUxTOiB1bnBhY2tlZF9sYWJlbHMsCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKCiAgICAgICAgc3RvcmV5X2V2ZW50ID0gRXZlbnQoYm9keT1ldmVudHMsIGtleT1lbmRwb2ludF9pZCwgdGltZT10aW1lc3RhbXApCiAgICAgICAgcmV0dXJuIHN0b3JleV9ldmVudAoKICAgIGRlZiBpc19saXN0X29mX251bWVyaWNzKAogICAgICAgIHNlbGYsIGZpZWxkOiBMaXN0W1VuaW9uW2ludCwgZmxvYXQsIGRpY3QsIGxpc3RdXSwgZGljdF9wYXRoOiBMaXN0W3N0cl0KICAgICk6CiAgICAgICAgaWYgYWxsKGlzaW5zdGFuY2UoeCwgaW50KSBvciBpc2luc3RhbmNlKHgsIGZsb2F0KSBmb3IgeCBpbiBmaWVsZCk6CiAgICAgICAgICAgIHJldHVybiBUcnVlCiAgICAgICAgbG9nZ2VyLmVycm9yKAogICAgICAgICAgICBmIkxpc3QgZG9lcyBub3QgY29uc2lzdCBvZiBvbmx5IG51bWVyaWMgdmFsdWVzOiB7ZmllbGR9IFtFdmVudCAtPiB7JywnLmpvaW4oZGljdF9wYXRoKX1dIgogICAgICAgICkKICAgICAgICByZXR1cm4gRmFsc2UKCiAgICBkZWYgcmVzdW1lX3N0YXRlKHNlbGYsIGVuZHBvaW50X2lkKToKICAgICAgICAjIE1ha2Ugc3VyZSBwcm9jZXNzIGlzIHJlc3VtYWJsZSwgaWYgcHJvY2VzcyBmYWlscyBmb3IgYW55IHJlYXNvbiwgYmUgYWJsZSB0byBwaWNrIHRoaW5ncyB1cCBjbG9zZSB0byB3aGVyZSB3ZQogICAgICAgICMgbGVmdCB0aGVtCiAgICAgICAgaWYgZW5kcG9pbnRfaWQgbm90IGluIHNlbGYuZW5kcG9pbnRzOgogICAgICAgICAgICBsb2dnZXIuaW5mbygiVHJ5aW5nIHRvIHJlc3VtZSBzdGF0ZSIsIGVuZHBvaW50X2lkPWVuZHBvaW50X2lkKQogICAgICAgICAgICBlbmRwb2ludF9yZWNvcmQgPSBnZXRfZW5kcG9pbnRfcmVjb3JkKAogICAgICAgICAgICAgICAga3ZfY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgICAgICBlbmRwb2ludF9pZD1lbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgZW5kcG9pbnRfcmVjb3JkOgogICAgICAgICAgICAgICAgZmlyc3RfcmVxdWVzdCA9IGVuZHBvaW50X3JlY29yZC5nZXQoRklSU1RfUkVRVUVTVCkKICAgICAgICAgICAgICAgIGlmIGZpcnN0X3JlcXVlc3Q6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5maXJzdF9yZXF1ZXN0W2VuZHBvaW50X2lkXSA9IGZpcnN0X3JlcXVlc3QKICAgICAgICAgICAgICAgIGVycm9yX2NvdW50ID0gZW5kcG9pbnRfcmVjb3JkLmdldChFUlJPUl9DT1VOVCkKICAgICAgICAgICAgICAgIGlmIGVycm9yX2NvdW50OgogICAgICAgICAgICAgICAgICAgIHNlbGYuZXJyb3JfY291bnRbZW5kcG9pbnRfaWRdID0gZXJyb3JfY291bnQKICAgICAgICAgICAgc2VsZi5lbmRwb2ludHMuYWRkKGVuZHBvaW50X2lkKQoKICAgIGRlZiBpc192YWxpZCgKICAgICAgICBzZWxmLCBlbmRwb2ludF9pZDogc3RyLCB2YWxpZGF0aW9uX2Z1bmN0aW9uLCBmaWVsZDogQW55LCBkaWN0X3BhdGg6IExpc3Rbc3RyXQogICAgKToKICAgICAgICBpZiB2YWxpZGF0aW9uX2Z1bmN0aW9uKGZpZWxkLCBkaWN0X3BhdGgpOgogICAgICAgICAgICByZXR1cm4gVHJ1ZQogICAgICAgIHNlbGYuZXJyb3JfY291bnRbZW5kcG9pbnRfaWRdICs9IDEKICAgICAgICByZXR1cm4gRmFsc2UKCiAgICBkZWYgaGFuZGxlX2Vycm9ycyhzZWxmLCBlbmRwb2ludF9pZCwgZXZlbnQpIC0+IGJvb2w6CiAgICAgICAgaWYgImVycm9yIiBpbiBldmVudDoKICAgICAgICAgICAgc2VsZi5lcnJvcl9jb3VudFtlbmRwb2ludF9pZF0gKz0gMQogICAgICAgICAgICByZXR1cm4gVHJ1ZQoKICAgICAgICByZXR1cm4gRmFsc2UKCgpkZWYgZW5yaWNoX2V2ZW5fZGV0YWlscyhldmVudCkgLT4gT3B0aW9uYWxbZGljdF06CiAgICBmdW5jdGlvbl91cmkgPSBldmVudC5nZXQoRlVOQ1RJT05fVVJJKQoKICAgIGlmIG5vdCBpc19ub3Rfbm9uZShmdW5jdGlvbl91cmksIFtGVU5DVElPTl9VUkldKToKICAgICAgICByZXR1cm4gTm9uZQoKICAgIG1vZGVsID0gZXZlbnQuZ2V0KE1PREVMKQogICAgaWYgbm90IGlzX25vdF9ub25lKG1vZGVsLCBbTU9ERUxdKToKICAgICAgICByZXR1cm4gTm9uZQoKICAgIHZlcnNpb24gPSBldmVudC5nZXQoVkVSU0lPTikKICAgIHZlcnNpb25lZF9tb2RlbCA9IGYie21vZGVsfTp7dmVyc2lvbn0iIGlmIHZlcnNpb24gZWxzZSBmInttb2RlbH06bGF0ZXN0IgoKICAgIGVuZHBvaW50X2lkID0gY3JlYXRlX21vZGVsX2VuZHBvaW50X2lkKAogICAgICAgIGZ1bmN0aW9uX3VyaT1mdW5jdGlvbl91cmksCiAgICAgICAgdmVyc2lvbmVkX21vZGVsPXZlcnNpb25lZF9tb2RlbCwKICAgICkKCiAgICBlbmRwb2ludF9pZCA9IHN0cihlbmRwb2ludF9pZCkKCiAgICBldmVudFtWRVJTSU9ORURfTU9ERUxdID0gdmVyc2lvbmVkX21vZGVsCiAgICBldmVudFtFTkRQT0lOVF9JRF0gPSBlbmRwb2ludF9pZAoKICAgIHJldHVybiBldmVudAoKCmRlZiBpc19ub3Rfbm9uZShmaWVsZDogQW55LCBkaWN0X3BhdGg6IExpc3Rbc3RyXSk6CiAgICBpZiBmaWVsZCBpcyBub3QgTm9uZToKICAgICAgICByZXR1cm4gVHJ1ZQogICAgbG9nZ2VyLmVycm9yKAogICAgICAgIGYiRXhwZWN0ZWQgZXZlbnQgZmllbGQgaXMgbWlzc2luZzoge2ZpZWxkfSBbRXZlbnQgLT4geycsJy5qb2luKGRpY3RfcGF0aCl9XSIKICAgICkKICAgIHJldHVybiBGYWxzZQoKCmNsYXNzIEZpbHRlckFuZFVucGFja0tleXMoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGtleXMsICoqa3dhcmdzKToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCoqa3dhcmdzKQogICAgICAgIHNlbGYua2V5cyA9IGtleXMKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQpOgogICAgICAgIG5ld19ldmVudCA9IHt9CiAgICAgICAgZm9yIGtleSBpbiBzZWxmLmtleXM6CiAgICAgICAgICAgIGlmIGtleSBpbiBldmVudDoKICAgICAgICAgICAgICAgIG5ld19ldmVudFtrZXldID0gZXZlbnRba2V5XQogICAgICAgIHVucGFja2VkID0ge30KICAgICAgICBmb3Iga2V5IGluIG5ld19ldmVudC5rZXlzKCk6CiAgICAgICAgICAgIGlmIGtleSBpbiBzZWxmLmtleXM6CiAgICAgICAgICAgICAgICB1bnBhY2tlZCA9IHsqKnVucGFja2VkLCAqKm5ld19ldmVudFtrZXldfQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgdW5wYWNrZWRba2V5XSA9IG5ld19ldmVudFtrZXldCiAgICAgICAgcmV0dXJuIHVucGFja2VkIGlmIHVucGFja2VkIGVsc2UgTm9uZQoKCmNsYXNzIE1hcEZlYXR1cmVOYW1lcyhNYXBDbGFzcyk6CiAgICBkZWYgX19pbml0X18oCiAgICAgICAgc2VsZiwKICAgICAgICBrdl9jb250YWluZXI6IHN0ciwKICAgICAgICBrdl9wYXRoOiBzdHIsCiAgICAgICAgYWNjZXNzX2tleTogc3RyLAogICAgICAgIGluZmVyX2NvbHVtbnNfZnJvbV9kYXRhOiBib29sID0gRmFsc2UsCiAgICAgICAgKiprd2FyZ3MsCiAgICApOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKiprd2FyZ3MpCiAgICAgICAgc2VsZi5rdl9jb250YWluZXIgPSBrdl9jb250YWluZXIKICAgICAgICBzZWxmLmt2X3BhdGggPSBrdl9wYXRoCiAgICAgICAgc2VsZi5hY2Nlc3Nfa2V5ID0gYWNjZXNzX2tleQogICAgICAgIHNlbGYuX2luZmVyX2NvbHVtbnNfZnJvbV9kYXRhID0gaW5mZXJfY29sdW1uc19mcm9tX2RhdGEKICAgICAgICBzZWxmLmZlYXR1cmVfbmFtZXMgPSB7fQogICAgICAgIHNlbGYubGFiZWxfY29sdW1ucyA9IHt9CgogICAgZGVmIF9pbmZlcl9mZWF0dXJlX25hbWVzX2Zyb21fZGF0YShzZWxmLCBldmVudCk6CiAgICAgICAgZm9yIGVuZHBvaW50X2lkIGluIHNlbGYuZmVhdHVyZV9uYW1lczoKICAgICAgICAgICAgaWYgbGVuKHNlbGYuZmVhdHVyZV9uYW1lc1tlbmRwb2ludF9pZF0pID49IGxlbihldmVudFtGRUFUVVJFU10pOgogICAgICAgICAgICAgICAgcmV0dXJuIHNlbGYuZmVhdHVyZV9uYW1lc1tlbmRwb2ludF9pZF0KICAgICAgICByZXR1cm4gTm9uZQoKICAgIGRlZiBfaW5mZXJfbGFiZWxfY29sdW1uc19mcm9tX2RhdGEoc2VsZiwgZXZlbnQpOgogICAgICAgIGZvciBlbmRwb2ludF9pZCBpbiBzZWxmLmxhYmVsX2NvbHVtbnM6CiAgICAgICAgICAgIGlmIGxlbihzZWxmLmxhYmVsX2NvbHVtbnNbZW5kcG9pbnRfaWRdKSA+PSBsZW4oZXZlbnRbUFJFRElDVElPTl0pOgogICAgICAgICAgICAgICAgcmV0dXJuIHNlbGYubGFiZWxfY29sdW1uc1tlbmRwb2ludF9pZF0KICAgICAgICByZXR1cm4gTm9uZQoKICAgIGRlZiBkbyhzZWxmLCBldmVudDogRGljdCk6CiAgICAgICAgZW5kcG9pbnRfaWQgPSBldmVudFtFTkRQT0lOVF9JRF0KCiAgICAgICAgaWYgZW5kcG9pbnRfaWQgbm90IGluIHNlbGYuZmVhdHVyZV9uYW1lczoKICAgICAgICAgICAgZW5kcG9pbnRfcmVjb3JkID0gZ2V0X2VuZHBvaW50X3JlY29yZCgKICAgICAgICAgICAgICAgIGt2X2NvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAgICAgIGt2X3BhdGg9c2VsZi5rdl9wYXRoLAogICAgICAgICAgICAgICAgZW5kcG9pbnRfaWQ9ZW5kcG9pbnRfaWQsCiAgICAgICAgICAgICAgICBhY2Nlc3Nfa2V5PXNlbGYuYWNjZXNzX2tleSwKICAgICAgICAgICAgKQogICAgICAgICAgICBmZWF0dXJlX25hbWVzID0gZW5kcG9pbnRfcmVjb3JkLmdldChGRUFUVVJFX05BTUVTKQogICAgICAgICAgICBmZWF0dXJlX25hbWVzID0ganNvbi5sb2FkcyhmZWF0dXJlX25hbWVzKSBpZiBmZWF0dXJlX25hbWVzIGVsc2UgTm9uZQoKICAgICAgICAgICAgbGFiZWxfY29sdW1ucyA9IGVuZHBvaW50X3JlY29yZC5nZXQoTEFCRUxfQ09MVU1OUykKICAgICAgICAgICAgbGFiZWxfY29sdW1ucyA9IGpzb24ubG9hZHMobGFiZWxfY29sdW1ucykgaWYgbGFiZWxfY29sdW1ucyBlbHNlIE5vbmUKCiAgICAgICAgICAgIGlmIG5vdCBmZWF0dXJlX25hbWVzIGFuZCBzZWxmLl9pbmZlcl9jb2x1bW5zX2Zyb21fZGF0YToKICAgICAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMgPSBzZWxmLl9pbmZlcl9mZWF0dXJlX25hbWVzX2Zyb21fZGF0YShldmVudCkKCiAgICAgICAgICAgIGlmIG5vdCBmZWF0dXJlX25hbWVzOgogICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oCiAgICAgICAgICAgICAgICAgICAgIkZlYXR1cmUgbmFtZXMgYXJlIG5vdCBpbml0aWFsaXplZCwgdGhleSB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIiwKICAgICAgICAgICAgICAgICAgICBlbmRwb2ludF9pZD1lbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMgPSBbZiJme2l9IiBmb3IgaSwgXyBpbiBlbnVtZXJhdGUoZXZlbnRbRkVBVFVSRVNdKV0KICAgICAgICAgICAgICAgIGdldF92M2lvX2NsaWVudCgpLmt2LnVwZGF0ZSgKICAgICAgICAgICAgICAgICAgICBjb250YWluZXI9c2VsZi5rdl9jb250YWluZXIsCiAgICAgICAgICAgICAgICAgICAgdGFibGVfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgICAgICAgICAgYWNjZXNzX2tleT1zZWxmLmFjY2Vzc19rZXksCiAgICAgICAgICAgICAgICAgICAga2V5PWV2ZW50W0VORFBPSU5UX0lEXSwKICAgICAgICAgICAgICAgICAgICBhdHRyaWJ1dGVzPXtGRUFUVVJFX05BTUVTOiBqc29uLmR1bXBzKGZlYXR1cmVfbmFtZXMpfSwKICAgICAgICAgICAgICAgICAgICByYWlzZV9mb3Jfc3RhdHVzPVJhaXNlRm9yU3RhdHVzLmFsd2F5cywKICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgIGlmIG5vdCBsYWJlbF9jb2x1bW5zIGFuZCBzZWxmLl9pbmZlcl9jb2x1bW5zX2Zyb21fZGF0YToKICAgICAgICAgICAgICAgIGxhYmVsX2NvbHVtbnMgPSBzZWxmLl9pbmZlcl9sYWJlbF9jb2x1bW5zX2Zyb21fZGF0YShldmVudCkKCiAgICAgICAgICAgIGlmIG5vdCBsYWJlbF9jb2x1bW5zOgogICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oCiAgICAgICAgICAgICAgICAgICAgImxhYmVsIGNvbHVtbiBuYW1lcyBhcmUgbm90IGluaXRpYWxpemVkLCB0aGV5IHdpbGwgYmUgYXV0b21hdGljYWxseSBnZW5lcmF0ZWQiLAogICAgICAgICAgICAgICAgICAgIGVuZHBvaW50X2lkPWVuZHBvaW50X2lkLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgbGFiZWxfY29sdW1ucyA9IFtmInB7aX0iIGZvciBpLCBfIGluIGVudW1lcmF0ZShldmVudFtQUkVESUNUSU9OXSldCiAgICAgICAgICAgICAgICBnZXRfdjNpb19jbGllbnQoKS5rdi51cGRhdGUoCiAgICAgICAgICAgICAgICAgICAgY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICAgICAgICAgIHRhYmxlX3BhdGg9c2VsZi5rdl9wYXRoLAogICAgICAgICAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi5hY2Nlc3Nfa2V5LAogICAgICAgICAgICAgICAgICAgIGtleT1ldmVudFtFTkRQT0lOVF9JRF0sCiAgICAgICAgICAgICAgICAgICAgYXR0cmlidXRlcz17TEFCRUxfQ09MVU1OUzoganNvbi5kdW1wcyhsYWJlbF9jb2x1bW5zKX0sCiAgICAgICAgICAgICAgICAgICAgcmFpc2VfZm9yX3N0YXR1cz1SYWlzZUZvclN0YXR1cy5hbHdheXMsCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICBzZWxmLmxhYmVsX2NvbHVtbnNbZW5kcG9pbnRfaWRdID0gbGFiZWxfY29sdW1ucwogICAgICAgICAgICBzZWxmLmZlYXR1cmVfbmFtZXNbZW5kcG9pbnRfaWRdID0gZmVhdHVyZV9uYW1lcwoKICAgICAgICAgICAgbG9nZ2VyLmluZm8oCiAgICAgICAgICAgICAgICAiTGFiZWwgY29sdW1ucyIsIGVuZHBvaW50X2lkPWVuZHBvaW50X2lkLCBsYWJlbF9jb2x1bW5zPWxhYmVsX2NvbHVtbnMKICAgICAgICAgICAgKQogICAgICAgICAgICBsb2dnZXIuaW5mbygKICAgICAgICAgICAgICAgICJGZWF0dXJlIG5hbWVzIiwgZW5kcG9pbnRfaWQ9ZW5kcG9pbnRfaWQsIGZlYXR1cmVfbmFtZXM9ZmVhdHVyZV9uYW1lcwogICAgICAgICAgICApCgogICAgICAgIGZlYXR1cmVfbmFtZXMgPSBzZWxmLmZlYXR1cmVfbmFtZXNbZW5kcG9pbnRfaWRdCiAgICAgICAgZmVhdHVyZXMgPSBldmVudFtGRUFUVVJFU10KICAgICAgICBldmVudFtOQU1FRF9GRUFUVVJFU10gPSB7CiAgICAgICAgICAgIG5hbWU6IGZlYXR1cmUgZm9yIG5hbWUsIGZlYXR1cmUgaW4gemlwKGZlYXR1cmVfbmFtZXMsIGZlYXR1cmVzKQogICAgICAgIH0KCiAgICAgICAgbGFiZWxfY29sdW1ucyA9IHNlbGYubGFiZWxfY29sdW1uc1tlbmRwb2ludF9pZF0KICAgICAgICBwcmVkaWN0aW9uID0gZXZlbnRbUFJFRElDVElPTl0KICAgICAgICBldmVudFtOQU1FRF9QUkVESUNUSU9OU10gPSB7CiAgICAgICAgICAgIG5hbWU6IHByZWRpY3Rpb24gZm9yIG5hbWUsIHByZWRpY3Rpb24gaW4gemlwKGxhYmVsX2NvbHVtbnMsIHByZWRpY3Rpb24pCiAgICAgICAgfQogICAgICAgIGxvZ2dlci5pbmZvKCJNYXBwZWQgZXZlbnQiLCBldmVudD1ldmVudCkKICAgICAgICByZXR1cm4gZXZlbnQKCgpjbGFzcyBXcml0ZVRvS1YoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGNvbnRhaW5lcjogc3RyLCB0YWJsZTogc3RyLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKICAgICAgICBzZWxmLmNvbnRhaW5lciA9IGNvbnRhaW5lcgogICAgICAgIHNlbGYudGFibGUgPSB0YWJsZQoKICAgIGRlZiBkbyhzZWxmLCBldmVudDogRGljdCk6CiAgICAgICAgZ2V0X3YzaW9fY2xpZW50KCkua3YudXBkYXRlKAogICAgICAgICAgICBjb250YWluZXI9c2VsZi5jb250YWluZXIsCiAgICAgICAgICAgIHRhYmxlX3BhdGg9c2VsZi50YWJsZSwKICAgICAgICAgICAga2V5PWV2ZW50W0VORFBPSU5UX0lEXSwKICAgICAgICAgICAgYXR0cmlidXRlcz1ldmVudCwKICAgICAgICApCiAgICAgICAgcmV0dXJuIGV2ZW50CgoKY2xhc3MgSW5mZXJTY2hlbWEoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgdjNpb19hY2Nlc3Nfa2V5OiBzdHIsCiAgICAgICAgdjNpb19mcmFtZXNkOiBzdHIsCiAgICAgICAgY29udGFpbmVyOiBzdHIsCiAgICAgICAgdGFibGU6IHN0ciwKICAgICAgICAqKmt3YXJncywKICAgICk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKICAgICAgICBzZWxmLmNvbnRhaW5lciA9IGNvbnRhaW5lcgogICAgICAgIHNlbGYudjNpb19hY2Nlc3Nfa2V5ID0gdjNpb19hY2Nlc3Nfa2V5CiAgICAgICAgc2VsZi52M2lvX2ZyYW1lc2QgPSB2M2lvX2ZyYW1lc2QKICAgICAgICBzZWxmLnRhYmxlID0gdGFibGUKICAgICAgICBzZWxmLmtleXMgPSBzZXQoKQoKICAgIGRlZiBkbyhzZWxmLCBldmVudDogRGljdCk6CiAgICAgICAga2V5X3NldCA9IHNldChldmVudC5rZXlzKCkpCiAgICAgICAgaWYgbm90IGtleV9zZXQuaXNzdWJzZXQoc2VsZi5rZXlzKToKICAgICAgICAgICAgc2VsZi5rZXlzLnVwZGF0ZShrZXlfc2V0KQogICAgICAgICAgICBnZXRfZnJhbWVzX2NsaWVudCgKICAgICAgICAgICAgICAgIHRva2VuPXNlbGYudjNpb19hY2Nlc3Nfa2V5LAogICAgICAgICAgICAgICAgY29udGFpbmVyPXNlbGYuY29udGFpbmVyLAogICAgICAgICAgICAgICAgYWRkcmVzcz1zZWxmLnYzaW9fZnJhbWVzZCwKICAgICAgICAgICAgKS5leGVjdXRlKGJhY2tlbmQ9Imt2IiwgdGFibGU9c2VsZi50YWJsZSwgY29tbWFuZD0iaW5mZXJfc2NoZW1hIikKICAgICAgICAgICAgbG9nZ2VyLmluZm8oCiAgICAgICAgICAgICAgICAiRm91bmQgbmV3IGtleXMsIGluZmVycmVkIHNjaGVtYSIsIHRhYmxlPXNlbGYudGFibGUsIGV2ZW50PWV2ZW50CiAgICAgICAgICAgICkKICAgICAgICByZXR1cm4gZXZlbnQKCgpkZWYgZ2V0X2VuZHBvaW50X3JlY29yZCgKICAgIGt2X2NvbnRhaW5lcjogc3RyLCBrdl9wYXRoOiBzdHIsIGVuZHBvaW50X2lkOiBzdHIsIGFjY2Vzc19rZXk6IHN0cgopIC0+IE9wdGlvbmFsW2RpY3RdOgogICAgbG9nZ2VyLmluZm8oCiAgICAgICAgIkdyYWJiaW5nIGVuZHBvaW50IGRhdGEiLAogICAgICAgIGNvbnRhaW5lcj1rdl9jb250YWluZXIsCiAgICAgICAgdGFibGVfcGF0aD1rdl9wYXRoLAogICAgICAgIGtleT1lbmRwb2ludF9pZCwKICAgICkKICAgIHRyeToKICAgICAgICBlbmRwb2ludF9yZWNvcmQgPSAoCiAgICAgICAgICAgIGdldF92M2lvX2NsaWVudCgpCiAgICAgICAgICAgIC5rdi5nZXQoCiAgICAgICAgICAgICAgICBjb250YWluZXI9a3ZfY29udGFpbmVyLAogICAgICAgICAgICAgICAgdGFibGVfcGF0aD1rdl9wYXRoLAogICAgICAgICAgICAgICAga2V5PWVuZHBvaW50X2lkLAogICAgICAgICAgICAgICAgYWNjZXNzX2tleT1hY2Nlc3Nfa2V5LAogICAgICAgICAgICAgICAgcmFpc2VfZm9yX3N0YXR1cz12M2lvLmRhdGFwbGFuZS5SYWlzZUZvclN0YXR1cy5hbHdheXMsCiAgICAgICAgICAgICkKICAgICAgICAgICAgLm91dHB1dC5pdGVtCiAgICAgICAgKQogICAgICAgIHJldHVybiBlbmRwb2ludF9yZWNvcmQKICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgcmV0dXJuIE5vbmUKCmZyb20gbWxydW4ucnVudGltZXMgaW1wb3J0IG51Y2xpb19pbml0X2hvb2sKZGVmIGluaXRfY29udGV4dChjb250ZXh0KToKICAgIG51Y2xpb19pbml0X2hvb2soY29udGV4dCwgZ2xvYmFscygpLCAnc2VydmluZ192MicpCgpkZWYgaGFuZGxlcihjb250ZXh0LCBldmVudCk6CiAgICByZXR1cm4gY29udGV4dC5tbHJ1bl9oYW5kbGVyKGNvbnRleHQsIGV2ZW50KQo=", + "baseImage": "datanode-registry.iguazio-platform.app.product-3-4.iguazio-cd1.com:80/quay.io/mlrun/mlrun:1.0.0" }, - "limits": { - "memory": "20Gi", - "cpu": "2" - } - }, - "priority_class_name": "igz-workload-medium", - "preemption_mode": "prevent", - "min_replicas": 1, - "max_replicas": 1, - "config": { - "spec.triggers.monitoring_stream_trigger": { + "triggers": { + "monitoring_stream_trigger": { "kind": "v3ioStream", "url": "http://v3io-webapi:8081", "attributes": { - "containerName": "users", - "streamPath": "pipelines/default/model-endpoints/stream", - "consumerGroup": "serving", - "sequenceNumberCommitInterval": "1s", - "workerAllocationMode": "pool", - "sessionTimeout": "10s", - "heartbeatInterval": "3s", - "seekTo": "earliest", - "readBatchSize": 256, - "pollingIntervalMs": 500 + "containerName": "users", + "streamPath": "pipelines/default/model-endpoints/stream", + "consumerGroup": "serving", + "sequenceNumberCommitInterval": "1s", + "workerAllocationMode": "pool", + "sessionTimeout": "10s", + "heartbeatInterval": "3s", + "seekTo": "earliest", + "readBatchSize": 256, + "pollingIntervalMs": 500 }, "name": "monitoring_stream_trigger", "maxWorkers": 1, "password": "76ceea19-4b10-47d9-afbb-f687c91b9231" - }, - "metadata.labels.mlrun/class": "serving", - "spec.runtime": "python:3.7", - "spec.serviceType": "ClusterIP", - "spec.resources": { - "requests": { - "memory": "1Mi", - "cpu": "25m" - }, - "limits": { - "memory": "20Gi", - "cpu": "2" + }, + "http": { + "kind": "http", + "name": "http", + "maxWorkers": 1, + "workerAvailabilityTimeoutMilliseconds": 10000, + "attributes": { + "ingresses": { + "0": { + "paths": [ + "/" + ], + "hostTemplate": "@nuclio.fromDefault" + } + }, + "serviceType": "ClusterIP" } + } }, - "spec.PreemptionMode": "prevent", - "spec.priorityClassName": "igz-workload-medium", - "spec.minReplicas": 1, - "spec.maxReplicas": 1 - }, - "base_spec": { - "apiVersion": "nuclio.io/v1", - "kind": "Function", - "metadata": { - "name": "default-model-monitoring-stream", - "labels": { - "mlrun/class": "serving", - "nuclio.io/project-name": "default" - }, - "annotations": { - "nuclio.io/generated_by": "function generated from /mlrun/mlrun/model_monitoring/stream_processing_fs.py" - } + "serviceType": "ClusterIP", + "resources": { + "requests": { + "memory": "1Mi", + "cpu": "25m" + }, + "limits": { + "memory": "20Gi", + "cpu": "2" + } }, - "spec": { - "runtime": "python:3.7", - "handler": "stream_processing_fs:handler", - "env": [ - { - "name": "V3IO_API", - "value": "http://v3io-webapi:8081" - }, - { - "name": "V3IO_USERNAME", - "value": "pipelines" - }, - { - "name": "V3IO_FRAMESD", - "value": "http://framesd:8080" - }, - { - "name": "MLRUN_DEFAULT_PROJECT", - "value": "azureml-admin" - }, - { - "name": "MLRUN_DBPATH", - "value": "http://mlrun-api:8080" - }, - { - "name": "MLRUN_NAMESPACE", - "value": "default-tenant" - }, - { - "name": "MLRUN_AUTH_SESSION", - "valueFrom": { - "secretKeyRef": { - "key": "accessKey", - "name": "mlrun-auth-secrets.36ade9f8ae7bddc0fc42b8c701469b8d23268177977bd695c36ed51c" - } - } - }, - { - "name": "SERVING_SPEC_ENV", - "value": "{\"function_uri\": \"azureml-admin/model-monitoring-stream\", \"version\": \"v2\", \"parameters\": {\"infer_options\": 0, \"overwrite\": null, \"featureset\": \"store://feature-sets/azureml-admin/monitoring\", \"source\": {\"kind\": \"http\", \"online\": true}, \"targets\": [{\"name\": \"parquet\", \"kind\": \"parquet\", \"path\": \"v3io:///projects/azureml-admin/model-endpoints/parquet\", \"after_step\": \"ProcessBeforeParquet\", \"attributes\": {\"infer_columns_from_data\": true}, \"partitioned\": true, \"key_bucketing_number\": 0, \"time_partitioning_granularity\": \"hour\", \"max_events\": 10000, \"flush_after_seconds\": 1800, \"storage_options\": {\"v3io_access_key\": \"55a0d13c-7d9a-44ab-a556-dd213d8c7165\", \"v3io_api\": \"http://v3io-webapi:8081\"}}]}, \"graph\": {\"steps\": {\"ProcessEndpointEvent\": {\"kind\": \"task\", \"class_name\": \"ProcessEndpointEvent\", \"class_args\": {\"kv_container\": \"users\", \"kv_path\": \"pipelines/azureml-admin/model-endpoints/endpoints/\", \"v3io_access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\"}, \"full_event\": true}, \"filter_none\": {\"kind\": \"task\", \"class_name\": \"storey.Filter\", \"class_args\": {\"_fn\": \"(event is not None)\"}, \"after\": [\"ProcessEndpointEvent\"]}, \"flatten_events\": {\"kind\": \"task\", \"class_name\": \"storey.FlatMap\", \"class_args\": {\"_fn\": \"(event)\"}, \"after\": [\"filter_none\"]}, \"MapFeatureNames\": {\"kind\": \"task\", \"class_name\": \"MapFeatureNames\", \"class_args\": {\"kv_container\": \"users\", \"kv_path\": \"pipelines/azureml-admin/model-endpoints/endpoints/\", \"access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"infer_columns_from_data\": true}, \"after\": [\"flatten_events\"]}, \"Aggregates\": {\"kind\": \"task\", \"class_name\": \"storey.AggregateByKey\", \"class_args\": {\"aggregates\": [{\"name\": \"predictions\", \"column\": \"endpoint_id\", \"operations\": [\"count\"], \"windows\": [\"5m\", \"1h\"], \"period\": \"30s\"}, {\"name\": \"latency\", \"column\": \"latency\", \"operations\": [\"avg\"], \"windows\": [\"5m\", \"1h\"], \"period\": \"30s\"}], \"table\": \".\"}, \"after\": [\"MapFeatureNames\"]}, \"sample\": {\"kind\": \"task\", \"class_name\": \"storey.steps.SampleWindow\", \"class_args\": {\"window_size\": 10, \"key\": \"endpoint_id\"}, \"after\": [\"Aggregates\"]}, \"ProcessBeforeKV\": {\"kind\": \"task\", \"class_name\": \"ProcessBeforeKV\", \"after\": [\"sample\"]}, \"WriteToKV\": {\"kind\": \"task\", \"class_name\": \"WriteToKV\", \"class_args\": {\"container\": \"users\", \"table\": \"pipelines/azureml-admin/model-endpoints/endpoints/\"}, \"after\": [\"ProcessBeforeKV\"]}, \"InferSchema\": {\"kind\": \"task\", \"class_name\": \"InferSchema\", \"class_args\": {\"v3io_access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"v3io_framesd\": \"http://framesd:8080\", \"container\": \"users\", \"table\": \"pipelines/azureml-admin/model-endpoints/endpoints/\"}, \"after\": [\"WriteToKV\"]}, \"ProcessBeforeTSDB\": {\"kind\": \"task\", \"class_name\": \"ProcessBeforeTSDB\", \"after\": [\"sample\"]}, \"FilterAndUnpackKeys1\": {\"kind\": \"task\", \"class_name\": \"FilterAndUnpackKeys\", \"class_args\": {\"keys\": [\"base_metrics\"]}, \"after\": [\"ProcessBeforeTSDB\"]}, \"tsdb1\": {\"kind\": \"task\", \"class_name\": \"storey.TSDBTarget\", \"class_args\": {\"path\": \"users/pipelines/azureml-admin/model-endpoints/events/\", \"rate\": \"10/m\", \"time_col\": \"timestamp\", \"container\": \"users\", \"access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"v3io_frames\": \"http://framesd:8080\", \"index_cols\": [\"endpoint_id\", \"record_type\"], \"max_events\": 10, \"timeout_secs\": 300, \"key\": \"endpoint_id\"}, \"after\": [\"FilterAndUnpackKeys1\"]}, \"FilterAndUnpackKeys2\": {\"kind\": \"task\", \"class_name\": \"FilterAndUnpackKeys\", \"class_args\": {\"keys\": [\"endpoint_features\"]}, \"after\": [\"ProcessBeforeTSDB\"]}, \"tsdb2\": {\"kind\": \"task\", \"class_name\": \"storey.TSDBTarget\", \"class_args\": {\"path\": \"users/pipelines/azureml-admin/model-endpoints/events/\", \"rate\": \"10/m\", \"time_col\": \"timestamp\", \"container\": \"users\", \"access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"v3io_frames\": \"http://framesd:8080\", \"index_cols\": [\"endpoint_id\", \"record_type\"], \"max_events\": 10, \"timeout_secs\": 300, \"key\": \"endpoint_id\"}, \"after\": [\"FilterAndUnpackKeys2\"]}, \"FilterAndUnpackKeys3\": {\"kind\": \"task\", \"class_name\": \"FilterAndUnpackKeys\", \"class_args\": {\"keys\": [\"custom_metrics\"]}, \"after\": [\"ProcessBeforeTSDB\"]}, \"FilterNotNone\": {\"kind\": \"task\", \"class_name\": \"storey.Filter\", \"class_args\": {\"_fn\": \"(event is not None)\"}, \"after\": [\"FilterAndUnpackKeys3\"]}, \"tsdb3\": {\"kind\": \"task\", \"class_name\": \"storey.TSDBTarget\", \"class_args\": {\"path\": \"users/pipelines/azureml-admin/model-endpoints/events/\", \"rate\": \"10/m\", \"time_col\": \"timestamp\", \"container\": \"users\", \"access_key\": \"76ceea19-4b10-47d9-afbb-f687c91b9231\", \"v3io_frames\": \"http://framesd:8080\", \"index_cols\": [\"endpoint_id\", \"record_type\"], \"max_events\": 10, \"timeout_secs\": 300, \"key\": \"endpoint_id\"}, \"after\": [\"FilterNotNone\"]}, \"ProcessBeforeParquet\": {\"kind\": \"task\", \"class_name\": \"ProcessBeforeParquet\", \"class_args\": {\"_fn\": \"(event)\"}, \"after\": [\"MapFeatureNames\"]}}, \"final_step\": \"ProcessBeforeParquet\"}, \"load_mode\": null, \"functions\": {}, \"graph_initializer\": \"mlrun.feature_store.ingestion.featureset_initializer\", \"error_stream\": null, \"track_models\": null, \"default_content_type\": null}" - }, - { - "name": "MODEL_MONITORING_ACCESS_KEY", - "valueFrom": { - "secretKeyRef": { - "key": "mlrun.model-monitoring.MODEL_MONITORING_ACCESS_KEY", - "name": "mlrun-project-secrets-default" - } - } - }, - { - "name": "V3IO_ACCESS_KEY", - "valueFrom": { - "secretKeyRef": { - "key": "accessKey", - "name": "mlrun-auth-secrets.27111631aff0f77b2ca9e3f972065f482a58b63645f0afd8d231028f" - } - } - }, - { - "name": "MLRUN_K8S_SECRET__AZURE_RESOURCE_GROUP", - "valueFrom": { - "secretKeyRef": { - "key": "AZURE_RESOURCE_GROUP", - "name": "mlrun-project-secrets-default" - } - } - }, - { - "name": "MLRUN_K8S_SECRET__AZURE_SERVICE_PRINCIPAL_ID", - "valueFrom": { - "secretKeyRef": { - "key": "AZURE_SERVICE_PRINCIPAL_ID", - "name": "mlrun-project-secrets-default" - } - } - }, - { - "name": "MLRUN_K8S_SECRET__AZURE_SERVICE_PRINCIPAL_PASSWORD", - "valueFrom": { - "secretKeyRef": { - "key": "AZURE_SERVICE_PRINCIPAL_PASSWORD", - "name": "mlrun-project-secrets-default" - } - } - }, - { - "name": "MLRUN_K8S_SECRET__AZURE_STORAGE_CONNECTION_STRING", - "valueFrom": { - "secretKeyRef": { - "key": "AZURE_STORAGE_CONNECTION_STRING", - "name": "mlrun-project-secrets-default" - } - } - }, - { - "name": "MLRUN_K8S_SECRET__AZURE_SUBSCRIPTION_ID", - "valueFrom": { - "secretKeyRef": { - "key": "AZURE_SUBSCRIPTION_ID", - "name": "mlrun-project-secrets-default" - } - } - }, - { - "name": "MLRUN_K8S_SECRET__AZURE_TENANT_ID", - "valueFrom": { - "secretKeyRef": { - "key": "AZURE_TENANT_ID", - "name": "mlrun-project-secrets-default" - } - } - }, - { - "name": "MLRUN_K8S_SECRET__AZURE_WORKSPACE_NAME", - "valueFrom": { - "secretKeyRef": { - "key": "AZURE_WORKSPACE_NAME", - "name": "mlrun-project-secrets-default" - } - } - } - ], - "volumes": [], - "build": { - "commands": [], - "noBaseImagesPull": true, - "functionSourceCode": "aW1wb3J0IGpzb24KaW1wb3J0IG9zCmZyb20gY29sbGVjdGlvbnMgaW1wb3J0IGRlZmF1bHRkaWN0CmZyb20gb3MgaW1wb3J0IGVudmlyb24KZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgRGljdCwgTGlzdCwgT3B0aW9uYWwsIFNldCwgVW5pb24KCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IHYzaW8KCiMgQ29uc3RhbnRzCmZyb20gc3RvcmV5IGltcG9ydCBFdmVudApmcm9tIHYzaW8uZGF0YXBsYW5lIGltcG9ydCBSYWlzZUZvclN0YXR1cwoKaW1wb3J0IG1scnVuLmZlYXR1cmVfc3RvcmUgYXMgZnMKZnJvbSBtbHJ1bi5jb25maWcgaW1wb3J0IGNvbmZpZwpmcm9tIG1scnVuLmRhdGFzdG9yZS50YXJnZXRzIGltcG9ydCBQYXJxdWV0VGFyZ2V0CmZyb20gbWxydW4uZmVhdHVyZV9zdG9yZS5zdGVwcyBpbXBvcnQgTWFwQ2xhc3MKZnJvbSBtbHJ1bi51dGlscyBpbXBvcnQgbG9nZ2VyCmZyb20gbWxydW4udXRpbHMubW9kZWxfbW9uaXRvcmluZyBpbXBvcnQgKAogICAgY3JlYXRlX21vZGVsX2VuZHBvaW50X2lkLAogICAgcGFyc2VfbW9kZWxfZW5kcG9pbnRfc3RvcmVfcHJlZml4LAopCmZyb20gbWxydW4udXRpbHMudjNpb19jbGllbnRzIGltcG9ydCBnZXRfZnJhbWVzX2NsaWVudCwgZ2V0X3YzaW9fY2xpZW50CgpJU09fODA2MV9VVEMgPSAiJVktJW0tJWQgJUg6JU06JVMuJWYleiIKRlVOQ1RJT05fVVJJID0gImZ1bmN0aW9uX3VyaSIKTU9ERUwgPSAibW9kZWwiClZFUlNJT04gPSAidmVyc2lvbiIKVkVSU0lPTkVEX01PREVMID0gInZlcnNpb25lZF9tb2RlbCIKTU9ERUxfQ0xBU1MgPSAibW9kZWxfY2xhc3MiClRJTUVTVEFNUCA9ICJ0aW1lc3RhbXAiCkVORFBPSU5UX0lEID0gImVuZHBvaW50X2lkIgpSRVFVRVNUX0lEID0gInJlcXVlc3RfaWQiCkxBQkVMUyA9ICJsYWJlbHMiClVOUEFDS0VEX0xBQkVMUyA9ICJ1bnBhY2tlZF9sYWJlbHMiCkxBVEVOQ1lfQVZHXzVNID0gImxhdGVuY3lfYXZnXzVtIgpMQVRFTkNZX0FWR18xSCA9ICJsYXRlbmN5X2F2Z18xaCIKUFJFRElDVElPTlNfUEVSX1NFQ09ORCA9ICJwcmVkaWN0aW9uc19wZXJfc2Vjb25kIgpQUkVESUNUSU9OU19DT1VOVF81TSA9ICJwcmVkaWN0aW9uc19jb3VudF81bSIKUFJFRElDVElPTlNfQ09VTlRfMUggPSAicHJlZGljdGlvbnNfY291bnRfMWgiCkZJUlNUX1JFUVVFU1QgPSAiZmlyc3RfcmVxdWVzdCIKTEFTVF9SRVFVRVNUID0gImxhc3RfcmVxdWVzdCIKRVJST1JfQ09VTlQgPSAiZXJyb3JfY291bnQiCkVOVElUSUVTID0gImVudGl0aWVzIgpGRUFUVVJFX05BTUVTID0gImZlYXR1cmVfbmFtZXMiCkxBQkVMX0NPTFVNTlMgPSAibGFiZWxfY29sdW1ucyIKTEFURU5DWSA9ICJsYXRlbmN5IgpSRUNPUkRfVFlQRSA9ICJyZWNvcmRfdHlwZSIKRkVBVFVSRVMgPSAiZmVhdHVyZXMiClBSRURJQ1RJT04gPSAicHJlZGljdGlvbiIKUFJFRElDVElPTlMgPSAicHJlZGljdGlvbnMiCk5BTUVEX0ZFQVRVUkVTID0gIm5hbWVkX2ZlYXR1cmVzIgpOQU1FRF9QUkVESUNUSU9OUyA9ICJuYW1lZF9wcmVkaWN0aW9ucyIKQkFTRV9NRVRSSUNTID0gImJhc2VfbWV0cmljcyIKQ1VTVE9NX01FVFJJQ1MgPSAiY3VzdG9tX21ldHJpY3MiCkVORFBPSU5UX0ZFQVRVUkVTID0gImVuZHBvaW50X2ZlYXR1cmVzIgpNRVRSSUNTID0gIm1ldHJpY3MiCkJBVENIX1RJTUVTVEFNUCA9ICJiYXRjaF90aW1lc3RhbXAiClRJTUVfRk9STUFUOiBzdHIgPSAiJVktJW0tJWQgJUg6JU06JVMuJWYiICAjIElTTyA4MDYxCgoKIyBTdHJlYW0gcHJvY2Vzc2luZyBjb2RlCmNsYXNzIEV2ZW50U3RyZWFtUHJvY2Vzc29yOgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgcHJvamVjdDogc3RyLAogICAgICAgIHBhcnF1ZXRfYmF0Y2hpbmdfbWF4X2V2ZW50czogaW50LAogICAgICAgIHNhbXBsZV93aW5kb3c6IGludCA9IDEwLAogICAgICAgIHRzZGJfYmF0Y2hpbmdfbWF4X2V2ZW50czogaW50ID0gMTAsCiAgICAgICAgdHNkYl9iYXRjaGluZ190aW1lb3V0X3NlY3M6IGludCA9IDYwICogNSwgICMgRGVmYXVsdCA1IG1pbnV0ZXMKICAgICAgICBwYXJxdWV0X2JhdGNoaW5nX3RpbWVvdXRfc2VjczogaW50ID0gMzAgKiA2MCwgICMgRGVmYXVsdCAzMCBtaW51dGVzCiAgICAgICAgYWdncmVnYXRlX2NvdW50X3dpbmRvd3M6IE9wdGlvbmFsW0xpc3Rbc3RyXV0gPSBOb25lLAogICAgICAgIGFnZ3JlZ2F0ZV9jb3VudF9wZXJpb2Q6IHN0ciA9ICIzMHMiLAogICAgICAgIGFnZ3JlZ2F0ZV9hdmdfd2luZG93czogT3B0aW9uYWxbTGlzdFtzdHJdXSA9IE5vbmUsCiAgICAgICAgYWdncmVnYXRlX2F2Z19wZXJpb2Q6IHN0ciA9ICIzMHMiLAogICAgICAgIHYzaW9fYWNjZXNzX2tleTogT3B0aW9uYWxbc3RyXSA9IE5vbmUsCiAgICAgICAgdjNpb19mcmFtZXNkOiBPcHRpb25hbFtzdHJdID0gTm9uZSwKICAgICAgICB2M2lvX2FwaTogT3B0aW9uYWxbc3RyXSA9IE5vbmUsCiAgICAgICAgbW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5OiBzdHIgPSBOb25lLAogICAgKToKICAgICAgICBzZWxmLnByb2plY3QgPSBwcm9qZWN0CiAgICAgICAgc2VsZi5zYW1wbGVfd2luZG93ID0gc2FtcGxlX3dpbmRvdwogICAgICAgIHNlbGYudHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzID0gdHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzCiAgICAgICAgc2VsZi50c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjcyA9IHRzZGJfYmF0Y2hpbmdfdGltZW91dF9zZWNzCiAgICAgICAgc2VsZi5wYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMgPSBwYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMKICAgICAgICBzZWxmLnBhcnF1ZXRfYmF0Y2hpbmdfdGltZW91dF9zZWNzID0gcGFycXVldF9iYXRjaGluZ190aW1lb3V0X3NlY3MKICAgICAgICBzZWxmLmFnZ3JlZ2F0ZV9jb3VudF93aW5kb3dzID0gYWdncmVnYXRlX2NvdW50X3dpbmRvd3Mgb3IgWyI1bSIsICIxaCJdCiAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfcGVyaW9kID0gYWdncmVnYXRlX2NvdW50X3BlcmlvZAogICAgICAgIHNlbGYuYWdncmVnYXRlX2F2Z193aW5kb3dzID0gYWdncmVnYXRlX2F2Z193aW5kb3dzIG9yIFsiNW0iLCAiMWgiXQogICAgICAgIHNlbGYuYWdncmVnYXRlX2F2Z19wZXJpb2QgPSBhZ2dyZWdhdGVfYXZnX3BlcmlvZAoKICAgICAgICBzZWxmLnYzaW9fZnJhbWVzZCA9IHYzaW9fZnJhbWVzZCBvciBjb25maWcudjNpb19mcmFtZXNkCiAgICAgICAgc2VsZi52M2lvX2FwaSA9IHYzaW9fYXBpIG9yIGNvbmZpZy52M2lvX2FwaQoKICAgICAgICBzZWxmLnYzaW9fYWNjZXNzX2tleSA9IHYzaW9fYWNjZXNzX2tleSBvciBlbnZpcm9uLmdldCgiVjNJT19BQ0NFU1NfS0VZIikKICAgICAgICBzZWxmLm1vZGVsX21vbml0b3JpbmdfYWNjZXNzX2tleSA9ICgKICAgICAgICAgICAgbW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5CiAgICAgICAgICAgIG9yIG9zLmVudmlyb24uZ2V0KCJNT0RFTF9NT05JVE9SSU5HX0FDQ0VTU19LRVkiKQogICAgICAgICAgICBvciBzZWxmLnYzaW9fYWNjZXNzX2tleQogICAgICAgICkKCiAgICAgICAgdGVtcGxhdGUgPSBjb25maWcubW9kZWxfZW5kcG9pbnRfbW9uaXRvcmluZy5zdG9yZV9wcmVmaXhlcy5kZWZhdWx0CgogICAgICAgIGt2X3BhdGggPSB0ZW1wbGF0ZS5mb3JtYXQocHJvamVjdD1wcm9qZWN0LCBraW5kPSJlbmRwb2ludHMiKQogICAgICAgIF8sIHNlbGYua3ZfY29udGFpbmVyLCBzZWxmLmt2X3BhdGggPSBwYXJzZV9tb2RlbF9lbmRwb2ludF9zdG9yZV9wcmVmaXgoa3ZfcGF0aCkKCiAgICAgICAgdHNkYl9wYXRoID0gdGVtcGxhdGUuZm9ybWF0KHByb2plY3Q9cHJvamVjdCwga2luZD0iZXZlbnRzIikKICAgICAgICBfLCBzZWxmLnRzZGJfY29udGFpbmVyLCBzZWxmLnRzZGJfcGF0aCA9IHBhcnNlX21vZGVsX2VuZHBvaW50X3N0b3JlX3ByZWZpeCgKICAgICAgICAgICAgdHNkYl9wYXRoCiAgICAgICAgKQogICAgICAgIHNlbGYudHNkYl9wYXRoID0gZiJ7c2VsZi50c2RiX2NvbnRhaW5lcn0ve3NlbGYudHNkYl9wYXRofSIKCiAgICAgICAgc2VsZi5wYXJxdWV0X3BhdGggPSAoCiAgICAgICAgICAgIGNvbmZpZy5tb2RlbF9lbmRwb2ludF9tb25pdG9yaW5nLnN0b3JlX3ByZWZpeGVzLnVzZXJfc3BhY2UuZm9ybWF0KAogICAgICAgICAgICAgICAgcHJvamVjdD1wcm9qZWN0LCBraW5kPSJwYXJxdWV0IgogICAgICAgICAgICApCiAgICAgICAgKQoKICAgICAgICBsb2dnZXIuaW5mbygKICAgICAgICAgICAgIkluaXRpYWxpemluZyBtb2RlbCBtb25pdG9yaW5nIGV2ZW50IHN0cmVhbSBwcm9jZXNzb3IiLAogICAgICAgICAgICBwYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHM9c2VsZi5wYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMsCiAgICAgICAgICAgIHYzaW9fYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgbW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5PXNlbGYubW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5LAogICAgICAgICAgICBkZWZhdWx0X3N0b3JlX3ByZWZpeD1jb25maWcubW9kZWxfZW5kcG9pbnRfbW9uaXRvcmluZy5zdG9yZV9wcmVmaXhlcy5kZWZhdWx0LAogICAgICAgICAgICB1c2VyX3NwYWNlX3N0b3JlX3ByZWZpeD1jb25maWcubW9kZWxfZW5kcG9pbnRfbW9uaXRvcmluZy5zdG9yZV9wcmVmaXhlcy51c2VyX3NwYWNlLAogICAgICAgICAgICB2M2lvX2FwaT1zZWxmLnYzaW9fYXBpLAogICAgICAgICAgICB2M2lvX2ZyYW1lc2Q9c2VsZi52M2lvX2ZyYW1lc2QsCiAgICAgICAgICAgIGt2X2NvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgIHRzZGJfY29udGFpbmVyPXNlbGYudHNkYl9jb250YWluZXIsCiAgICAgICAgICAgIHRzZGJfcGF0aD1zZWxmLnRzZGJfcGF0aCwKICAgICAgICAgICAgcGFycXVldF9wYXRoPXNlbGYucGFycXVldF9wYXRoLAogICAgICAgICkKCiAgICBkZWYgY3JlYXRlX2ZlYXR1cmVfc2V0KHNlbGYpOgogICAgICAgIGZlYXR1cmVfc2V0ID0gZnMuRmVhdHVyZVNldCgKICAgICAgICAgICAgIm1vbml0b3JpbmciLCBlbnRpdGllcz1bRU5EUE9JTlRfSURdLCB0aW1lc3RhbXBfa2V5PVRJTUVTVEFNUAogICAgICAgICkKICAgICAgICBmZWF0dXJlX3NldC5tZXRhZGF0YS5wcm9qZWN0ID0gc2VsZi5wcm9qZWN0CiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGgudG8oCiAgICAgICAgICAgICJQcm9jZXNzRW5kcG9pbnRFdmVudCIsCiAgICAgICAgICAgIGt2X2NvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgIHYzaW9fYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgZnVsbF9ldmVudD1UcnVlLAogICAgICAgICkudG8oInN0b3JleS5GaWx0ZXIiLCAiZmlsdGVyX25vbmUiLCBfZm49IihldmVudCBpcyBub3QgTm9uZSkiKS50bygKICAgICAgICAgICAgInN0b3JleS5GbGF0TWFwIiwgImZsYXR0ZW5fZXZlbnRzIiwgX2ZuPSIoZXZlbnQpIgogICAgICAgICkudG8oCiAgICAgICAgICAgICJNYXBGZWF0dXJlTmFtZXMiLAogICAgICAgICAgICBuYW1lPSJNYXBGZWF0dXJlTmFtZXMiLAogICAgICAgICAgICBrdl9jb250YWluZXI9c2VsZi5rdl9jb250YWluZXIsCiAgICAgICAgICAgIGt2X3BhdGg9c2VsZi5rdl9wYXRoLAogICAgICAgICAgICBhY2Nlc3Nfa2V5PXNlbGYudjNpb19hY2Nlc3Nfa2V5LAogICAgICAgICAgICBpbmZlcl9jb2x1bW5zX2Zyb21fZGF0YT1UcnVlLAogICAgICAgICkKICAgICAgICAjIGt2IGFuZCB0c2RiIGJyYW5jaAogICAgICAgIGZlYXR1cmVfc2V0LmFkZF9hZ2dyZWdhdGlvbigKICAgICAgICAgICAgRU5EUE9JTlRfSUQsCiAgICAgICAgICAgIFsiY291bnQiXSwKICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfd2luZG93cywKICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfcGVyaW9kLAogICAgICAgICAgICBuYW1lPVBSRURJQ1RJT05TLAogICAgICAgICAgICBhZnRlcj0iTWFwRmVhdHVyZU5hbWVzIiwKICAgICAgICAgICAgc3RlcF9uYW1lPSJBZ2dyZWdhdGVzIiwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuYWRkX2FnZ3JlZ2F0aW9uKAogICAgICAgICAgICBMQVRFTkNZLAogICAgICAgICAgICBbImF2ZyJdLAogICAgICAgICAgICBzZWxmLmFnZ3JlZ2F0ZV9hdmdfd2luZG93cywKICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfYXZnX3BlcmlvZCwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJzdG9yZXkuc3RlcHMuU2FtcGxlV2luZG93IiwKICAgICAgICAgICAgbmFtZT0ic2FtcGxlIiwKICAgICAgICAgICAgYWZ0ZXI9IkFnZ3JlZ2F0ZXMiLAogICAgICAgICAgICB3aW5kb3dfc2l6ZT1zZWxmLnNhbXBsZV93aW5kb3csCiAgICAgICAgICAgIGtleT1FTkRQT0lOVF9JRCwKICAgICAgICApCiAgICAgICAgIyBrdgogICAgICAgIGZlYXR1cmVfc2V0LmdyYXBoLmFkZF9zdGVwKAogICAgICAgICAgICAiUHJvY2Vzc0JlZm9yZUtWIiwgbmFtZT0iUHJvY2Vzc0JlZm9yZUtWIiwgYWZ0ZXI9InNhbXBsZSIKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJXcml0ZVRvS1YiLAogICAgICAgICAgICBuYW1lPSJXcml0ZVRvS1YiLAogICAgICAgICAgICBhZnRlcj0iUHJvY2Vzc0JlZm9yZUtWIiwKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICB0YWJsZT1zZWxmLmt2X3BhdGgsCiAgICAgICAgKQogICAgICAgIGZlYXR1cmVfc2V0LmdyYXBoLmFkZF9zdGVwKAogICAgICAgICAgICAiSW5mZXJTY2hlbWEiLAogICAgICAgICAgICBuYW1lPSJJbmZlclNjaGVtYSIsCiAgICAgICAgICAgIGFmdGVyPSJXcml0ZVRvS1YiLAogICAgICAgICAgICB2M2lvX2FjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgIHYzaW9fZnJhbWVzZD1zZWxmLnYzaW9fZnJhbWVzZCwKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICB0YWJsZT1zZWxmLmt2X3BhdGgsCiAgICAgICAgKQogICAgICAgICMgdHNkYgogICAgICAgIGZlYXR1cmVfc2V0LmdyYXBoLmFkZF9zdGVwKAogICAgICAgICAgICAiUHJvY2Vzc0JlZm9yZVRTREIiLCBuYW1lPSJQcm9jZXNzQmVmb3JlVFNEQiIsIGFmdGVyPSJzYW1wbGUiCiAgICAgICAgKQogICAgICAgIGZlYXR1cmVfc2V0LmdyYXBoLmFkZF9zdGVwKAogICAgICAgICAgICAiRmlsdGVyQW5kVW5wYWNrS2V5cyIsCiAgICAgICAgICAgIG5hbWU9IkZpbHRlckFuZFVucGFja0tleXMxIiwKICAgICAgICAgICAgYWZ0ZXI9IlByb2Nlc3NCZWZvcmVUU0RCIiwKICAgICAgICAgICAga2V5cz1bQkFTRV9NRVRSSUNTXSwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJzdG9yZXkuVFNEQlRhcmdldCIsCiAgICAgICAgICAgIG5hbWU9InRzZGIxIiwKICAgICAgICAgICAgYWZ0ZXI9IkZpbHRlckFuZFVucGFja0tleXMxIiwKICAgICAgICAgICAgcGF0aD1zZWxmLnRzZGJfcGF0aCwKICAgICAgICAgICAgcmF0ZT0iMTAvbSIsCiAgICAgICAgICAgIHRpbWVfY29sPVRJTUVTVEFNUCwKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYudHNkYl9jb250YWluZXIsCiAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgIHYzaW9fZnJhbWVzPXNlbGYudjNpb19mcmFtZXNkLAogICAgICAgICAgICBpbmRleF9jb2xzPVtFTkRQT0lOVF9JRCwgUkVDT1JEX1RZUEVdLAogICAgICAgICAgICBtYXhfZXZlbnRzPXNlbGYudHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzLAogICAgICAgICAgICB0aW1lb3V0X3NlY3M9c2VsZi50c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjcywKICAgICAgICAgICAga2V5PUVORFBPSU5UX0lELAogICAgICAgICkKICAgICAgICBmZWF0dXJlX3NldC5ncmFwaC5hZGRfc3RlcCgKICAgICAgICAgICAgIkZpbHRlckFuZFVucGFja0tleXMiLAogICAgICAgICAgICBuYW1lPSJGaWx0ZXJBbmRVbnBhY2tLZXlzMiIsCiAgICAgICAgICAgIGFmdGVyPSJQcm9jZXNzQmVmb3JlVFNEQiIsCiAgICAgICAgICAgIGtleXM9W0VORFBPSU5UX0ZFQVRVUkVTXSwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJzdG9yZXkuVFNEQlRhcmdldCIsCiAgICAgICAgICAgIG5hbWU9InRzZGIyIiwKICAgICAgICAgICAgYWZ0ZXI9IkZpbHRlckFuZFVucGFja0tleXMyIiwKICAgICAgICAgICAgcGF0aD1zZWxmLnRzZGJfcGF0aCwKICAgICAgICAgICAgcmF0ZT0iMTAvbSIsCiAgICAgICAgICAgIHRpbWVfY29sPVRJTUVTVEFNUCwKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYudHNkYl9jb250YWluZXIsCiAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgIHYzaW9fZnJhbWVzPXNlbGYudjNpb19mcmFtZXNkLAogICAgICAgICAgICBpbmRleF9jb2xzPVtFTkRQT0lOVF9JRCwgUkVDT1JEX1RZUEVdLAogICAgICAgICAgICBtYXhfZXZlbnRzPXNlbGYudHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzLAogICAgICAgICAgICB0aW1lb3V0X3NlY3M9c2VsZi50c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjcywKICAgICAgICAgICAga2V5PUVORFBPSU5UX0lELAogICAgICAgICkKICAgICAgICBmZWF0dXJlX3NldC5ncmFwaC5hZGRfc3RlcCgKICAgICAgICAgICAgIkZpbHRlckFuZFVucGFja0tleXMiLAogICAgICAgICAgICBuYW1lPSJGaWx0ZXJBbmRVbnBhY2tLZXlzMyIsCiAgICAgICAgICAgIGFmdGVyPSJQcm9jZXNzQmVmb3JlVFNEQiIsCiAgICAgICAgICAgIGtleXM9W0NVU1RPTV9NRVRSSUNTXSwKICAgICAgICApCiAgICAgICAgZmVhdHVyZV9zZXQuZ3JhcGguYWRkX3N0ZXAoCiAgICAgICAgICAgICJzdG9yZXkuRmlsdGVyIiwKICAgICAgICAgICAgIkZpbHRlck5vdE5vbmUiLAogICAgICAgICAgICBhZnRlcj0iRmlsdGVyQW5kVW5wYWNrS2V5czMiLAogICAgICAgICAgICBfZm49IihldmVudCBpcyBub3QgTm9uZSkiLAogICAgICAgICkKICAgICAgICBmZWF0dXJlX3NldC5ncmFwaC5hZGRfc3RlcCgKICAgICAgICAgICAgInN0b3JleS5UU0RCVGFyZ2V0IiwKICAgICAgICAgICAgbmFtZT0idHNkYjMiLAogICAgICAgICAgICBhZnRlcj0iRmlsdGVyTm90Tm9uZSIsCiAgICAgICAgICAgIHBhdGg9c2VsZi50c2RiX3BhdGgsCiAgICAgICAgICAgIHJhdGU9IjEwL20iLAogICAgICAgICAgICB0aW1lX2NvbD1USU1FU1RBTVAsCiAgICAgICAgICAgIGNvbnRhaW5lcj1zZWxmLnRzZGJfY29udGFpbmVyLAogICAgICAgICAgICBhY2Nlc3Nfa2V5PXNlbGYudjNpb19hY2Nlc3Nfa2V5LAogICAgICAgICAgICB2M2lvX2ZyYW1lcz1zZWxmLnYzaW9fZnJhbWVzZCwKICAgICAgICAgICAgaW5kZXhfY29scz1bRU5EUE9JTlRfSUQsIFJFQ09SRF9UWVBFXSwKICAgICAgICAgICAgbWF4X2V2ZW50cz1zZWxmLnRzZGJfYmF0Y2hpbmdfbWF4X2V2ZW50cywKICAgICAgICAgICAgdGltZW91dF9zZWNzPXNlbGYudHNkYl9iYXRjaGluZ190aW1lb3V0X3NlY3MsCiAgICAgICAgICAgIGtleT1FTkRQT0lOVF9JRCwKICAgICAgICApCgogICAgICAgICMgcGFycXVldCBicmFuY2gKICAgICAgICBmZWF0dXJlX3NldC5ncmFwaC5hZGRfc3RlcCgKICAgICAgICAgICAgIlByb2Nlc3NCZWZvcmVQYXJxdWV0IiwKICAgICAgICAgICAgbmFtZT0iUHJvY2Vzc0JlZm9yZVBhcnF1ZXQiLAogICAgICAgICAgICBhZnRlcj0iTWFwRmVhdHVyZU5hbWVzIiwKICAgICAgICAgICAgX2ZuPSIoZXZlbnQpIiwKICAgICAgICApCiAgICAgICAgc3RvcmFnZV9vcHRpb25zID0gZGljdCgKICAgICAgICAgICAgdjNpb19hY2Nlc3Nfa2V5PXNlbGYubW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5LCB2M2lvX2FwaT1zZWxmLnYzaW9fYXBpCiAgICAgICAgKQoKICAgICAgICBwcV90YXJnZXQgPSBQYXJxdWV0VGFyZ2V0KAogICAgICAgICAgICBwYXRoPXNlbGYucGFycXVldF9wYXRoLAogICAgICAgICAgICBhZnRlcl9zdGVwPSJQcm9jZXNzQmVmb3JlUGFycXVldCIsCiAgICAgICAgICAgIGtleV9idWNrZXRpbmdfbnVtYmVyPTAsCiAgICAgICAgICAgIHRpbWVfcGFydGl0aW9uaW5nX2dyYW51bGFyaXR5PSJob3VyIiwKICAgICAgICAgICAgbWF4X2V2ZW50cz1zZWxmLnBhcnF1ZXRfYmF0Y2hpbmdfbWF4X2V2ZW50cywKICAgICAgICAgICAgZmx1c2hfYWZ0ZXJfc2Vjb25kcz1zZWxmLnBhcnF1ZXRfYmF0Y2hpbmdfdGltZW91dF9zZWNzLAogICAgICAgICAgICBzdG9yYWdlX29wdGlvbnM9c3RvcmFnZV9vcHRpb25zLAogICAgICAgICAgICBhdHRyaWJ1dGVzPXsiaW5mZXJfY29sdW1uc19mcm9tX2RhdGEiOiBUcnVlfSwKICAgICAgICApCgogICAgICAgIGZlYXR1cmVfc2V0LnNldF90YXJnZXRzKAogICAgICAgICAgICB0YXJnZXRzPVtwcV90YXJnZXRdLAogICAgICAgICAgICB3aXRoX2RlZmF1bHRzPUZhbHNlLAogICAgICAgICAgICBkZWZhdWx0X2ZpbmFsX3N0ZXA9IlByb2Nlc3NCZWZvcmVQYXJxdWV0IiwKICAgICAgICApCiAgICAgICAgcmV0dXJuIGZlYXR1cmVfc2V0CgoKY2xhc3MgUHJvY2Vzc0JlZm9yZUtWKE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQpOgogICAgICAgICMgY29tcHV0ZSBwcmVkaWN0aW9uIHBlciBzZWNvbmQKICAgICAgICBldmVudFtQUkVESUNUSU9OU19QRVJfU0VDT05EXSA9IGZsb2F0KGV2ZW50W1BSRURJQ1RJT05TX0NPVU5UXzVNXSkgLyAzMDAKICAgICAgICAjIEZpbHRlciByZWxldmFudCBrZXlzCiAgICAgICAgZSA9IHsKICAgICAgICAgICAgazogZXZlbnRba10KICAgICAgICAgICAgZm9yIGsgaW4gWwogICAgICAgICAgICAgICAgRlVOQ1RJT05fVVJJLAogICAgICAgICAgICAgICAgTU9ERUwsCiAgICAgICAgICAgICAgICBNT0RFTF9DTEFTUywKICAgICAgICAgICAgICAgIFRJTUVTVEFNUCwKICAgICAgICAgICAgICAgIEVORFBPSU5UX0lELAogICAgICAgICAgICAgICAgTEFCRUxTLAogICAgICAgICAgICAgICAgVU5QQUNLRURfTEFCRUxTLAogICAgICAgICAgICAgICAgTEFURU5DWV9BVkdfNU0sCiAgICAgICAgICAgICAgICBMQVRFTkNZX0FWR18xSCwKICAgICAgICAgICAgICAgIFBSRURJQ1RJT05TX1BFUl9TRUNPTkQsCiAgICAgICAgICAgICAgICBQUkVESUNUSU9OU19DT1VOVF81TSwKICAgICAgICAgICAgICAgIFBSRURJQ1RJT05TX0NPVU5UXzFILAogICAgICAgICAgICAgICAgRklSU1RfUkVRVUVTVCwKICAgICAgICAgICAgICAgIExBU1RfUkVRVUVTVCwKICAgICAgICAgICAgICAgIEVSUk9SX0NPVU5ULAogICAgICAgICAgICBdCiAgICAgICAgfQogICAgICAgICMgVW5wYWNrIGxhYmVscyBkaWN0aW9uYXJ5CiAgICAgICAgZSA9IHsqKmUsICoqZS5wb3AoVU5QQUNLRURfTEFCRUxTLCB7fSl9CiAgICAgICAgIyBXcml0ZSBsYWJlbHMgdG8ga3YgYXMganNvbiBzdHJpbmcgdG8gYmUgcHJlc2VudGFibGUgbGF0ZXIKICAgICAgICBlW0xBQkVMU10gPSBqc29uLmR1bXBzKGVbTEFCRUxTXSkKICAgICAgICByZXR1cm4gZQoKCmNsYXNzIFByb2Nlc3NCZWZvcmVUU0RCKE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQpOgogICAgICAgICMgY29tcHV0ZSBwcmVkaWN0aW9uIHBlciBzZWNvbmQKICAgICAgICBldmVudFtQUkVESUNUSU9OU19QRVJfU0VDT05EXSA9IGZsb2F0KGV2ZW50W1BSRURJQ1RJT05TX0NPVU5UXzVNXSkgLyAzMDAKICAgICAgICBiYXNlX2ZpZWxkcyA9IFtUSU1FU1RBTVAsIEVORFBPSU5UX0lEXQoKICAgICAgICBiYXNlX2V2ZW50ID0ge2s6IGV2ZW50W2tdIGZvciBrIGluIGJhc2VfZmllbGRzfQogICAgICAgIGJhc2VfZXZlbnRbVElNRVNUQU1QXSA9IHBkLnRvX2RhdGV0aW1lKAogICAgICAgICAgICBiYXNlX2V2ZW50W1RJTUVTVEFNUF0sIGZvcm1hdD1USU1FX0ZPUk1BVAogICAgICAgICkKCiAgICAgICAgYmFzZV9tZXRyaWNzID0gewogICAgICAgICAgICBSRUNPUkRfVFlQRTogQkFTRV9NRVRSSUNTLAogICAgICAgICAgICBQUkVESUNUSU9OU19QRVJfU0VDT05EOiBldmVudFtQUkVESUNUSU9OU19QRVJfU0VDT05EXSwKICAgICAgICAgICAgUFJFRElDVElPTlNfQ09VTlRfNU06IGV2ZW50W1BSRURJQ1RJT05TX0NPVU5UXzVNXSwKICAgICAgICAgICAgUFJFRElDVElPTlNfQ09VTlRfMUg6IGV2ZW50W1BSRURJQ1RJT05TX0NPVU5UXzFIXSwKICAgICAgICAgICAgTEFURU5DWV9BVkdfNU06IGV2ZW50W0xBVEVOQ1lfQVZHXzVNXSwKICAgICAgICAgICAgTEFURU5DWV9BVkdfMUg6IGV2ZW50W0xBVEVOQ1lfQVZHXzFIXSwKICAgICAgICAgICAgKipiYXNlX2V2ZW50LAogICAgICAgIH0KCiAgICAgICAgZW5kcG9pbnRfZmVhdHVyZXMgPSB7CiAgICAgICAgICAgIFJFQ09SRF9UWVBFOiBFTkRQT0lOVF9GRUFUVVJFUywKICAgICAgICAgICAgKipldmVudFtOQU1FRF9QUkVESUNUSU9OU10sCiAgICAgICAgICAgICoqZXZlbnRbTkFNRURfRkVBVFVSRVNdLAogICAgICAgICAgICAqKmJhc2VfZXZlbnQsCiAgICAgICAgfQoKICAgICAgICBwcm9jZXNzZWQgPSB7QkFTRV9NRVRSSUNTOiBiYXNlX21ldHJpY3MsIEVORFBPSU5UX0ZFQVRVUkVTOiBlbmRwb2ludF9mZWF0dXJlc30KCiAgICAgICAgaWYgZXZlbnRbTUVUUklDU106CiAgICAgICAgICAgIHByb2Nlc3NlZFtDVVNUT01fTUVUUklDU10gPSB7CiAgICAgICAgICAgICAgICBSRUNPUkRfVFlQRTogQ1VTVE9NX01FVFJJQ1MsCiAgICAgICAgICAgICAgICAqKmV2ZW50W01FVFJJQ1NdLAogICAgICAgICAgICAgICAgKipiYXNlX2V2ZW50LAogICAgICAgICAgICB9CgogICAgICAgIHJldHVybiBwcm9jZXNzZWQKCgpjbGFzcyBQcm9jZXNzQmVmb3JlUGFycXVldChNYXBDbGFzcyk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgKiprd2FyZ3MpOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKiprd2FyZ3MpCgogICAgZGVmIGRvKHNlbGYsIGV2ZW50KToKICAgICAgICBsb2dnZXIuaW5mbygiUHJvY2Vzc0JlZm9yZVBhcnF1ZXQxIiwgZXZlbnQ9ZXZlbnQpCiAgICAgICAgZm9yIGtleSBpbiBbVU5QQUNLRURfTEFCRUxTLCBGRUFUVVJFU106CiAgICAgICAgICAgIGV2ZW50LnBvcChrZXksIE5vbmUpCiAgICAgICAgdmFsdWUgPSBldmVudC5nZXQoImVudGl0aWVzIikKICAgICAgICBpZiB2YWx1ZSBpcyBub3QgTm9uZToKICAgICAgICAgICAgZXZlbnQgPSB7Kip2YWx1ZSwgKipldmVudH0KICAgICAgICBmb3Iga2V5IGluIFtMQUJFTFMsIE1FVFJJQ1MsIEVOVElUSUVTXToKICAgICAgICAgICAgaWYgbm90IGV2ZW50LmdldChrZXkpOgogICAgICAgICAgICAgICAgZXZlbnRba2V5XSA9IE5vbmUKICAgICAgICBsb2dnZXIuaW5mbygiUHJvY2Vzc0JlZm9yZVBhcnF1ZXQyIiwgZXZlbnQ9ZXZlbnQpCiAgICAgICAgcmV0dXJuIGV2ZW50CgoKY2xhc3MgUHJvY2Vzc0VuZHBvaW50RXZlbnQoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGt2X2NvbnRhaW5lcjogc3RyLCBrdl9wYXRoOiBzdHIsIHYzaW9fYWNjZXNzX2tleTogc3RyLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKICAgICAgICBzZWxmLmt2X2NvbnRhaW5lcjogc3RyID0ga3ZfY29udGFpbmVyCiAgICAgICAgc2VsZi5rdl9wYXRoOiBzdHIgPSBrdl9wYXRoCiAgICAgICAgc2VsZi52M2lvX2FjY2Vzc19rZXk6IHN0ciA9IHYzaW9fYWNjZXNzX2tleQogICAgICAgIHNlbGYuZmlyc3RfcmVxdWVzdDogRGljdFtzdHIsIHN0cl0gPSBkaWN0KCkKICAgICAgICBzZWxmLmxhc3RfcmVxdWVzdDogRGljdFtzdHIsIHN0cl0gPSBkaWN0KCkKICAgICAgICBzZWxmLmVycm9yX2NvdW50OiBEaWN0W3N0ciwgaW50XSA9IGRlZmF1bHRkaWN0KGludCkKICAgICAgICBzZWxmLmVuZHBvaW50czogU2V0W3N0cl0gPSBzZXQoKQoKICAgIGRlZiBkbyhzZWxmLCBmdWxsX2V2ZW50KToKICAgICAgICBldmVudCA9IGZ1bGxfZXZlbnQuYm9keQoKICAgICAgICAjIGNvZGUgdGhhdCBjYWxjdWxhdGVzIHRoZSBlbmRwcGludCBpZC4gc2hvdWxkIGJlCiAgICAgICAgZnVuY3Rpb25fdXJpID0gZXZlbnQuZ2V0KEZVTkNUSU9OX1VSSSkKICAgICAgICBpZiBub3QgaXNfbm90X25vbmUoZnVuY3Rpb25fdXJpLCBbRlVOQ1RJT05fVVJJXSk6CiAgICAgICAgICAgIHJldHVybiBOb25lCgogICAgICAgIG1vZGVsID0gZXZlbnQuZ2V0KE1PREVMKQogICAgICAgIGlmIG5vdCBpc19ub3Rfbm9uZShtb2RlbCwgW01PREVMXSk6CiAgICAgICAgICAgIHJldHVybiBOb25lCgogICAgICAgIHZlcnNpb24gPSBldmVudC5nZXQoVkVSU0lPTikKICAgICAgICB2ZXJzaW9uZWRfbW9kZWwgPSBmInttb2RlbH06e3ZlcnNpb259IiBpZiB2ZXJzaW9uIGVsc2UgZiJ7bW9kZWx9OmxhdGVzdCIKCiAgICAgICAgZW5kcG9pbnRfaWQgPSBjcmVhdGVfbW9kZWxfZW5kcG9pbnRfaWQoCiAgICAgICAgICAgIGZ1bmN0aW9uX3VyaT1mdW5jdGlvbl91cmksCiAgICAgICAgICAgIHZlcnNpb25lZF9tb2RlbD12ZXJzaW9uZWRfbW9kZWwsCiAgICAgICAgKQogICAgICAgIGVuZHBvaW50X2lkID0gc3RyKGVuZHBvaW50X2lkKQoKICAgICAgICBldmVudFtWRVJTSU9ORURfTU9ERUxdID0gdmVyc2lvbmVkX21vZGVsCiAgICAgICAgZXZlbnRbRU5EUE9JTlRfSURdID0gZW5kcG9pbnRfaWQKCiAgICAgICAgIyBJbiBjYXNlIHRoaXMgcHJvY2VzcyBmYWlscywgcmVzdW1lIHN0YXRlIGZyb20gZXhpc3RpbmcgcmVjb3JkCiAgICAgICAgc2VsZi5yZXN1bWVfc3RhdGUoZW5kcG9pbnRfaWQpCgogICAgICAgICMgSGFuZGxlIGVycm9ycyBjb21pbmcgZnJvbSBzdHJlYW0KICAgICAgICBmb3VuZF9lcnJvcnMgPSBzZWxmLmhhbmRsZV9lcnJvcnMoZW5kcG9pbnRfaWQsIGV2ZW50KQogICAgICAgIGlmIGZvdW5kX2Vycm9yczoKICAgICAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAgICAgIyBWYWxpZGF0ZSBldmVudCBmaWVsZHMKICAgICAgICBtb2RlbF9jbGFzcyA9IGV2ZW50LmdldCgibW9kZWxfY2xhc3MiKSBvciBldmVudC5nZXQoImNsYXNzIikKICAgICAgICB0aW1lc3RhbXAgPSBldmVudC5nZXQoIndoZW4iKQogICAgICAgIHJlcXVlc3RfaWQgPSBldmVudC5nZXQoInJlcXVlc3QiLCB7fSkuZ2V0KCJpZCIpIG9yIGV2ZW50LmdldCgicmVzcCIsIHt9KS5nZXQoCiAgICAgICAgICAgICJpZCIKICAgICAgICApCiAgICAgICAgbGF0ZW5jeSA9IGV2ZW50LmdldCgibWljcm9zZWMiKQogICAgICAgIGZlYXR1cmVzID0gZXZlbnQuZ2V0KCJyZXF1ZXN0Iiwge30pLmdldCgiaW5wdXRzIikKICAgICAgICBwcmVkaWN0aW9ucyA9IGV2ZW50LmdldCgicmVzcCIsIHt9KS5nZXQoIm91dHB1dHMiKQoKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgZW5kcG9pbnRfaWQsCiAgICAgICAgICAgIGlzX25vdF9ub25lLAogICAgICAgICAgICB0aW1lc3RhbXAsCiAgICAgICAgICAgIFsid2hlbiJdLAogICAgICAgICk6CiAgICAgICAgICAgIHJldHVybiBOb25lCgogICAgICAgIGlmIGVuZHBvaW50X2lkIG5vdCBpbiBzZWxmLmZpcnN0X3JlcXVlc3Q6CiAgICAgICAgICAgIHNlbGYuZmlyc3RfcmVxdWVzdFtlbmRwb2ludF9pZF0gPSB0aW1lc3RhbXAKICAgICAgICBzZWxmLmxhc3RfcmVxdWVzdFtlbmRwb2ludF9pZF0gPSB0aW1lc3RhbXAKCiAgICAgICAgaWYgbm90IHNlbGYuaXNfdmFsaWQoCiAgICAgICAgICAgIGVuZHBvaW50X2lkLAogICAgICAgICAgICBpc19ub3Rfbm9uZSwKICAgICAgICAgICAgcmVxdWVzdF9pZCwKICAgICAgICAgICAgWyJyZXF1ZXN0IiwgImlkIl0sCiAgICAgICAgKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgZW5kcG9pbnRfaWQsCiAgICAgICAgICAgIGlzX25vdF9ub25lLAogICAgICAgICAgICBsYXRlbmN5LAogICAgICAgICAgICBbIm1pY3Jvc2VjIl0sCiAgICAgICAgKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgZW5kcG9pbnRfaWQsCiAgICAgICAgICAgIGlzX25vdF9ub25lLAogICAgICAgICAgICBmZWF0dXJlcywKICAgICAgICAgICAgWyJyZXF1ZXN0IiwgImlucHV0cyJdLAogICAgICAgICk6CiAgICAgICAgICAgIHJldHVybiBOb25lCiAgICAgICAgaWYgbm90IHNlbGYuaXNfdmFsaWQoCiAgICAgICAgICAgIGVuZHBvaW50X2lkLAogICAgICAgICAgICBpc19ub3Rfbm9uZSwKICAgICAgICAgICAgcHJlZGljdGlvbnMsCiAgICAgICAgICAgIFsicmVzcCIsICJvdXRwdXRzIl0sCiAgICAgICAgKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAgICAgdW5wYWNrZWRfbGFiZWxzID0ge2YiX3trfSI6IHYgZm9yIGssIHYgaW4gZXZlbnQuZ2V0KExBQkVMUywge30pLml0ZW1zKCl9CgogICAgICAgICMgU2VwYXJhdGUgZWFjaCBtb2RlbCBpbnZvY2F0aW9uIGludG8gc3ViIGV2ZW50cwogICAgICAgIGV2ZW50cyA9IFtdCiAgICAgICAgZm9yIGksIChmZWF0dXJlLCBwcmVkaWN0aW9uKSBpbiBlbnVtZXJhdGUoemlwKGZlYXR1cmVzLCBwcmVkaWN0aW9ucykpOgogICAgICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgICAgIGVuZHBvaW50X2lkLAogICAgICAgICAgICAgICAgc2VsZi5pc19saXN0X29mX251bWVyaWNzLAogICAgICAgICAgICAgICAgZmVhdHVyZSwKICAgICAgICAgICAgICAgIFsicmVxdWVzdCIsICJpbnB1dHMiLCBmIlt7aX1dIl0sCiAgICAgICAgICAgICk6CiAgICAgICAgICAgICAgICByZXR1cm4gTm9uZQoKICAgICAgICAgICAgaWYgbm90IGlzaW5zdGFuY2UocHJlZGljdGlvbiwgbGlzdCk6CiAgICAgICAgICAgICAgICBwcmVkaWN0aW9uID0gW3ByZWRpY3Rpb25dCgogICAgICAgICAgICBldmVudHMuYXBwZW5kKAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIEZVTkNUSU9OX1VSSTogZnVuY3Rpb25fdXJpLAogICAgICAgICAgICAgICAgICAgIE1PREVMOiB2ZXJzaW9uZWRfbW9kZWwsCiAgICAgICAgICAgICAgICAgICAgTU9ERUxfQ0xBU1M6IG1vZGVsX2NsYXNzLAogICAgICAgICAgICAgICAgICAgIFRJTUVTVEFNUDogdGltZXN0YW1wLAogICAgICAgICAgICAgICAgICAgIEVORFBPSU5UX0lEOiBlbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgICAgICBSRVFVRVNUX0lEOiByZXF1ZXN0X2lkLAogICAgICAgICAgICAgICAgICAgIExBVEVOQ1k6IGxhdGVuY3ksCiAgICAgICAgICAgICAgICAgICAgRkVBVFVSRVM6IGZlYXR1cmUsCiAgICAgICAgICAgICAgICAgICAgUFJFRElDVElPTjogcHJlZGljdGlvbiwKICAgICAgICAgICAgICAgICAgICBGSVJTVF9SRVFVRVNUOiBzZWxmLmZpcnN0X3JlcXVlc3RbZW5kcG9pbnRfaWRdLAogICAgICAgICAgICAgICAgICAgIExBU1RfUkVRVUVTVDogc2VsZi5sYXN0X3JlcXVlc3RbZW5kcG9pbnRfaWRdLAogICAgICAgICAgICAgICAgICAgIEVSUk9SX0NPVU5UOiBzZWxmLmVycm9yX2NvdW50W2VuZHBvaW50X2lkXSwKICAgICAgICAgICAgICAgICAgICBMQUJFTFM6IGV2ZW50LmdldChMQUJFTFMsIHt9KSwKICAgICAgICAgICAgICAgICAgICBNRVRSSUNTOiBldmVudC5nZXQoTUVUUklDUywge30pLAogICAgICAgICAgICAgICAgICAgIEVOVElUSUVTOiBldmVudC5nZXQoInJlcXVlc3QiLCB7fSkuZ2V0KEVOVElUSUVTLCB7fSksCiAgICAgICAgICAgICAgICAgICAgVU5QQUNLRURfTEFCRUxTOiB1bnBhY2tlZF9sYWJlbHMsCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKCiAgICAgICAgc3RvcmV5X2V2ZW50ID0gRXZlbnQoYm9keT1ldmVudHMsIGtleT1lbmRwb2ludF9pZCwgdGltZT10aW1lc3RhbXApCiAgICAgICAgcmV0dXJuIHN0b3JleV9ldmVudAoKICAgIGRlZiBpc19saXN0X29mX251bWVyaWNzKAogICAgICAgIHNlbGYsIGZpZWxkOiBMaXN0W1VuaW9uW2ludCwgZmxvYXQsIGRpY3QsIGxpc3RdXSwgZGljdF9wYXRoOiBMaXN0W3N0cl0KICAgICk6CiAgICAgICAgaWYgYWxsKGlzaW5zdGFuY2UoeCwgaW50KSBvciBpc2luc3RhbmNlKHgsIGZsb2F0KSBmb3IgeCBpbiBmaWVsZCk6CiAgICAgICAgICAgIHJldHVybiBUcnVlCiAgICAgICAgbG9nZ2VyLmVycm9yKAogICAgICAgICAgICBmIkxpc3QgZG9lcyBub3QgY29uc2lzdCBvZiBvbmx5IG51bWVyaWMgdmFsdWVzOiB7ZmllbGR9IFtFdmVudCAtPiB7JywnLmpvaW4oZGljdF9wYXRoKX1dIgogICAgICAgICkKICAgICAgICByZXR1cm4gRmFsc2UKCiAgICBkZWYgcmVzdW1lX3N0YXRlKHNlbGYsIGVuZHBvaW50X2lkKToKICAgICAgICAjIE1ha2Ugc3VyZSBwcm9jZXNzIGlzIHJlc3VtYWJsZSwgaWYgcHJvY2VzcyBmYWlscyBmb3IgYW55IHJlYXNvbiwgYmUgYWJsZSB0byBwaWNrIHRoaW5ncyB1cCBjbG9zZSB0byB3aGVyZSB3ZQogICAgICAgICMgbGVmdCB0aGVtCiAgICAgICAgaWYgZW5kcG9pbnRfaWQgbm90IGluIHNlbGYuZW5kcG9pbnRzOgogICAgICAgICAgICBsb2dnZXIuaW5mbygiVHJ5aW5nIHRvIHJlc3VtZSBzdGF0ZSIsIGVuZHBvaW50X2lkPWVuZHBvaW50X2lkKQogICAgICAgICAgICBlbmRwb2ludF9yZWNvcmQgPSBnZXRfZW5kcG9pbnRfcmVjb3JkKAogICAgICAgICAgICAgICAga3ZfY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgICAgICBlbmRwb2ludF9pZD1lbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgZW5kcG9pbnRfcmVjb3JkOgogICAgICAgICAgICAgICAgZmlyc3RfcmVxdWVzdCA9IGVuZHBvaW50X3JlY29yZC5nZXQoRklSU1RfUkVRVUVTVCkKICAgICAgICAgICAgICAgIGlmIGZpcnN0X3JlcXVlc3Q6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5maXJzdF9yZXF1ZXN0W2VuZHBvaW50X2lkXSA9IGZpcnN0X3JlcXVlc3QKICAgICAgICAgICAgICAgIGVycm9yX2NvdW50ID0gZW5kcG9pbnRfcmVjb3JkLmdldChFUlJPUl9DT1VOVCkKICAgICAgICAgICAgICAgIGlmIGVycm9yX2NvdW50OgogICAgICAgICAgICAgICAgICAgIHNlbGYuZXJyb3JfY291bnRbZW5kcG9pbnRfaWRdID0gZXJyb3JfY291bnQKICAgICAgICAgICAgc2VsZi5lbmRwb2ludHMuYWRkKGVuZHBvaW50X2lkKQoKICAgIGRlZiBpc192YWxpZCgKICAgICAgICBzZWxmLCBlbmRwb2ludF9pZDogc3RyLCB2YWxpZGF0aW9uX2Z1bmN0aW9uLCBmaWVsZDogQW55LCBkaWN0X3BhdGg6IExpc3Rbc3RyXQogICAgKToKICAgICAgICBpZiB2YWxpZGF0aW9uX2Z1bmN0aW9uKGZpZWxkLCBkaWN0X3BhdGgpOgogICAgICAgICAgICByZXR1cm4gVHJ1ZQogICAgICAgIHNlbGYuZXJyb3JfY291bnRbZW5kcG9pbnRfaWRdICs9IDEKICAgICAgICByZXR1cm4gRmFsc2UKCiAgICBkZWYgaGFuZGxlX2Vycm9ycyhzZWxmLCBlbmRwb2ludF9pZCwgZXZlbnQpIC0+IGJvb2w6CiAgICAgICAgaWYgImVycm9yIiBpbiBldmVudDoKICAgICAgICAgICAgc2VsZi5lcnJvcl9jb3VudFtlbmRwb2ludF9pZF0gKz0gMQogICAgICAgICAgICByZXR1cm4gVHJ1ZQoKICAgICAgICByZXR1cm4gRmFsc2UKCgpkZWYgZW5yaWNoX2V2ZW5fZGV0YWlscyhldmVudCkgLT4gT3B0aW9uYWxbZGljdF06CiAgICBmdW5jdGlvbl91cmkgPSBldmVudC5nZXQoRlVOQ1RJT05fVVJJKQoKICAgIGlmIG5vdCBpc19ub3Rfbm9uZShmdW5jdGlvbl91cmksIFtGVU5DVElPTl9VUkldKToKICAgICAgICByZXR1cm4gTm9uZQoKICAgIG1vZGVsID0gZXZlbnQuZ2V0KE1PREVMKQogICAgaWYgbm90IGlzX25vdF9ub25lKG1vZGVsLCBbTU9ERUxdKToKICAgICAgICByZXR1cm4gTm9uZQoKICAgIHZlcnNpb24gPSBldmVudC5nZXQoVkVSU0lPTikKICAgIHZlcnNpb25lZF9tb2RlbCA9IGYie21vZGVsfTp7dmVyc2lvbn0iIGlmIHZlcnNpb24gZWxzZSBmInttb2RlbH06bGF0ZXN0IgoKICAgIGVuZHBvaW50X2lkID0gY3JlYXRlX21vZGVsX2VuZHBvaW50X2lkKAogICAgICAgIGZ1bmN0aW9uX3VyaT1mdW5jdGlvbl91cmksCiAgICAgICAgdmVyc2lvbmVkX21vZGVsPXZlcnNpb25lZF9tb2RlbCwKICAgICkKCiAgICBlbmRwb2ludF9pZCA9IHN0cihlbmRwb2ludF9pZCkKCiAgICBldmVudFtWRVJTSU9ORURfTU9ERUxdID0gdmVyc2lvbmVkX21vZGVsCiAgICBldmVudFtFTkRQT0lOVF9JRF0gPSBlbmRwb2ludF9pZAoKICAgIHJldHVybiBldmVudAoKCmRlZiBpc19ub3Rfbm9uZShmaWVsZDogQW55LCBkaWN0X3BhdGg6IExpc3Rbc3RyXSk6CiAgICBpZiBmaWVsZCBpcyBub3QgTm9uZToKICAgICAgICByZXR1cm4gVHJ1ZQogICAgbG9nZ2VyLmVycm9yKAogICAgICAgIGYiRXhwZWN0ZWQgZXZlbnQgZmllbGQgaXMgbWlzc2luZzoge2ZpZWxkfSBbRXZlbnQgLT4geycsJy5qb2luKGRpY3RfcGF0aCl9XSIKICAgICkKICAgIHJldHVybiBGYWxzZQoKCmNsYXNzIEZpbHRlckFuZFVucGFja0tleXMoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGtleXMsICoqa3dhcmdzKToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCoqa3dhcmdzKQogICAgICAgIHNlbGYua2V5cyA9IGtleXMKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQpOgogICAgICAgIG5ld19ldmVudCA9IHt9CiAgICAgICAgZm9yIGtleSBpbiBzZWxmLmtleXM6CiAgICAgICAgICAgIGlmIGtleSBpbiBldmVudDoKICAgICAgICAgICAgICAgIG5ld19ldmVudFtrZXldID0gZXZlbnRba2V5XQogICAgICAgIHVucGFja2VkID0ge30KICAgICAgICBmb3Iga2V5IGluIG5ld19ldmVudC5rZXlzKCk6CiAgICAgICAgICAgIGlmIGtleSBpbiBzZWxmLmtleXM6CiAgICAgICAgICAgICAgICB1bnBhY2tlZCA9IHsqKnVucGFja2VkLCAqKm5ld19ldmVudFtrZXldfQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgdW5wYWNrZWRba2V5XSA9IG5ld19ldmVudFtrZXldCiAgICAgICAgcmV0dXJuIHVucGFja2VkIGlmIHVucGFja2VkIGVsc2UgTm9uZQoKCmNsYXNzIE1hcEZlYXR1cmVOYW1lcyhNYXBDbGFzcyk6CiAgICBkZWYgX19pbml0X18oCiAgICAgICAgc2VsZiwKICAgICAgICBrdl9jb250YWluZXI6IHN0ciwKICAgICAgICBrdl9wYXRoOiBzdHIsCiAgICAgICAgYWNjZXNzX2tleTogc3RyLAogICAgICAgIGluZmVyX2NvbHVtbnNfZnJvbV9kYXRhOiBib29sID0gRmFsc2UsCiAgICAgICAgKiprd2FyZ3MsCiAgICApOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKiprd2FyZ3MpCiAgICAgICAgc2VsZi5rdl9jb250YWluZXIgPSBrdl9jb250YWluZXIKICAgICAgICBzZWxmLmt2X3BhdGggPSBrdl9wYXRoCiAgICAgICAgc2VsZi5hY2Nlc3Nfa2V5ID0gYWNjZXNzX2tleQogICAgICAgIHNlbGYuX2luZmVyX2NvbHVtbnNfZnJvbV9kYXRhID0gaW5mZXJfY29sdW1uc19mcm9tX2RhdGEKICAgICAgICBzZWxmLmZlYXR1cmVfbmFtZXMgPSB7fQogICAgICAgIHNlbGYubGFiZWxfY29sdW1ucyA9IHt9CgogICAgZGVmIF9pbmZlcl9mZWF0dXJlX25hbWVzX2Zyb21fZGF0YShzZWxmLCBldmVudCk6CiAgICAgICAgZm9yIGVuZHBvaW50X2lkIGluIHNlbGYuZmVhdHVyZV9uYW1lczoKICAgICAgICAgICAgaWYgbGVuKHNlbGYuZmVhdHVyZV9uYW1lc1tlbmRwb2ludF9pZF0pID49IGxlbihldmVudFtGRUFUVVJFU10pOgogICAgICAgICAgICAgICAgcmV0dXJuIHNlbGYuZmVhdHVyZV9uYW1lc1tlbmRwb2ludF9pZF0KICAgICAgICByZXR1cm4gTm9uZQoKICAgIGRlZiBfaW5mZXJfbGFiZWxfY29sdW1uc19mcm9tX2RhdGEoc2VsZiwgZXZlbnQpOgogICAgICAgIGZvciBlbmRwb2ludF9pZCBpbiBzZWxmLmxhYmVsX2NvbHVtbnM6CiAgICAgICAgICAgIGlmIGxlbihzZWxmLmxhYmVsX2NvbHVtbnNbZW5kcG9pbnRfaWRdKSA+PSBsZW4oZXZlbnRbUFJFRElDVElPTl0pOgogICAgICAgICAgICAgICAgcmV0dXJuIHNlbGYubGFiZWxfY29sdW1uc1tlbmRwb2ludF9pZF0KICAgICAgICByZXR1cm4gTm9uZQoKICAgIGRlZiBkbyhzZWxmLCBldmVudDogRGljdCk6CiAgICAgICAgZW5kcG9pbnRfaWQgPSBldmVudFtFTkRQT0lOVF9JRF0KCiAgICAgICAgaWYgZW5kcG9pbnRfaWQgbm90IGluIHNlbGYuZmVhdHVyZV9uYW1lczoKICAgICAgICAgICAgZW5kcG9pbnRfcmVjb3JkID0gZ2V0X2VuZHBvaW50X3JlY29yZCgKICAgICAgICAgICAgICAgIGt2X2NvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAgICAgIGt2X3BhdGg9c2VsZi5rdl9wYXRoLAogICAgICAgICAgICAgICAgZW5kcG9pbnRfaWQ9ZW5kcG9pbnRfaWQsCiAgICAgICAgICAgICAgICBhY2Nlc3Nfa2V5PXNlbGYuYWNjZXNzX2tleSwKICAgICAgICAgICAgKQogICAgICAgICAgICBmZWF0dXJlX25hbWVzID0gZW5kcG9pbnRfcmVjb3JkLmdldChGRUFUVVJFX05BTUVTKQogICAgICAgICAgICBmZWF0dXJlX25hbWVzID0ganNvbi5sb2FkcyhmZWF0dXJlX25hbWVzKSBpZiBmZWF0dXJlX25hbWVzIGVsc2UgTm9uZQoKICAgICAgICAgICAgbGFiZWxfY29sdW1ucyA9IGVuZHBvaW50X3JlY29yZC5nZXQoTEFCRUxfQ09MVU1OUykKICAgICAgICAgICAgbGFiZWxfY29sdW1ucyA9IGpzb24ubG9hZHMobGFiZWxfY29sdW1ucykgaWYgbGFiZWxfY29sdW1ucyBlbHNlIE5vbmUKCiAgICAgICAgICAgIGlmIG5vdCBmZWF0dXJlX25hbWVzIGFuZCBzZWxmLl9pbmZlcl9jb2x1bW5zX2Zyb21fZGF0YToKICAgICAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMgPSBzZWxmLl9pbmZlcl9mZWF0dXJlX25hbWVzX2Zyb21fZGF0YShldmVudCkKCiAgICAgICAgICAgIGlmIG5vdCBmZWF0dXJlX25hbWVzOgogICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oCiAgICAgICAgICAgICAgICAgICAgIkZlYXR1cmUgbmFtZXMgYXJlIG5vdCBpbml0aWFsaXplZCwgdGhleSB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIiwKICAgICAgICAgICAgICAgICAgICBlbmRwb2ludF9pZD1lbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMgPSBbZiJme2l9IiBmb3IgaSwgXyBpbiBlbnVtZXJhdGUoZXZlbnRbRkVBVFVSRVNdKV0KICAgICAgICAgICAgICAgIGdldF92M2lvX2NsaWVudCgpLmt2LnVwZGF0ZSgKICAgICAgICAgICAgICAgICAgICBjb250YWluZXI9c2VsZi5rdl9jb250YWluZXIsCiAgICAgICAgICAgICAgICAgICAgdGFibGVfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgICAgICAgICAgYWNjZXNzX2tleT1zZWxmLmFjY2Vzc19rZXksCiAgICAgICAgICAgICAgICAgICAga2V5PWV2ZW50W0VORFBPSU5UX0lEXSwKICAgICAgICAgICAgICAgICAgICBhdHRyaWJ1dGVzPXtGRUFUVVJFX05BTUVTOiBqc29uLmR1bXBzKGZlYXR1cmVfbmFtZXMpfSwKICAgICAgICAgICAgICAgICAgICByYWlzZV9mb3Jfc3RhdHVzPVJhaXNlRm9yU3RhdHVzLmFsd2F5cywKICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgIGlmIG5vdCBsYWJlbF9jb2x1bW5zIGFuZCBzZWxmLl9pbmZlcl9jb2x1bW5zX2Zyb21fZGF0YToKICAgICAgICAgICAgICAgIGxhYmVsX2NvbHVtbnMgPSBzZWxmLl9pbmZlcl9sYWJlbF9jb2x1bW5zX2Zyb21fZGF0YShldmVudCkKCiAgICAgICAgICAgIGlmIG5vdCBsYWJlbF9jb2x1bW5zOgogICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oCiAgICAgICAgICAgICAgICAgICAgImxhYmVsIGNvbHVtbiBuYW1lcyBhcmUgbm90IGluaXRpYWxpemVkLCB0aGV5IHdpbGwgYmUgYXV0b21hdGljYWxseSBnZW5lcmF0ZWQiLAogICAgICAgICAgICAgICAgICAgIGVuZHBvaW50X2lkPWVuZHBvaW50X2lkLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgbGFiZWxfY29sdW1ucyA9IFtmInB7aX0iIGZvciBpLCBfIGluIGVudW1lcmF0ZShldmVudFtQUkVESUNUSU9OXSldCiAgICAgICAgICAgICAgICBnZXRfdjNpb19jbGllbnQoKS5rdi51cGRhdGUoCiAgICAgICAgICAgICAgICAgICAgY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICAgICAgICAgIHRhYmxlX3BhdGg9c2VsZi5rdl9wYXRoLAogICAgICAgICAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi5hY2Nlc3Nfa2V5LAogICAgICAgICAgICAgICAgICAgIGtleT1ldmVudFtFTkRQT0lOVF9JRF0sCiAgICAgICAgICAgICAgICAgICAgYXR0cmlidXRlcz17TEFCRUxfQ09MVU1OUzoganNvbi5kdW1wcyhsYWJlbF9jb2x1bW5zKX0sCiAgICAgICAgICAgICAgICAgICAgcmFpc2VfZm9yX3N0YXR1cz1SYWlzZUZvclN0YXR1cy5hbHdheXMsCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICBzZWxmLmxhYmVsX2NvbHVtbnNbZW5kcG9pbnRfaWRdID0gbGFiZWxfY29sdW1ucwogICAgICAgICAgICBzZWxmLmZlYXR1cmVfbmFtZXNbZW5kcG9pbnRfaWRdID0gZmVhdHVyZV9uYW1lcwoKICAgICAgICAgICAgbG9nZ2VyLmluZm8oCiAgICAgICAgICAgICAgICAiTGFiZWwgY29sdW1ucyIsIGVuZHBvaW50X2lkPWVuZHBvaW50X2lkLCBsYWJlbF9jb2x1bW5zPWxhYmVsX2NvbHVtbnMKICAgICAgICAgICAgKQogICAgICAgICAgICBsb2dnZXIuaW5mbygKICAgICAgICAgICAgICAgICJGZWF0dXJlIG5hbWVzIiwgZW5kcG9pbnRfaWQ9ZW5kcG9pbnRfaWQsIGZlYXR1cmVfbmFtZXM9ZmVhdHVyZV9uYW1lcwogICAgICAgICAgICApCgogICAgICAgIGZlYXR1cmVfbmFtZXMgPSBzZWxmLmZlYXR1cmVfbmFtZXNbZW5kcG9pbnRfaWRdCiAgICAgICAgZmVhdHVyZXMgPSBldmVudFtGRUFUVVJFU10KICAgICAgICBldmVudFtOQU1FRF9GRUFUVVJFU10gPSB7CiAgICAgICAgICAgIG5hbWU6IGZlYXR1cmUgZm9yIG5hbWUsIGZlYXR1cmUgaW4gemlwKGZlYXR1cmVfbmFtZXMsIGZlYXR1cmVzKQogICAgICAgIH0KCiAgICAgICAgbGFiZWxfY29sdW1ucyA9IHNlbGYubGFiZWxfY29sdW1uc1tlbmRwb2ludF9pZF0KICAgICAgICBwcmVkaWN0aW9uID0gZXZlbnRbUFJFRElDVElPTl0KICAgICAgICBldmVudFtOQU1FRF9QUkVESUNUSU9OU10gPSB7CiAgICAgICAgICAgIG5hbWU6IHByZWRpY3Rpb24gZm9yIG5hbWUsIHByZWRpY3Rpb24gaW4gemlwKGxhYmVsX2NvbHVtbnMsIHByZWRpY3Rpb24pCiAgICAgICAgfQogICAgICAgIGxvZ2dlci5pbmZvKCJNYXBwZWQgZXZlbnQiLCBldmVudD1ldmVudCkKICAgICAgICByZXR1cm4gZXZlbnQKCgpjbGFzcyBXcml0ZVRvS1YoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGNvbnRhaW5lcjogc3RyLCB0YWJsZTogc3RyLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKICAgICAgICBzZWxmLmNvbnRhaW5lciA9IGNvbnRhaW5lcgogICAgICAgIHNlbGYudGFibGUgPSB0YWJsZQoKICAgIGRlZiBkbyhzZWxmLCBldmVudDogRGljdCk6CiAgICAgICAgZ2V0X3YzaW9fY2xpZW50KCkua3YudXBkYXRlKAogICAgICAgICAgICBjb250YWluZXI9c2VsZi5jb250YWluZXIsCiAgICAgICAgICAgIHRhYmxlX3BhdGg9c2VsZi50YWJsZSwKICAgICAgICAgICAga2V5PWV2ZW50W0VORFBPSU5UX0lEXSwKICAgICAgICAgICAgYXR0cmlidXRlcz1ldmVudCwKICAgICAgICApCiAgICAgICAgcmV0dXJuIGV2ZW50CgoKY2xhc3MgSW5mZXJTY2hlbWEoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgdjNpb19hY2Nlc3Nfa2V5OiBzdHIsCiAgICAgICAgdjNpb19mcmFtZXNkOiBzdHIsCiAgICAgICAgY29udGFpbmVyOiBzdHIsCiAgICAgICAgdGFibGU6IHN0ciwKICAgICAgICAqKmt3YXJncywKICAgICk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKICAgICAgICBzZWxmLmNvbnRhaW5lciA9IGNvbnRhaW5lcgogICAgICAgIHNlbGYudjNpb19hY2Nlc3Nfa2V5ID0gdjNpb19hY2Nlc3Nfa2V5CiAgICAgICAgc2VsZi52M2lvX2ZyYW1lc2QgPSB2M2lvX2ZyYW1lc2QKICAgICAgICBzZWxmLnRhYmxlID0gdGFibGUKICAgICAgICBzZWxmLmtleXMgPSBzZXQoKQoKICAgIGRlZiBkbyhzZWxmLCBldmVudDogRGljdCk6CiAgICAgICAga2V5X3NldCA9IHNldChldmVudC5rZXlzKCkpCiAgICAgICAgaWYgbm90IGtleV9zZXQuaXNzdWJzZXQoc2VsZi5rZXlzKToKICAgICAgICAgICAgc2VsZi5rZXlzLnVwZGF0ZShrZXlfc2V0KQogICAgICAgICAgICBnZXRfZnJhbWVzX2NsaWVudCgKICAgICAgICAgICAgICAgIHRva2VuPXNlbGYudjNpb19hY2Nlc3Nfa2V5LAogICAgICAgICAgICAgICAgY29udGFpbmVyPXNlbGYuY29udGFpbmVyLAogICAgICAgICAgICAgICAgYWRkcmVzcz1zZWxmLnYzaW9fZnJhbWVzZCwKICAgICAgICAgICAgKS5leGVjdXRlKGJhY2tlbmQ9Imt2IiwgdGFibGU9c2VsZi50YWJsZSwgY29tbWFuZD0iaW5mZXJfc2NoZW1hIikKICAgICAgICAgICAgbG9nZ2VyLmluZm8oCiAgICAgICAgICAgICAgICAiRm91bmQgbmV3IGtleXMsIGluZmVycmVkIHNjaGVtYSIsIHRhYmxlPXNlbGYudGFibGUsIGV2ZW50PWV2ZW50CiAgICAgICAgICAgICkKICAgICAgICByZXR1cm4gZXZlbnQKCgpkZWYgZ2V0X2VuZHBvaW50X3JlY29yZCgKICAgIGt2X2NvbnRhaW5lcjogc3RyLCBrdl9wYXRoOiBzdHIsIGVuZHBvaW50X2lkOiBzdHIsIGFjY2Vzc19rZXk6IHN0cgopIC0+IE9wdGlvbmFsW2RpY3RdOgogICAgbG9nZ2VyLmluZm8oCiAgICAgICAgIkdyYWJiaW5nIGVuZHBvaW50IGRhdGEiLAogICAgICAgIGNvbnRhaW5lcj1rdl9jb250YWluZXIsCiAgICAgICAgdGFibGVfcGF0aD1rdl9wYXRoLAogICAgICAgIGtleT1lbmRwb2ludF9pZCwKICAgICkKICAgIHRyeToKICAgICAgICBlbmRwb2ludF9yZWNvcmQgPSAoCiAgICAgICAgICAgIGdldF92M2lvX2NsaWVudCgpCiAgICAgICAgICAgIC5rdi5nZXQoCiAgICAgICAgICAgICAgICBjb250YWluZXI9a3ZfY29udGFpbmVyLAogICAgICAgICAgICAgICAgdGFibGVfcGF0aD1rdl9wYXRoLAogICAgICAgICAgICAgICAga2V5PWVuZHBvaW50X2lkLAogICAgICAgICAgICAgICAgYWNjZXNzX2tleT1hY2Nlc3Nfa2V5LAogICAgICAgICAgICAgICAgcmFpc2VfZm9yX3N0YXR1cz12M2lvLmRhdGFwbGFuZS5SYWlzZUZvclN0YXR1cy5hbHdheXMsCiAgICAgICAgICAgICkKICAgICAgICAgICAgLm91dHB1dC5pdGVtCiAgICAgICAgKQogICAgICAgIHJldHVybiBlbmRwb2ludF9yZWNvcmQKICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgcmV0dXJuIE5vbmUKCmZyb20gbWxydW4ucnVudGltZXMgaW1wb3J0IG51Y2xpb19pbml0X2hvb2sKZGVmIGluaXRfY29udGV4dChjb250ZXh0KToKICAgIG51Y2xpb19pbml0X2hvb2soY29udGV4dCwgZ2xvYmFscygpLCAnc2VydmluZ192MicpCgpkZWYgaGFuZGxlcihjb250ZXh0LCBldmVudCk6CiAgICByZXR1cm4gY29udGV4dC5tbHJ1bl9oYW5kbGVyKGNvbnRleHQsIGV2ZW50KQo=", - "baseImage": "datanode-registry.iguazio-platform.app.product-3-4.iguazio-cd1.com:80/quay.io/mlrun/mlrun:1.0.0" - }, - "triggers": { - "monitoring_stream_trigger": { - "kind": "v3ioStream", - "url": "http://v3io-webapi:8081", - "attributes": { - "containerName": "users", - "streamPath": "pipelines/default/model-endpoints/stream", - "consumerGroup": "serving", - "sequenceNumberCommitInterval": "1s", - "workerAllocationMode": "pool", - "sessionTimeout": "10s", - "heartbeatInterval": "3s", - "seekTo": "earliest", - "readBatchSize": 256, - "pollingIntervalMs": 500 - }, - "name": "monitoring_stream_trigger", - "maxWorkers": 1, - "password": "76ceea19-4b10-47d9-afbb-f687c91b9231" - }, - "http": { - "kind": "http", - "name": "http", - "maxWorkers": 1, - "workerAvailabilityTimeoutMilliseconds": 10000, - "attributes": { - "ingresses": { - "0": { - "paths": [ - "/" - ], - "hostTemplate": "@nuclio.fromDefault" - } - }, - "serviceType": "ClusterIP" - } - } - }, - "serviceType": "ClusterIP", - "resources": { - "requests": { - "memory": "1Mi", - "cpu": "25m" - }, - "limits": { - "memory": "20Gi", - "cpu": "2" - } - }, - "PreemptionMode": "prevent", - "priorityClassName": "igz-workload-medium", - "minReplicas": 1, - "maxReplicas": 1 - } + "PreemptionMode": "prevent", + "priorityClassName": "igz-workload-medium", + "minReplicas": 1, + "maxReplicas": 1 + } }, "source": "", "function_kind": "serving_v2", "graph": { - "steps": { - "ProcessEndpointEvent": { - "kind": "task", - "class_name": "ProcessEndpointEvent", - "class_args": { - "kv_container": "users", - "kv_path": "pipelines/default/model-endpoints/endpoints/", - "v3io_access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231" - }, - "full_event": true - }, - "filter_none": { - "kind": "task", - "class_name": "storey.Filter", - "class_args": { - "_fn": "(event is not None)" - }, - "after": [ - "ProcessEndpointEvent" - ] - }, - "flatten_events": { - "kind": "task", - "class_name": "storey.FlatMap", - "class_args": { - "_fn": "(event)" - }, - "after": [ - "filter_none" - ] - }, - "MapFeatureNames": { - "kind": "task", - "class_name": "MapFeatureNames", - "class_args": { - "kv_container": "users", - "kv_path": "pipelines/default/model-endpoints/endpoints/", - "access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", - "infer_columns_from_data": true - }, - "after": [ - "flatten_events" - ] - }, - "Aggregates": { - "kind": "task", - "class_name": "storey.AggregateByKey", - "class_args": { - "aggregates": [ - { - "name": "predictions", - "column": "endpoint_id", - "operations": [ - "count" - ], - "windows": [ - "5m", - "1h" - ], - "period": "30s" - }, - { - "name": "latency", - "column": "latency", - "operations": [ - "avg" - ], - "windows": [ - "5m", - "1h" - ], - "period": "30s" - } - ], - "table": "." - }, - "after": [ - "MapFeatureNames" - ] - }, - "sample": { - "kind": "task", - "class_name": "storey.steps.SampleWindow", - "class_args": { - "window_size": 10, - "key": "endpoint_id" - }, - "after": [ - "Aggregates" - ] - }, - "ProcessBeforeKV": { - "kind": "task", - "class_name": "ProcessBeforeKV", - "after": [ - "sample" - ] - }, - "WriteToKV": { - "kind": "task", - "class_name": "WriteToKV", - "class_args": { - "container": "users", - "table": "pipelines/default/model-endpoints/endpoints/" - }, - "after": [ - "ProcessBeforeKV" - ] - }, - "InferSchema": { - "kind": "task", - "class_name": "InferSchema", - "class_args": { - "v3io_access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", - "v3io_framesd": "http://framesd:8080", - "container": "users", - "table": "pipelines/default/model-endpoints/endpoints/" - }, - "after": [ - "WriteToKV" - ] - }, - "ProcessBeforeTSDB": { - "kind": "task", - "class_name": "ProcessBeforeTSDB", - "after": [ - "sample" - ] - }, - "FilterAndUnpackKeys1": { - "kind": "task", - "class_name": "FilterAndUnpackKeys", - "class_args": { - "keys": [ - "base_metrics" - ] - }, - "after": [ - "ProcessBeforeTSDB" - ] - }, - "tsdb1": { - "kind": "task", - "class_name": "storey.TSDBTarget", - "class_args": { - "path": "users/pipelines/default/model-endpoints/events/", - "rate": "10/m", - "time_col": "timestamp", - "container": "users", - "access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", - "v3io_frames": "http://framesd:8080", - "index_cols": [ - "endpoint_id", - "record_type" - ], - "max_events": 10, - "timeout_secs": 300, - "key": "endpoint_id" - }, - "after": [ - "FilterAndUnpackKeys1" - ] - }, - "FilterAndUnpackKeys2": { - "kind": "task", - "class_name": "FilterAndUnpackKeys", - "class_args": { - "keys": [ - "endpoint_features" - ] - }, - "after": [ - "ProcessBeforeTSDB" - ] - }, - "tsdb2": { - "kind": "task", - "class_name": "storey.TSDBTarget", - "class_args": { - "path": "users/pipelines/default/model-endpoints/events/", - "rate": "10/m", - "time_col": "timestamp", - "container": "users", - "access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", - "v3io_frames": "http://framesd:8080", - "index_cols": [ - "endpoint_id", - "record_type" - ], - "max_events": 10, - "timeout_secs": 300, - "key": "endpoint_id" - }, - "after": [ - "FilterAndUnpackKeys2" - ] - }, - "FilterAndUnpackKeys3": { - "kind": "task", - "class_name": "FilterAndUnpackKeys", - "class_args": { - "keys": [ - "custom_metrics" - ] - }, - "after": [ - "ProcessBeforeTSDB" - ] - }, - "FilterNotNone": { - "kind": "task", - "class_name": "storey.Filter", - "class_args": { - "_fn": "(event is not None)" - }, - "after": [ - "FilterAndUnpackKeys3" - ] - }, - "tsdb3": { - "kind": "task", - "class_name": "storey.TSDBTarget", - "class_args": { - "path": "users/pipelines/default/model-endpoints/events/", - "rate": "10/m", - "time_col": "timestamp", - "container": "users", - "access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", - "v3io_frames": "http://framesd:8080", - "index_cols": [ - "endpoint_id", - "record_type" - ], - "max_events": 10, - "timeout_secs": 300, - "key": "endpoint_id" - }, - "after": [ - "FilterNotNone" - ] - }, - "ProcessBeforeParquet": { - "kind": "task", - "class_name": "ProcessBeforeParquet", - "class_args": { - "_fn": "(event)" - }, - "after": [ - "MapFeatureNames" - ] - } + "steps": { + "ProcessEndpointEvent": { + "kind": "task", + "class_name": "ProcessEndpointEvent", + "class_args": { + "kv_container": "users", + "kv_path": "pipelines/default/model-endpoints/endpoints/", + "v3io_access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231" + }, + "full_event": true + }, + "filter_none": { + "kind": "task", + "class_name": "storey.Filter", + "class_args": { + "_fn": "(event is not None)" + }, + "after": [ + "ProcessEndpointEvent" + ] + }, + "flatten_events": { + "kind": "task", + "class_name": "storey.FlatMap", + "class_args": { + "_fn": "(event)" + }, + "after": [ + "filter_none" + ] + }, + "MapFeatureNames": { + "kind": "task", + "class_name": "MapFeatureNames", + "class_args": { + "kv_container": "users", + "kv_path": "pipelines/default/model-endpoints/endpoints/", + "access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", + "infer_columns_from_data": true + }, + "after": [ + "flatten_events" + ] + }, + "Aggregates": { + "kind": "task", + "class_name": "storey.AggregateByKey", + "class_args": { + "aggregates": [ + { + "name": "predictions", + "column": "endpoint_id", + "operations": [ + "count" + ], + "windows": [ + "5m", + "1h" + ], + "period": "30s" + }, + { + "name": "latency", + "column": "latency", + "operations": [ + "avg" + ], + "windows": [ + "5m", + "1h" + ], + "period": "30s" + } + ], + "table": "." + }, + "after": [ + "MapFeatureNames" + ] + }, + "sample": { + "kind": "task", + "class_name": "storey.steps.SampleWindow", + "class_args": { + "window_size": 10, + "key": "endpoint_id" + }, + "after": [ + "Aggregates" + ] + }, + "ProcessBeforeKV": { + "kind": "task", + "class_name": "ProcessBeforeKV", + "after": [ + "sample" + ] + }, + "WriteToKV": { + "kind": "task", + "class_name": "WriteToKV", + "class_args": { + "container": "users", + "table": "pipelines/default/model-endpoints/endpoints/" + }, + "after": [ + "ProcessBeforeKV" + ] + }, + "InferSchema": { + "kind": "task", + "class_name": "InferSchema", + "class_args": { + "v3io_access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", + "v3io_framesd": "http://framesd:8080", + "container": "users", + "table": "pipelines/default/model-endpoints/endpoints/" + }, + "after": [ + "WriteToKV" + ] + }, + "ProcessBeforeTSDB": { + "kind": "task", + "class_name": "ProcessBeforeTSDB", + "after": [ + "sample" + ] + }, + "FilterAndUnpackKeys1": { + "kind": "task", + "class_name": "FilterAndUnpackKeys", + "class_args": { + "keys": [ + "base_metrics" + ] + }, + "after": [ + "ProcessBeforeTSDB" + ] + }, + "tsdb1": { + "kind": "task", + "class_name": "storey.TSDBTarget", + "class_args": { + "path": "users/pipelines/default/model-endpoints/events/", + "rate": "10/m", + "time_col": "timestamp", + "container": "users", + "access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", + "v3io_frames": "http://framesd:8080", + "index_cols": [ + "endpoint_id", + "record_type" + ], + "max_events": 10, + "timeout_secs": 300, + "key": "endpoint_id" + }, + "after": [ + "FilterAndUnpackKeys1" + ] + }, + "FilterAndUnpackKeys2": { + "kind": "task", + "class_name": "FilterAndUnpackKeys", + "class_args": { + "keys": [ + "endpoint_features" + ] + }, + "after": [ + "ProcessBeforeTSDB" + ] + }, + "tsdb2": { + "kind": "task", + "class_name": "storey.TSDBTarget", + "class_args": { + "path": "users/pipelines/default/model-endpoints/events/", + "rate": "10/m", + "time_col": "timestamp", + "container": "users", + "access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", + "v3io_frames": "http://framesd:8080", + "index_cols": [ + "endpoint_id", + "record_type" + ], + "max_events": 10, + "timeout_secs": 300, + "key": "endpoint_id" + }, + "after": [ + "FilterAndUnpackKeys2" + ] }, - "final_step": "ProcessBeforeParquet" + "FilterAndUnpackKeys3": { + "kind": "task", + "class_name": "FilterAndUnpackKeys", + "class_args": { + "keys": [ + "custom_metrics" + ] + }, + "after": [ + "ProcessBeforeTSDB" + ] + }, + "FilterNotNone": { + "kind": "task", + "class_name": "storey.Filter", + "class_args": { + "_fn": "(event is not None)" + }, + "after": [ + "FilterAndUnpackKeys3" + ] + }, + "tsdb3": { + "kind": "task", + "class_name": "storey.TSDBTarget", + "class_args": { + "path": "users/pipelines/default/model-endpoints/events/", + "rate": "10/m", + "time_col": "timestamp", + "container": "users", + "access_key": "76ceea19-4b10-47d9-afbb-f687c91b9231", + "v3io_frames": "http://framesd:8080", + "index_cols": [ + "endpoint_id", + "record_type" + ], + "max_events": 10, + "timeout_secs": 300, + "key": "endpoint_id" + }, + "after": [ + "FilterNotNone" + ] + }, + "ProcessBeforeParquet": { + "kind": "task", + "class_name": "ProcessBeforeParquet", + "class_args": { + "_fn": "(event)" + }, + "after": [ + "MapFeatureNames" + ] + } + }, + "final_step": "ProcessBeforeParquet" }, "graph_initializer": "mlrun.feature_store.ingestion.featureset_initializer", "parameters": { - "infer_options": 0, - "overwrite": null, - "featureset": "store://feature-sets/default/monitoring", - "source": { - "kind": "http", - "online": true - }, - "targets": [ - { - "name": "parquet", - "kind": "parquet", - "path": "v3io:///projects/default/model-endpoints/parquet", - "after_step": "ProcessBeforeParquet", - "attributes": { - "infer_columns_from_data": true - }, - "partitioned": true, - "key_bucketing_number": 0, - "time_partitioning_granularity": "hour", - "max_events": 10000, - "flush_after_seconds": 1800, - "storage_options": { - "v3io_access_key": "55a0d13c-7d9a-44ab-a556-dd213d8c7165", - "v3io_api": "http://v3io-webapi:8081" - } - } - ] + "infer_options": 0, + "overwrite": null, + "featureset": "store://feature-sets/default/monitoring", + "source": { + "kind": "http", + "online": true + }, + "targets": [ + { + "name": "parquet", + "kind": "parquet", + "path": "v3io:///projects/default/model-endpoints/parquet", + "after_step": "ProcessBeforeParquet", + "attributes": { + "infer_columns_from_data": true + }, + "partitioned": true, + "key_bucketing_number": 0, + "time_partitioning_granularity": "hour", + "max_events": 10000, + "flush_after_seconds": 1800, + "storage_options": { + "v3io_access_key": "55a0d13c-7d9a-44ab-a556-dd213d8c7165", + "v3io_api": "http://v3io-webapi:8081" + } + } + ] }, "secret_sources": [], "affinity": null, "tolerations": null - }, - "status": { + }, + "status": { "nuclio_name": "default-model-monitoring-stream", "internal_invocation_urls": [], "external_invocation_urls": [] + }, + "verbose": false }, - "verbose": false -}, { "kind": "job", "metadata": { @@ -30503,8 +30506,8 @@ "updated": "2025-09-04T12:45:44.659000+00:00", "project": "default", "tag": "latest", - "name": "test-func-oyn", - "uid": "93124a9c66fcefbe27b24109a729691f8dbea5c0" + "name": "test-func-oyn", + "uid": "93124a9c66fcefbe27b24109a729691f8dbea5c0" }, "verbose": false, "spec": { diff --git a/tests/mockServer/mock.js b/tests/mockServer/mock.js index c052302d8d..13f5109b70 100644 --- a/tests/mockServer/mock.js +++ b/tests/mockServer/mock.js @@ -836,7 +836,10 @@ function getMonitoringApplications(req, res) { const collectedMonitoringApplications = (monitoringApplications[req.params['project']] || []).map( application => ({ ...application, - stats: { ...omit(application.stats, ['shards', 'processed_model_endpoints', 'metrics']), stream_stats: application.stats.stream_stats['0']} + stats: { + ...omit(application.stats, ['shards', 'processed_model_endpoints', 'metrics']), + stream_stats: application.stats.stream_stats['0'] + } }) ) @@ -2380,7 +2383,7 @@ function putTags(req, res) { ) }) - // handle existing artifacts with same name and tag + // handle existing artifacts with same name and tag collectedArtifactsWithSameName.forEach(artifact => { if (artifact.metadata?.tag === tagName) { if ( @@ -2661,7 +2664,7 @@ function getModelEndpoints(req, res) { if (req.query['endpoint-id']) { const modelEndpoint = collectedEndpoints.find( - endpoint => endpoint.metadata.uid === req.query.endpoint-id + endpoint => endpoint.metadata.uid === req.query['endpoint-id'] ) return res.send(modelEndpoint) From 8e222ffb432152e55207534b65137eb42e7f8f5e Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 13 Nov 2025 12:36:37 +0200 Subject: [PATCH 214/228] =?UTF-8?q?Fix=20[UI]=20Show=20=E2=80=9CN/A?= =?UTF-8?q?=E2=80=9D=20instead=20of=200=20when=20a=20Project=20Summary=20c?= =?UTF-8?q?ounter=20cannot=20be=20retrieved=20(#3497)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoringApplicationCounters.util.jsx | 22 ++++---- .../ProjectStatisticsCounter.jsx | 6 +- .../AlertsCounters.jsx | 31 +++++----- .../ArtifactsCounters.jsx | 23 +++----- .../ModelsCounters.jsx | 6 +- .../ScheduledJobsCounters.jsx | 16 ++---- .../WorkflowsCounters.jsx | 19 ++----- src/utils/generateAlertsStats.js | 8 +-- src/utils/generateMonitoringData.js | 56 ++++++++++++------- 9 files changed, 87 insertions(+), 100 deletions(-) diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx index 48c308b72b..fb8fb3a028 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplicationCounters/monitoringApplicationCounters.util.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { capitalize } from 'lodash' +import { capitalize, isEmpty } from 'lodash' import classNames from 'classnames' import { aggregateApplicationStatuses } from '../../../../utils/applications.utils' @@ -110,17 +110,17 @@ export const generateCountersContent = (params, monitoringApplicationsStore) => } ] - const aggregatedStreamStats = Object.values( - monitoringApplication?.stats?.stream_stats || {} - ).reduce( - (acc, { committed, lag }) => { - acc.committed += committed - acc.lag += lag + const aggregatedStreamStats = !isEmpty(monitoringApplication?.stats?.stream_stats) + ? Object.values(monitoringApplication.stats.stream_stats).reduce( + (acc, { committed, lag }) => { + acc.committed += committed + acc.lag += lag - return acc - }, - { committed: 0, lag: 0 } - ) + return acc + }, + { committed: 0, lag: 0 } + ) + : { committed: 'N/A', lag: 'N/A' } const applicationCountersContent = [ { id: 'appStatus', diff --git a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx index eec9d4baad..f303188b01 100644 --- a/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx +++ b/src/elements/ProjectStatisticsCounter/ProjectStatisticsCounter.jsx @@ -64,7 +64,7 @@ const ProjectStatisticsCounter = ({ counterObject }) => { ) : ( <> - {generatedCountersContent.value} + {generatedCountersContent.value ?? 'N/A'} )} @@ -87,7 +87,7 @@ const ProjectStatisticsCounter = ({ counterObject }) => { textShow={Boolean(generatedCountersContent.tooltip)} template={} > - {generatedCountersContent.value} + {generatedCountersContent.value ?? 'N/A'} @@ -97,7 +97,7 @@ const ProjectStatisticsCounter = ({ counterObject }) => { className="project-data-card__statistics-label" key={counterObject.label + Math.random()} > - {counterObject.label} + {counterObject.label ?? 'N/A'} {counterObject.status && }
      ] diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index 11236643e8..719176febf 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -27,6 +27,7 @@ import { Loader, PopUpDialog } from 'igz-controls/components' import StatsCard from '../../common/StatsCard/StatsCard' import { generateAlertsStats } from '../../utils/generateAlertsStats' +import { countTotalValue } from '../../utils/generateMonitoringData' import Alerts from 'igz-controls/images/alerts.svg?react' import ClockIcon from 'igz-controls/images/clock.svg?react' @@ -52,17 +53,11 @@ const AlertsCounters = () => { const alertsData = useMemo(() => { const projectName = paramProjectName ? paramProjectName : '*' - const defaultAlertData = { - endpoint: 0, - jobs: 0, - application: 0, - total: 0 - } if (projectName !== '*') { - const endpoint = projectStore?.projectSummary?.data?.endpoint_alerts_count || 0 - const jobs = projectStore?.projectSummary?.data?.job_alerts_count || 0 - const application = projectStore?.projectSummary?.data?.other_alerts_count || 0 + const endpoint = projectStore?.projectSummary?.data?.endpoint_alerts_count + const jobs = projectStore?.projectSummary?.data?.job_alerts_count + const application = projectStore?.projectSummary?.data?.other_alerts_count return { projectName, @@ -70,14 +65,14 @@ const AlertsCounters = () => { endpoint, jobs, application, - total: endpoint + jobs + application + total: countTotalValue([endpoint, jobs, application]) } } } return { projectName, - data: defaults({}, projectStore?.jobsMonitoringData?.alerts, defaultAlertData) + data: defaults({}, projectStore?.jobsMonitoringData?.alerts) } }, [ paramProjectName, @@ -117,7 +112,7 @@ const AlertsCounters = () => { {projectStore?.projectsSummary?.loading ? ( ) : ( - alertsData?.data?.total?.toLocaleString() + alertsStats.total?.counter?.toLocaleString?.() )} @@ -134,7 +129,7 @@ const AlertsCounters = () => { {projectStore?.projectsSummary?.loading ? ( ) : ( - alertsData?.data?.endpoint?.toLocaleString() + alertsStats.endpoints?.counter?.toLocaleString?.() )}
      @@ -150,7 +145,7 @@ const AlertsCounters = () => { {projectStore?.projectsSummary?.loading ? ( ) : ( - alertsData?.data?.jobs?.toLocaleString() + alertsStats.job?.counter?.toLocaleString?.() )}
      @@ -166,7 +161,7 @@ const AlertsCounters = () => { {projectStore.projectsSummary.loading ? ( ) : ( - alertsData?.data?.application?.toLocaleString() + alertsStats.application?.counter?.toLocaleString?.() )}
      @@ -183,13 +178,13 @@ const AlertsCounters = () => { >
      - Endpoint: {alertsData?.data?.endpoint} + Endpoint: {alertsStats.endpoints?.counter}
      - Jobs: {alertsData?.data?.jobs} + Jobs: {alertsStats.job?.counter}
      - Application: {alertsData?.data?.application} + Application: {alertsStats.application?.counter}
      diff --git a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx index 2207868ec6..4265a20f7d 100644 --- a/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ArtifactsCounters.jsx @@ -24,7 +24,7 @@ import { Loader, PopUpDialog } from 'igz-controls/components' import { ARTIFACTS_PAGE } from '../../constants' import StatsCard from '../../common/StatsCard/StatsCard' -import { generateMonitoringStats } from '../../utils/generateMonitoringData' +import { countTotalValue, generateMonitoringStats } from '../../utils/generateMonitoringData' import './projectsMonitoringCounters.scss' @@ -47,28 +47,20 @@ const ArtifactsCounters = () => { const dataStats = useMemo(() => { if (projectName) { - const llm_prompts = projectStore?.projectSummary?.data?.llm_prompts_count || 0 - const files = projectStore?.projectSummary?.data?.files_count || 0 - const documents = projectStore?.projectSummary?.data?.documents_count || 0 - const datasets = projectStore?.projectSummary?.data?.datasets_count || 0 + const llm_prompts = projectStore?.projectSummary?.data?.llm_prompts_count + const files = projectStore?.projectSummary?.data?.files_count + const documents = projectStore?.projectSummary?.data?.documents_count + const datasets = projectStore?.projectSummary?.data?.datasets_count return { llm_prompts, files, documents, datasets, - total: llm_prompts + files + datasets + documents + total: countTotalValue([llm_prompts, files, datasets, documents]) } } - return ( - projectStore.jobsMonitoringData.artifacts || { - llm_prompts: 0, - files: 0, - documents: 0, - datasets: 0, - total: 0 - } - ) + return projectStore.jobsMonitoringData.artifacts || {} }, [projectName, projectStore.jobsMonitoringData.artifacts, projectStore.projectSummary.data]) const data = useMemo( @@ -153,7 +145,6 @@ const ArtifactsCounters = () => { data?.files?.counter?.toLocaleString() )} -
      diff --git a/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx index a5c8d143b7..30190439af 100644 --- a/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ModelsCounters.jsx @@ -32,8 +32,8 @@ const ModelsAndApplication = () => { const navigate = useNavigate() const modelsData = projectName - ? projectStore.projectSummary.data?.models_count || 0 - : projectStore.jobsMonitoringData?.models?.total || 0 + ? projectStore.projectSummary.data?.models_count + : projectStore.jobsMonitoringData?.models?.total const data = useMemo( () => generateMonitoringStats(modelsData, navigate, MODELS_PAGE, projectName), @@ -54,7 +54,7 @@ const ModelsAndApplication = () => { ) : ( data?.models?.counter?.toLocaleString() )} - + ) diff --git a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx index 0bb0d3e39c..d014223213 100644 --- a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx @@ -24,7 +24,7 @@ import { useSelector } from 'react-redux' import { Loader, PopUpDialog } from 'igz-controls/components' import StatsCard from '../../common/StatsCard/StatsCard' -import { generateMonitoringStats } from '../../utils/generateMonitoringData' +import { countTotalValue, generateMonitoringStats } from '../../utils/generateMonitoringData' import { JOBS_MONITORING_SCHEDULED_TAB, SCHEDULE_TAB } from '../../constants' import ClockIcon from 'igz-controls/images/clock.svg?react' @@ -50,23 +50,17 @@ const ScheduledJobsCounters = () => { const scheduledData = useMemo(() => { if (projectName) { - const jobs = projectStore.projectSummary?.data?.distinct_scheduled_jobs_pending_count || 0 + const jobs = projectStore.projectSummary?.data?.distinct_scheduled_jobs_pending_count const workflows = - projectStore.projectSummary?.data?.distinct_scheduled_pipelines_pending_count || 0 + projectStore.projectSummary?.data?.distinct_scheduled_pipelines_pending_count return { jobs, workflows, - total: jobs + workflows + total: countTotalValue([jobs, workflows]) } } - return ( - projectStore?.jobsMonitoringData.scheduled || { - jobs: 0, - workflows: 0, - total: 0 - } - ) + return projectStore?.jobsMonitoringData.scheduled || {} }, [ projectName, projectStore.projectSummary?.data?.distinct_scheduled_jobs_pending_count, diff --git a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx index ff008cbc36..d0f0788561 100644 --- a/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/WorkflowsCounters.jsx @@ -25,7 +25,7 @@ import { Loader, PopUpDialog, TextTooltipTemplate, Tooltip } from 'igz-controls/ import ClockIcon from 'igz-controls/images/clock.svg?react' import StatsCard from '../../common/StatsCard/StatsCard' -import { generateMonitoringStats } from '../../utils/generateMonitoringData' +import { countTotalValue, generateMonitoringStats } from '../../utils/generateMonitoringData' import { JOBS_MONITORING_WORKFLOWS_TAB, MONITOR_WORKFLOWS_TAB } from '../../constants' import './projectsMonitoringCounters.scss' @@ -49,26 +49,19 @@ const WorkflowsCounters = () => { const workflowsData = useMemo(() => { if (projectName) { - const completed = projectStore?.projectSummary.data?.pipelines_completed_recent_count || 0 - const failed = projectStore?.projectSummary.data?.pipelines_failed_recent_count || 0 - const running = projectStore?.projectSummary.data?.pipelines_running_count || 0 + const completed = projectStore?.projectSummary.data?.pipelines_completed_recent_count + const failed = projectStore?.projectSummary.data?.pipelines_failed_recent_count + const running = projectStore?.projectSummary.data?.pipelines_running_count return { completed, failed, running, - total: completed + failed + running + total: countTotalValue([completed, failed, running]) } } - return ( - projectStore.jobsMonitoringData.workflows || { - completed: 0, - failed: 0, - running: 0, - total: 0 - } - ) + return projectStore.jobsMonitoringData.workflows || {} }, [ projectName, projectStore.projectSummary.data?.pipelines_completed_recent_count, diff --git a/src/utils/generateAlertsStats.js b/src/utils/generateAlertsStats.js index c3553871f0..274184d353 100644 --- a/src/utils/generateAlertsStats.js +++ b/src/utils/generateAlertsStats.js @@ -35,19 +35,19 @@ export const generateAlertsStats = (data, navigate, projectName) => { return { total: { - counter: data.total, + counter: data.total ?? 'N/A', link: () => navigateToAlertsPage({}) }, job: { - counter: data.job, + counter: data.jobs ?? 'N/A', link: () => navigateToAlertsPage({ [ENTITY_TYPE]: JOB }) }, endpoints: { - counter: data.endpoint, + counter: data.endpoint ?? 'N/A', link: () => navigateToAlertsPage({ [ENTITY_TYPE]: MODEL_ENDPOINT_RESULT }) }, application: { - counter: data.application, + counter: data.application ?? 'N/A', link: () => navigateToAlertsPage({ [ENTITY_TYPE]: MODEL_MONITORING_APPLICATION }) } } diff --git a/src/utils/generateMonitoringData.js b/src/utils/generateMonitoringData.js index 97d5ce3f3b..0b41247558 100644 --- a/src/utils/generateMonitoringData.js +++ b/src/utils/generateMonitoringData.js @@ -75,7 +75,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { return tab === JOBS_MONITORING_JOBS_TAB ? { total: { - counter: data.total || 0, + counter: data.total ?? 'N/A', link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: [FILTER_ALL_ITEMS], @@ -84,7 +84,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }, counters: [ { - counter: data.running || 0, + counter: data.running ?? 'N/A', className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ @@ -101,7 +101,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { label: IN_PROCESS }, { - counter: data.failed || 0, + counter: data.failed ?? 'N/A', className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ @@ -116,7 +116,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }) }, { - counter: data.completed || 0, + counter: data.completed ?? 'N/A', className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ @@ -132,7 +132,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { : [JOBS_MONITORING_WORKFLOWS_TAB, MONITOR_WORKFLOWS_TAB].includes(tab) ? { total: { - counter: data.total || 0, + counter: data.total ?? 'N/A', link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: [FILTER_ALL_ITEMS], @@ -141,7 +141,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }, counters: [ { - counter: data.running || 0, + counter: data.running ?? 'N/A', link: () => navigateToJobsMonitoringPage({ [STATUS_FILTER]: [RUNNING_STATE, TERMINATING_STATE], @@ -153,7 +153,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { label: IN_PROCESS }, { - counter: data.failed || 0, + counter: data.failed ?? 'N/A', className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ @@ -168,7 +168,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }) }, { - counter: data.completed || 0, + counter: data.completed ?? 'N/A', className: classNames('stats__link', 'stats__line'), link: () => navigateToJobsMonitoringPage({ @@ -184,25 +184,25 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { : tab === ARTIFACTS_PAGE ? { total: { - counter: data.total || 0 + counter: data.total ?? 'N/A' }, datasets: { - counter: data.datasets || 0, + counter: data.datasets ?? 'N/A', link: () => navigateToTab(projectName, 'datasets'), className: linkClassNameDetails(projectName) }, documents: { - counter: data.documents || 0, + counter: data.documents ?? 'N/A', link: () => navigateToTab(projectName, 'documents'), className: linkClassNameDetails(projectName) }, llm_prompt: { - counter: data.llm_prompts || 0, + counter: data.llm_prompts ?? 'N/A', link: () => navigateToTab(projectName, 'llm-prompts'), className: linkClassNameDetails(projectName) }, files: { - counter: data.files || 0, + counter: data.files ?? 'N/A', link: () => navigateToTab(projectName, 'files'), className: linkClassNameDetails(projectName) }, @@ -216,7 +216,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { : tab === MODELS_PAGE ? { models: { - counter: data || 0, + counter: data ?? 'N/A', link: () => navigateToTab(projectName, 'models'), className: linkClassNameHeader(projectName) } @@ -224,13 +224,13 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { : tab === APPLICATION ? { total: { - counter: data.total || 0, + counter: data.total ?? 'N/A', link: () => navigateToTab(projectName, MONITORING_APP_PAGE), className: `stats__counter_total ${linkClassNameHeader(projectName)}` }, counters: [ { - counter: data.running || 0, + counter: data.running ?? 'N/A', className: classNames(projectName && 'stats__link'), link: () => navigateToTab(projectName, MONITORING_APP_PAGE), statusClass: RUNNING_STATE, @@ -239,7 +239,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { tooltip: RUNNING }, { - counter: data.failed || 0, + counter: data.failed ?? 'N/A', className: classNames(projectName && 'stats__link', { stats__failed: data.failed > 0 }), @@ -253,7 +253,7 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { } : { total: { - counter: data.total || 0, + counter: data.total ?? 'N/A', link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: FILTER_ALL_ITEMS, @@ -261,15 +261,23 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { }) }, jobs: { - counter: data.jobs || 0, + counter: data.jobs ?? 'N/A', link: () => navigateToJobsMonitoringPage({ - [TYPE_FILTER]: generateTypeFilter(JOBS_MONITORING_SCHEDULED_TAB).filter(type => type.id !== JOB_KIND_WORKFLOW && type.id !== FILTER_ALL_ITEMS && !type.hidden).map(item => item.id).join(','), + [TYPE_FILTER]: generateTypeFilter(JOBS_MONITORING_SCHEDULED_TAB) + .filter( + type => + type.id !== JOB_KIND_WORKFLOW && + type.id !== FILTER_ALL_ITEMS && + !type.hidden + ) + .map(item => item.id) + .join(','), [DATES_FILTER]: NEXT_24_HOUR_DATE_OPTION }) }, workflows: { - counter: data.workflows || 0, + counter: data.workflows ?? 'N/A', link: () => navigateToJobsMonitoringPage({ [TYPE_FILTER]: JOB_KIND_WORKFLOW, @@ -278,3 +286,9 @@ export const generateMonitoringStats = (data, navigate, tab, projectName) => { } } } + +export const countTotalValue = (values = []) => { + if (values.every(element => typeof element !== 'number')) return 'N/A' + + return values.reduce((acc, element) => acc + (typeof element === 'number' ? element : 0), 0) +} From 0971a80db9879cf725ae4f1b45218df561a591d4 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 13 Nov 2025 12:36:51 +0200 Subject: [PATCH 215/228] Fix [Model Endpoints] Failed to open the details pane (#3496) --- src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx b/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx index 82aee7afa6..f1e6bc8d2f 100644 --- a/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx +++ b/src/components/ModelsPage/ModelEndpoints/ModelEndpoints.jsx @@ -20,7 +20,6 @@ such restriction. import React, { useState, useRef, useCallback, useEffect, useMemo } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom' -import { isEmpty } from 'lodash' import ActionBar from '../../ActionBar/ActionBar' import ArtifactsTableRow from '../../../elements/ArtifactsTableRow/ArtifactsTableRow' From 68d438768ac1ad83ec29ed98f78399e83bf531df Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Thu, 13 Nov 2025 12:37:02 +0200 Subject: [PATCH 216/228] Fix [Pagination] Scroll to table top on pagination (#3495) --- src/common/Pagination/Pagination.jsx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/common/Pagination/Pagination.jsx b/src/common/Pagination/Pagination.jsx index 65c0ec1dcf..1dedd9b324 100644 --- a/src/common/Pagination/Pagination.jsx +++ b/src/common/Pagination/Pagination.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useCallback, useMemo, useRef } from 'react' +import React, { useCallback, useEffect, useMemo, useRef } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { useNavigate, useSearchParams } from 'react-router-dom' @@ -35,6 +35,7 @@ import { ITEMS_COUNT_END, ITEMS_COUNT_START } from '../../constants' +import { MAIN_TABLE_ID } from 'igz-controls/constants' import { PAGINATION_CONFIG } from '../../types' import { getCloseDetailsLink } from '../../utils/link-helper.util' @@ -51,8 +52,9 @@ const Pagination = ({ disabledNextDoubleBtnTooltip = '', paginationConfig, selectedItemName = '', + tableId = MAIN_TABLE_ID }) => { - const [, setSearchParams] = useSearchParams() + const [searchParams, setSearchParams] = useSearchParams() const navigate = useNavigate() const paginationPagesRef = useRef() const leftSideRef = useRef(0) @@ -220,6 +222,18 @@ const Pagination = ({ [paginationConfig] ) + useEffect(() => { + if (parseInt(searchParams.get(FE_PAGE)) !== paginationConfig[FE_PAGE]) { + const tableElement = document.getElementById(tableId) + + if (tableElement) { + tableElement.scrollTo({ + top: 0 + }) + } + } + }, [paginationConfig, searchParams, tableId]) + return (
      {paginationConfig.isNewResponse && ( @@ -321,7 +335,8 @@ Pagination.propTypes = { disableNextDoubleBtn: PropTypes.bool, disabledNextDoubleBtnTooltip: PropTypes.string, paginationConfig: PAGINATION_CONFIG.isRequired, - selectedItemName: PropTypes.string + selectedItemName: PropTypes.string, + tableId: PropTypes.string } export default Pagination From 8b0538cb99cf8375e44e94f97f928aa78c5a54b8 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Mon, 17 Nov 2025 09:43:02 +0200 Subject: [PATCH 217/228] Fix [Real-time pipelines] Redundant title icon in graph detail pane (#3501) --- src/common/ReactFlow/MlReactFlowEdge.jsx | 12 +++++++----- src/components/Pipeline/Pipeline.jsx | 8 +++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/common/ReactFlow/MlReactFlowEdge.jsx b/src/common/ReactFlow/MlReactFlowEdge.jsx index 9497695529..93771880eb 100644 --- a/src/common/ReactFlow/MlReactFlowEdge.jsx +++ b/src/common/ReactFlow/MlReactFlowEdge.jsx @@ -44,9 +44,11 @@ const MlReactFlowEdge = ({ targetY }) => { const nodes = useNodes() + const markerEndIdConverted = useMemo(() => markerEndId?.replace(' ', '_'), [markerEndId]) + const idConverted = useMemo(() => id?.replace(' ', '_'), [id]) const markerEnd = useMemo( - () => getMarkerEnd(arrowHeadType, markerEndId, id), - [arrowHeadType, id, markerEndId] + () => getMarkerEnd(arrowHeadType, markerEndIdConverted, idConverted), + [arrowHeadType, idConverted, markerEndIdConverted] ) const sourceNode = useMemo(() => nodes.find(n => n.id === source), [source, nodes]) const targetNode = useMemo(() => nodes.find(n => n.id === target), [target, nodes]) @@ -98,7 +100,7 @@ const MlReactFlowEdge = ({ - + ) } diff --git a/src/components/Pipeline/Pipeline.jsx b/src/components/Pipeline/Pipeline.jsx index 421881cc06..e206fa3985 100644 --- a/src/components/Pipeline/Pipeline.jsx +++ b/src/components/Pipeline/Pipeline.jsx @@ -380,9 +380,11 @@ const Pipeline = ({ content }) => {
      -
      - -
      + {selectedStep.type === ML_MODEL_RUNNER_NODE && ( +
      + +
      + )}
      -
      Class Name
      +
      Class name
      } diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelDataSource/FeatureSetsPanelDataSourceView.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanelDataSource/FeatureSetsPanelDataSourceView.jsx index d937a74406..afe7be4dfe 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelDataSource/FeatureSetsPanelDataSourceView.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelDataSource/FeatureSetsPanelDataSourceView.jsx @@ -60,7 +60,7 @@ const FeatureSetsPanelDataSourceView = ({ return (
      - +
      setSelectedEnvVariable(state => ({ ...state, secretName }))} pattern="^(?=[\S\s]{1,253}$)[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?)*$" validationRules={getValidationRules('environmentVariables.secretName', [ @@ -133,7 +133,7 @@ const EditableEnvironmentVariablesRow = ({ setSelectedEnvVariable(state => ({ ...state, secretKey }))} pattern="^(?=[\S\s]{0,253}$)(?!\.$)(?!\.\.[\S\s]*$)[-._a-zA-Z0-9]*$" setInvalid={value => setValidation(state => ({ ...state, isSecretKeyValid: value }))} diff --git a/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx b/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx index b0e7ccdf0d..18076b4654 100644 --- a/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx +++ b/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx @@ -131,7 +131,7 @@ const FormEnvironmentVariablesRow = ({ className="secret-name" density="normal" name={`${rowPath}.data.secretName`} - placeholder="Secret Name" + placeholder="Secret name" required validationRules={getValidationRules('environmentVariables.secretName', [ getSecretNameValidator(projectName, editingItem?.data?.typeName) @@ -140,7 +140,7 @@ const FormEnvironmentVariablesRow = ({ diff --git a/src/elements/FormVolumesTable/FormVolumesTable.jsx b/src/elements/FormVolumesTable/FormVolumesTable.jsx index 8e9a800e7d..a072f5942a 100644 --- a/src/elements/FormVolumesTable/FormVolumesTable.jsx +++ b/src/elements/FormVolumesTable/FormVolumesTable.jsx @@ -55,7 +55,7 @@ const FormVolumesTable = ({ }>Type
      - }>Volume Name + }>Volume name
      }>Path diff --git a/src/elements/FormVolumesTable/formVolumesTable.util.js b/src/elements/FormVolumesTable/formVolumesTable.util.js index 8961396ea7..6bc4cd5569 100644 --- a/src/elements/FormVolumesTable/formVolumesTable.util.js +++ b/src/elements/FormVolumesTable/formVolumesTable.util.js @@ -38,7 +38,7 @@ const volumeTypeInputLabels = { const selectVolumeTypeOptions = [ ...(isCommunityEdition() ? [] : [{ label: 'V3IO', id: V3IO_VOLUME_TYPE }]), - { label: 'Config Map', id: CONFIG_MAP_VOLUME_TYPE }, + { label: 'Config map', id: CONFIG_MAP_VOLUME_TYPE }, { label: 'Secret', id: SECRET_VOLUME_TYPE }, { label: 'PVC', id: PVC_VOLUME_TYPE } ] @@ -92,7 +92,7 @@ export const generateVolumeInputsData = ( return { ...fieldBase, inputDisabled: selectedItem.isDefault, - label: 'Volume Name', + label: 'Volume name', required: true, type: 'input', validationRules: [ @@ -139,7 +139,7 @@ export const generateVolumeInputsData = ( return { ...fieldBase, inputHidden: selectedType !== V3IO_VOLUME_TYPE, - label: 'Access Key', + label: 'Access key', tip: 'A platform data-access key', required: true, customRequiredLabel: @@ -158,7 +158,7 @@ export const generateVolumeInputsData = ( return { ...fieldBase, inputHidden: selectedType !== V3IO_VOLUME_TYPE, - label: 'Resource Path', + label: 'Resource path', tip: 'A relative directory path within the data container', textHidden: true, type: 'input' diff --git a/src/elements/MetricsSelector/MetricsSelector.jsx b/src/elements/MetricsSelector/MetricsSelector.jsx index 2ac8fdd30c..9f65ccef2c 100644 --- a/src/elements/MetricsSelector/MetricsSelector.jsx +++ b/src/elements/MetricsSelector/MetricsSelector.jsx @@ -170,7 +170,7 @@ const MetricsSelector = ({ const getSelectValue = () => { if (isEmpty(appliedMetrics)) { - return 'Choose Metrics...' + return 'Choose metrics...' } if (appliedMetrics.length === 1) { diff --git a/src/elements/NewFunctionPopUp/NewFunctionPopUp.jsx b/src/elements/NewFunctionPopUp/NewFunctionPopUp.jsx index 21fe20f7c9..de94045acb 100644 --- a/src/elements/NewFunctionPopUp/NewFunctionPopUp.jsx +++ b/src/elements/NewFunctionPopUp/NewFunctionPopUp.jsx @@ -142,7 +142,7 @@ const NewFunctionPopUp = ({ } : {} } - headerText="Create New Function" + headerText="Create new function" >
      - Node Selectors + Node selectors setNewVolume(state => ({ ...state, name }))} required requiredText="This field is required" diff --git a/src/elements/VolumesTable/volumesTable.util.js b/src/elements/VolumesTable/volumesTable.util.js index b32f7d77a7..6f2ded9d74 100644 --- a/src/elements/VolumesTable/volumesTable.util.js +++ b/src/elements/VolumesTable/volumesTable.util.js @@ -44,7 +44,7 @@ export const tableHeaders = [ export const selectTypeOptions = { volumeType: [ ...(isCommunityEdition() ? [] : [{ label: 'V3IO', id: V3IO }]), - { label: 'Config Map', id: CONFIG_MAP }, + { label: 'Config map', id: CONFIG_MAP }, { label: 'Secret', id: SECRET }, { label: 'PVC', id: PVC } ] diff --git a/src/layout/Header/Header.jsx b/src/layout/Header/Header.jsx index 86e7c1de81..de57c938ee 100644 --- a/src/layout/Header/Header.jsx +++ b/src/layout/Header/Header.jsx @@ -56,7 +56,7 @@ const Header = () => { target="_blank" rel="noopener noreferrer" > - Function Hub + Function hub (!showExpandButton ? getLink(alert) : ''), @@ -293,7 +293,7 @@ export const createAlertRowData = ({ ...alert }, isCrossProjects, showExpandButt { id: `eventType.${alert.id}`, headerId: 'eventType', - headerLabel: 'Event Type', + headerLabel: 'Event type', value: alert.event_kind?.split('-')?.join(' '), className: 'table-cell-1' }, @@ -307,7 +307,7 @@ export const createAlertRowData = ({ ...alert }, isCrossProjects, showExpandButt { id: `entityType.${alert.id}`, headerId: 'entityType', - headerLabel: 'Entity Type', + headerLabel: 'Entity type', value: getEntityTypeData(alert.entity_kind).value, className: 'table-cell-small', tooltip: getEntityTypeData(alert.entity_kind).tooltip, diff --git a/src/utils/createArtifactsContent.jsx b/src/utils/createArtifactsContent.jsx index 46e5a010af..f1d561a531 100644 --- a/src/utils/createArtifactsContent.jsx +++ b/src/utils/createArtifactsContent.jsx @@ -196,7 +196,7 @@ export const createModelsRowData = (artifact, project, isAllVersions, metricsCou Framework &
      - Algorithm + algorithm
      ), value: @@ -499,7 +499,7 @@ export const createModelEndpointsRowData = (artifact, project) => { { id: `functionTag.${artifact.ui.identifierUnique}`, headerId: 'functionTag', - headerLabel: 'Function Tag', + headerLabel: 'Function tag', value: artifact.spec?.function_tag, className: 'table-cell-small' }, diff --git a/src/utils/createFeatureStoreContent.jsx b/src/utils/createFeatureStoreContent.jsx index 2ad61c1b5b..da7c595801 100644 --- a/src/utils/createFeatureStoreContent.jsx +++ b/src/utils/createFeatureStoreContent.jsx @@ -138,7 +138,7 @@ export const createFeaturesRowData = (feature, isTablePanelOpen, showExpandButto { id: `key.${feature.ui.identifierUnique}`, headerId: 'featurename', - headerLabel: 'Feature Name', + headerLabel: 'Feature name', type: feature.ui.type, value: feature.name, className: 'table-cell-name', diff --git a/src/utils/createFunctionsRowData.js b/src/utils/createFunctionsRowData.js index 282e6cda9b..ae7d95ac29 100644 --- a/src/utils/createFunctionsRowData.js +++ b/src/utils/createFunctionsRowData.js @@ -86,7 +86,7 @@ const createFunctionsRowData = (func, projectName, isAllVersions, showExpandButt { id: `command.${func.ui.identifierUnique}`, headerId: 'command', - headerLabel: 'Code Entry Point', + headerLabel: 'Code entry point', value: func.command, className: 'table-cell-2' }, From 903fe81cb1e427be5e4975bc566de59b8a6a3a24 Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Mon, 17 Nov 2025 18:06:37 +0200 Subject: [PATCH 220/228] Fix [Real-time pipelines] Accordion button scrolls above the header (#3504) --- src/scss/main.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scss/main.scss b/src/scss/main.scss index dcba51a691..b95ed7e119 100644 --- a/src/scss/main.scss +++ b/src/scss/main.scss @@ -339,7 +339,7 @@ main { font-size: 20px; position: sticky; top: 0; - z-index: 1; + z-index: 4; background-color: colors.$white; &-icon { From 8125be94f1001dc4f7b9d61de996de2b08eff6ed Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:55:47 +0200 Subject: [PATCH 221/228] Impl [UI] initiate vitest on mlrun (#3509) --- package.json | 10 ++++++++-- vitest.config.mjs | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 vitest.config.mjs diff --git a/package.json b/package.json index 3e3572b7d0..6d7fc47abc 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,9 @@ "build-storybook": "build-storybook", "mock-server": "node scripts/mockServer.js", "mock-server:dev": "nodemon --watch tests/mockServer scripts/mockServer.js", + "test": "vitest", "test:ui": "node scripts/testui.js", + "test:watch": "vitest --watch", "report": "node tests/report.js", "test:regression": "npm run test:ui && npm run report", "start:regression": "concurrently \"npm:mock-server\" \"npm:start\" \"npm:test:regression\"", @@ -90,7 +92,9 @@ "@storybook/addon-links": "^8.0.1", "@storybook/preset-scss": "^1.0.3", "@storybook/react": "^8.0.1", - "@testing-library/react": "^11.0.2", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", "@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react-swc": "^3.8.0", "acorn": "^7.4.1", @@ -123,6 +127,7 @@ "geckodriver": "^3.0.1", "globals": "^15.14.0", "http-proxy-middleware": "^2.0.3", + "jsdom": "^27.2.0", "mime-types": "^2.1.35", "node": "^21.6.2", "nodemon": "^3.1.2", @@ -149,7 +154,8 @@ "vite": "^6.2.0", "vite-plugin-commonjs": "^0.10.4", "vite-plugin-eslint": "^1.8.1", - "vite-plugin-svgr": "^4.3.0" + "vite-plugin-svgr": "^4.3.0", + "vitest": "^4.0.10" }, "babel": { "plugins": [ diff --git a/vitest.config.mjs b/vitest.config.mjs new file mode 100644 index 0000000000..6f69c51546 --- /dev/null +++ b/vitest.config.mjs @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config' +import react from '@vitejs/plugin-react-swc' + +export default defineConfig({ + plugins: [react()], + test: { + globals: true, + environment: 'jsdom', + include: ['src/**/*.{test,spec}.{js,jsx}'], + exclude: ['node_modules', 'build', 'dist'], + } +}) From 9e70896b1c3b97eddb014cac7f7f487bf26d1f80 Mon Sep 17 00:00:00 2001 From: EZheln <36635708+EZheln@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:35:39 +0100 Subject: [PATCH 222/228] Tests [QA] v1.11.0-rc1 (#3510) --- package.json | 2 +- tests/features/common-tools/common-consts.js | 21 ++++- .../common/page-objects/info-pane.po.js | 27 +++++- .../page-objects/jobs-and-workflows.po.js | 2 +- .../features/common/page-objects/models.po.js | 17 +++- tests/features/jobsAndWorkflows.feature | 1 - tests/features/models.feature | 88 +++++++++++++++++-- tests/features/monitoringApp.feature | 2 +- .../features/step-definitions/table.steps.js | 15 +++- tests/mockServer/data/summary.json | 41 ++++++++- 10 files changed, 197 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 6d7fc47abc..3c321a5fd9 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "report": "node tests/report.js", "test:regression": "npm run test:ui && npm run report", "start:regression": "concurrently \"npm:mock-server\" \"npm:start\" \"npm:test:regression\"", - "ui-steps": "export BABEL_ENV=test; export NODE_ENV=test; npx -p @babel/core -p @babel/node babel-node --presets @babel/preset-env scripts/collectUITestsSteps.js", + "ui-steps": "cross-env BABEL_ENV=test; cross-env NODE_ENV=test; npx -p @babel/core -p @babel/node babel-node --presets @babel/preset-env scripts/collectUITestsSteps.js", "nli": "npm link iguazio.dashboard-react-controls", "nui": "npm unlink iguazio.dashboard-react-controls" }, diff --git a/tests/features/common-tools/common-consts.js b/tests/features/common-tools/common-consts.js index 97063c1256..137ae8dde0 100644 --- a/tests/features/common-tools/common-consts.js +++ b/tests/features/common-tools/common-consts.js @@ -68,14 +68,33 @@ export default { ] }, Real_Time_Pipeline_Pane: { + In_Monitoring_State: 'In monitoring', + Chip_Tooltip: 'my-endpoint', Overview_Headers: [ 'Type:', - 'After:', 'Class name:', 'Function name:', + 'Arguments:', 'Handler:', 'Input path:', 'Result path:' + ], + Overview_Headers_Model_Runner: [ + 'Type:', + 'Class name:', + 'Function name:', + 'Arguments:', + 'Input path:', + 'Result path:' + ], + Running_Models_Headers: [ + 'Model endpoint:', + 'Model artifact:', + 'Class name:', + 'Input path:', + 'Result path:', + 'Outputs:', + 'Execution mechanism:' ] }, Feature_Sets_Info_Pane: { diff --git a/tests/features/common/page-objects/info-pane.po.js b/tests/features/common/page-objects/info-pane.po.js index 61e15d5fc6..c6a69807ce 100644 --- a/tests/features/common/page-objects/info-pane.po.js +++ b/tests/features/common/page-objects/info-pane.po.js @@ -592,7 +592,7 @@ const modelsRealTimeinfoPaneOverviewHeaders = { root: '.table-container', header: {}, body: { - root: '.graph-pane', + root: '.graph-pane .graph-pane__section:nth-of-type(2)', offset: 1, row: { root: '.graph-pane__row', @@ -603,6 +603,22 @@ const modelsRealTimeinfoPaneOverviewHeaders = { } } +const modelsRealTimeinfoPaneRunningModelsHeaders = { + root: '.table-container', + header: {}, + body: { + root: '.graph-pane .graph-pane__section:nth-of-type(3)', + offset: 0, + row: { + root: '.graph-pane__row', + fields: { + key: '.graph-pane__row-label', + key_value:'.graph-pane__row-value .link' + } + } + } +} + const featureSetTransformationGraph = { root: '.react-flow', elements: { @@ -1074,9 +1090,14 @@ export default { }, modelsRealTimePipelineInfoPane: { Arrow_Back: commonArrowBack, - Header: By.css('.graph-pane__title span'), + Header: By.css('.graph-pane__title .graph-pane__title-label'), + Title_Icon: By.css('.graph-pane__title .graph-pane__title-icon'), Cross_Close_Button: By.css('.graph-pane__title .round-icon-cp .round-icon-cp__circle'), - Overview_Headers: commonTable(modelsRealTimeinfoPaneOverviewHeaders) + General_Section_Title: By.css('.graph-pane .graph-pane__section:nth-of-type(2) .graph-pane__section-title'), + Overview_Headers: commonTable(modelsRealTimeinfoPaneOverviewHeaders), + Running_Models_Section_Title: By.css('.graph-pane .graph-pane__section:nth-of-type(3) .graph-pane__section-title'), + Graph_Pane_Expand_Icon: By.css('.graph-pane .graph-pane__section:nth-of-type(3) .graph-pane__expand-icon'), + Running_Models_Headers: commonTable(modelsRealTimeinfoPaneRunningModelsHeaders) }, llmPromptsInfoPane: { Header: header, diff --git a/tests/features/common/page-objects/jobs-and-workflows.po.js b/tests/features/common/page-objects/jobs-and-workflows.po.js index b7ad3ea96f..7d5361cd43 100644 --- a/tests/features/common/page-objects/jobs-and-workflows.po.js +++ b/tests/features/common/page-objects/jobs-and-workflows.po.js @@ -196,7 +196,7 @@ const monitorWorkflowGraph = { row: { root: '.selectable', fields: { - name: '.react-flow__node-label .data-ellipsis .data-ellipsis', + name: '.react-flow__node-label .data-ellipsis', top_handler: '.data-ellipsis .react-flow__handle-top', bottom_handler: '.data-ellipsis .react-flow__handle-bottom' } diff --git a/tests/features/common/page-objects/models.po.js b/tests/features/common/page-objects/models.po.js index cbd7b82d4c..9c35dc35f7 100644 --- a/tests/features/common/page-objects/models.po.js +++ b/tests/features/common/page-objects/models.po.js @@ -216,11 +216,12 @@ const realTimePipelinesGraph = { body: { root: '.react-flow__nodes', row: { - root: '.react-flow__node-ml-node', + root: '.react-flow__node', fields: { - name: '.react-flow__node-label .data-ellipsis .data-ellipsis', + name: '.react-flow__node-label .data-ellipsis', top_handler: '.data-ellipsis .react-flow__handle-top', - bottom_handler: '.data-ellipsis .react-flow__handle-bottom' + bottom_handler: '.data-ellipsis .react-flow__handle-bottom', + node_title: '.react-flow__node-chips-title' } } } @@ -293,6 +294,14 @@ export default { Table_Name_Filter_Input: tableNameFilterInput, Table_Refresh_Button: tableRefreshButton, Real_Time_Pipelines_Table: commonTable(realTimePipelinesTable), - Real_Time_Pipelines_Graph: graph(realTimePipelinesGraph) + Real_Time_Pipelines_Graph: graph(realTimePipelinesGraph), + Pipeline_Back_Button: By.css('[data-testid="pipeline-back-btn-tooltip-wrapper"]'), + Pipeline_Link_Title: By.css('.pipeline-container .link-back__title'), + Model_Runner_Step_Icon: By.css('.react-flow__node-ml-model-runner-node .react-flow__node-header .react-flow__node-header-icon'), + Model_Runner_Step_Label: By.css('.react-flow__node-ml-model-runner-node .react-flow__node-header-title .react-flow__node-header-label'), + Model_Runner_Step_Sub_Label: By.css('.react-flow__node-ml-model-runner-node .react-flow__node-header-title .react-flow__node-header-sub-label'), + Model_Runner_Monitoring_Icon: By.css('.react-flow__node-ml-model-runner-node .react-flow__node-header .react-flow__node-header-monitoring-icon'), + Model_Runner_Chips_Title: By.css('.react-flow__node-ml-model-runner-node div.react-flow__node-chips-title'), + Model_Runner_Chip_Container: By.css('.react-flow__node-ml-model-runner-node [data-testid="runningModels-chips"] .chip-block .edit-chip-container'), } } diff --git a/tests/features/jobsAndWorkflows.feature b/tests/features/jobsAndWorkflows.feature index 0ea0bdc692..78fd21cbd7 100644 --- a/tests/features/jobsAndWorkflows.feature +++ b/tests/features/jobsAndWorkflows.feature @@ -1578,7 +1578,6 @@ Feature: Jobs and workflows # Then verify arrow lines position on "Workflow_Graph" on "Workflows_Monitor_Tab" wizard When click on node with index 2 in "Workflow_Graph" graph on "Workflows_Monitor_Tab" wizard And wait load page - And wait load page Then verify "Header" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard Then verify "Updated" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard Then verify "Cross_Close_Button" element visibility on "Jobs_Monitor_Tab_Info_Pane" wizard diff --git a/tests/features/models.feature b/tests/features/models.feature index 4b18a2520d..bcda7c3fd1 100644 --- a/tests/features/models.feature +++ b/tests/features/models.feature @@ -1116,7 +1116,7 @@ Feature: Models Page And select "Real-Time Pipelines" tab in "Models_Tab_Selector" on "Models" wizard And wait load page Then verify "Real-Time Pipelines" tab is active in "Models_Tab_Selector" on "Models" wizard - Then save to context "name" column and "href" attribute on 3 row from "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + Then save to context "name" column and "href" attribute on 4 row from "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard When click on cell with value "model-monitoring-stream" in "name_link" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard And wait load page And wait load page @@ -1129,7 +1129,7 @@ Feature: Models Page Then verify "Overview_Headers" on "Real_Time_Pipeline_Pane" wizard should contains "Real_Time_Pipeline_Pane"."Overview_Headers" Then click on "Arrow_Back" element on "Real_Time_Pipeline_Pane" wizard And wait load page - Then click on cell with row index 3 in "function" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + Then click on cell with row index 4 in "function" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard And wait load page Then verify if "Modal_Transition_Popup" popup dialog appears Then verify "Title" element visibility on "Modal_Transition_Popup" wizard @@ -1154,7 +1154,7 @@ Feature: Models Page Then verify "Cross_Close_Button" element visibility on "Modal_Transition_Popup" wizard Then click on "Cross_Close_Button" element on "Modal_Transition_Popup" wizard And wait load page - Then click on cell with row index 3 in "function" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + Then click on cell with row index 4 in "function" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard And wait load page Then verify if "Modal_Transition_Popup" popup dialog appears Then verify "Tab_Selector" element visibility on "Modal_Transition_Popup" wizard @@ -1183,6 +1183,84 @@ Feature: Models Page Then "No_Data_Message" element on "commonPagesHeader" should contains "The ingestion function has no steps and therefore no graph." value And wait load page + @MLM + @passive + @smoke + Scenario: MLM039 - Check the model runner step on the Real-Time Pipeline graph + Given open url + And wait load page + And click on row root with value "default" in "name" column in "Projects_Table" table on "Projects" wizard + And wait load page + Then verify breadcrumbs "project" label should be equal "default" value + When click on "Model_Stats_Counter" element in "Models_Stats_Container" on "Project" wizard + And wait load page + Then verify breadcrumbs "tab" label should be equal "Models" value + And select "Real-Time Pipelines" tab in "Models_Tab_Selector" on "Models" wizard + And wait load page + Then verify "Real-Time Pipelines" tab is active in "Models_Tab_Selector" on "Models" wizard + When click on cell with value "function-with-llm" in "name_link" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + And wait load page + Then verify "Real_Time_Pipelines_Graph" element visibility on "Real_Time_Pipelines" wizard + Then verify "Pipeline_Back_Button" element visibility on "Real_Time_Pipelines" wizard + Then verify "Pipeline_Link_Title" element visibility on "Real_Time_Pipelines" wizard + Then "Pipeline_Link_Title" element on "Real_Time_Pipelines" should contains "function-with-llm" value + Then verify "Model_Runner_Step_Icon" element visibility on "Real_Time_Pipelines" wizard + Then verify "Model_Runner_Step_Label" element visibility on "Real_Time_Pipelines" wizard + Then "Model_Runner_Step_Label" element on "Real_Time_Pipelines" should contains "model-runner" value + Then verify "Model_Runner_Step_Sub_Label" element visibility on "Real_Time_Pipelines" wizard + Then "Model_Runner_Step_Sub_Label" element on "Real_Time_Pipelines" should contains "Model runner step" value + Then verify "Model_Runner_Monitoring_Icon" element visibility on "Real_Time_Pipelines" wizard + Then verify "Model_Runner_Monitoring_Icon" element on "Real_Time_Pipelines" wizard should display hover tooltip "Real_Time_Pipeline_Pane"."In_Monitoring_State" + Then verify "Model_Runner_Chips_Title" element visibility on "Real_Time_Pipelines" wizard + Then "Model_Runner_Chips_Title" element on "Real_Time_Pipelines" should contains "Running models" value + Then verify "Model_Runner_Chip_Container" element visibility on "Real_Time_Pipelines" wizard + Then verify "Model_Runner_Chip_Container" element on "Real_Time_Pipelines" wizard should display hover tooltip "Real_Time_Pipeline_Pane"."Chip_Tooltip" + When click on node with index 1 in "node_title" column in "Real_Time_Pipelines_Graph" graph on "Real_Time_Pipelines" wizard + And wait load page + Then verify "Header" element visibility on "Real_Time_Pipeline_Pane" wizard + Then verify "Title_Icon" element visibility on "Real_Time_Pipeline_Pane" wizard + Then verify "Cross_Close_Button" element visibility on "Real_Time_Pipeline_Pane" wizard + Then verify "General_Section_Title" element visibility on "Real_Time_Pipeline_Pane" wizard + Then "General_Section_Title" element on "Real_Time_Pipeline_Pane" should contains "General" value + Then verify "Overview_Headers" on "Real_Time_Pipeline_Pane" wizard should contains "Real_Time_Pipeline_Pane"."Overview_Headers_Model_Runner" + Then verify "Running_Models_Section_Title" element visibility on "Real_Time_Pipeline_Pane" wizard + Then "Running_Models_Section_Title" element on "Real_Time_Pipeline_Pane" should contains "Running models (1)" value + Then verify "Graph_Pane_Expand_Icon" element visibility on "Real_Time_Pipeline_Pane" wizard + Then click on "Graph_Pane_Expand_Icon" element on "Real_Time_Pipeline_Pane" wizard + And wait load page + Then verify "Running_Models_Headers" on "Real_Time_Pipeline_Pane" wizard should contains "Real_Time_Pipeline_Pane"."Running_Models_Headers" + When click on cell with value "c3e9308aaab54e53b1013ecda9234e43" in "key_value" column in "Running_Models_Headers" table on "Real_Time_Pipeline_Pane" wizard + And wait load page + Then verify if "Modal_Transition_Popup" popup dialog appears + Then verify "Title" element visibility on "Modal_Transition_Popup" wizard + Then "Title" element on "Modal_Transition_Popup" should contains "my-endpoint" value + Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard + Then verify "Cross_Close_Button" element visibility on "Modal_Transition_Popup" wizard + Then click on "Cross_Close_Button" element on "Modal_Transition_Popup" wizard + And wait load page + When click on cell with value "store://llm-prompts/default/my_llm4#0@9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554^d28e010ba24e272a3ba2ba522f6caecde05ff383" in "key_value" column in "Running_Models_Headers" table on "Real_Time_Pipeline_Pane" wizard + And wait load page + Then verify if "Modal_Transition_Popup" popup dialog appears + Then verify "Title" element visibility on "Modal_Transition_Popup" wizard + Then "Title" element on "Modal_Transition_Popup" should contains "my_llm4" value + Then verify "Data_Status" element visibility on "Modal_Transition_Popup" wizard + Then verify "Cross_Close_Button" element visibility on "Modal_Transition_Popup" wizard + Then click on "Cross_Close_Button" element on "Modal_Transition_Popup" wizard + And wait load page + Then click on "Arrow_Back" element on "Real_Time_Pipeline_Pane" wizard + And wait load page + When click on cell with value "model-monitoring-stream" in "name_link" column in "Real_Time_Pipelines_Table" table on "Real_Time_Pipelines" wizard + And wait load page + Then verify "Real_Time_Pipelines_Graph" element visibility on "Real_Time_Pipelines" wizard + When click on node with index 1 in "Real_Time_Pipelines_Graph" graph on "Real_Time_Pipelines" wizard + Then verify "Header" element visibility on "Real_Time_Pipeline_Pane" wizard + Then verify "Cross_Close_Button" element visibility on "Real_Time_Pipeline_Pane" wizard + Then verify "Overview_Headers" on "Real_Time_Pipeline_Pane" wizard should contains "Real_Time_Pipeline_Pane"."Overview_Headers" + And wait load page + Then verify "Graph_Pane_Expand_Icon" element not exists on "Real_Time_Pipeline_Pane" wizard + Then click on "Arrow_Back" element on "Real_Time_Pipeline_Pane" wizard + And wait load page + @MLM @smoke Scenario: MLM032 - Check broken link redirection @@ -1551,7 +1629,7 @@ Feature: Models Page And wait load page And select "Model Endpoints" tab in "Models_Tab_Selector" on "Models" wizard And wait load page - When click on cell with row index 3 in "name" column in "Model_Endpoints_Table" table on "Model_Endpoints" wizard + When click on cell with value "GradientBoostingClassifier" in "name" column in "Model_Endpoints_Table" table on "Model_Endpoints" wizard And wait load page Then verify "Info_Pane_Tab_Selector" element visibility on "Model_Endpoints_Info_Pane" wizard Then verify "Info_Pane_Tab_Selector" on "Model_Endpoints_Info_Pane" wizard should contains "Models_Endpoints_Info_Pane"."Tab_List" @@ -1608,7 +1686,7 @@ Feature: Models Page And wait load page And select "Model Endpoints" tab in "Models_Tab_Selector" on "Models" wizard And wait load page - When click on cell with row index 3 in "name" column in "Model_Endpoints_Table" table on "Model_Endpoints" wizard + When click on cell with value "GradientBoostingClassifier" in "name" column in "Model_Endpoints_Table" table on "Model_Endpoints" wizard Then select "Metrics" tab in "Info_Pane_Tab_Selector" on "Model_Endpoints_Info_Pane" wizard Then click on "Choose_Metrics_Dropdown" element on "Model_Endpoints_Info_Pane" wizard And wait load page diff --git a/tests/features/monitoringApp.feature b/tests/features/monitoringApp.feature index 49944a1b22..dc53a6967b 100644 --- a/tests/features/monitoringApp.feature +++ b/tests/features/monitoringApp.feature @@ -443,7 +443,7 @@ Feature: Monitoring app Page Then "Applications_Metrics_Title" element on "Application_Metrics" should contains "Applications metrics:" value Then verify "Endpoints_List_Section" element visibility on "Application_Metrics" wizard Then verify "Search_Endpoints_Counter" element visibility on "Application_Metrics" wizard - Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "4 endpoints found" value + Then "Search_Endpoints_Counter" element on "Application_Metrics" should contains "5 endpoints found" value Then verify "Endpoints_List_Table" element visibility on "Application_Metrics" wizard Then verify "Search_By_Endpoint_Filter_Input" element visibility on "Application_Metrics" wizard Then type value "boo" to "Search_By_Endpoint_Filter_Input" field on "Application_Metrics" wizard diff --git a/tests/features/step-definitions/table.steps.js b/tests/features/step-definitions/table.steps.js index 87f8bb561d..e876497c58 100644 --- a/tests/features/step-definitions/table.steps.js +++ b/tests/features/step-definitions/table.steps.js @@ -2063,7 +2063,7 @@ When( this.driver, pageObjects[wizardName][graphName].nodesTable.tableFields['name'](index) ) - await this.driver.sleep(250) + await this.driver.sleep(350) await isComponentContainsClass( this.driver, pageObjects[wizardName][graphName].nodesTable.rowRoot(index), @@ -2072,6 +2072,19 @@ When( } ) +When( + 'click on node with index {int} in {string} column in {string} graph on {string} wizard', + async function (index, column, graphName, wizard) { + await clickOnComponent(this.driver, pageObjects[wizard][graphName].nodesTable.tableFields[column](index)) + await this.driver.sleep(250) + await isComponentContainsClass( + this.driver, + pageObjects[wizard][graphName].nodesTable.rowRoot(index), + 'selected' + ) + } +) + When( 'save to context {string} column and {string} attribute on {int} row from {string} table on {string} wizard', async function (columnName, attributeName, rowIndex, tableName, wizardName) { diff --git a/tests/mockServer/data/summary.json b/tests/mockServer/data/summary.json index e1293ce6b0..d11ade74e3 100644 --- a/tests/mockServer/data/summary.json +++ b/tests/mockServer/data/summary.json @@ -52,6 +52,9 @@ }, { "name": "churn-project-admin", + "endpoint_alerts_count": 4, + "job_alerts_count": 2, + "other_alerts_count": 6, "files_count": 7, "feature_sets_count": 1, "failed_model_monitoring_functions": 1, @@ -75,7 +78,7 @@ { "name": "default", "endpoint_alerts_count": 3, - "project.job_alerts_count": 6, + "job_alerts_count": 6, "other_alerts_count": 1, "failed_model_monitoring_functions": 1, "files_count": 2, @@ -124,6 +127,9 @@ }, { "name": "fsdemo-admin", + "endpoint_alerts_count": 4, + "job_alerts_count": 2, + "other_alerts_count": 6, "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 4, @@ -143,6 +149,9 @@ }, { "name": "getting-started-tutorial-admin", + "endpoint_alerts_count": 4, + "job_alerts_count": 2, + "other_alerts_count": 6, "failed_model_monitoring_functions": 1, "files_count": 1, "feature_sets_count": 0, @@ -165,6 +174,9 @@ }, { "name": "hedi-proj", + "endpoint_alerts_count": 4, + "job_alerts_count": 2, + "other_alerts_count": 6, "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, @@ -187,6 +199,9 @@ }, { "name": "mask-detection", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, @@ -209,6 +224,9 @@ }, { "name": "model-deployment-pipeline-admin", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, @@ -231,6 +249,9 @@ }, { "name": "moreofthesame", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, @@ -253,6 +274,9 @@ }, { "name": "network-operations", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 0, @@ -275,6 +299,9 @@ }, { "name": "network-operations-admin", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 13, "files_count": 13, "feature_sets_count": 0, @@ -297,6 +324,9 @@ }, { "name": "sk-project-admin", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 4, "files_count": 4, "feature_sets_count": 0, @@ -319,6 +349,9 @@ }, { "name": "stocks", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 2, @@ -341,6 +374,9 @@ }, { "name": "stocks-admin", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 0, "files_count": 0, "feature_sets_count": 2, @@ -362,6 +398,9 @@ }, { "name": "test-test", + "endpoint_alerts_count": 0, + "job_alerts_count": 0, + "other_alerts_count": 0, "failed_model_monitoring_functions": 1, "files_count": 1, "feature_sets_count": 0, From e6703cd41a46d1ce56c73eb95645755868dc0c2a Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Wed, 19 Nov 2025 10:36:58 +0200 Subject: [PATCH 223/228] Fix [Real-time pipelines] Metrics remain preselected between views (#3506) --- .../DetailsTabsContent/DetailsTabsContent.jsx | 2 +- .../DetailsMetrics/DetailsMetrics.jsx | 19 +++++++++++++++++-- tests/mockServer/data/funcs.json | 11 +++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx b/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx index 0094f80a5d..827c902c7f 100644 --- a/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx +++ b/src/components/Details/DetailsTabsContent/DetailsTabsContent.jsx @@ -120,7 +120,7 @@ const DetailsTabsContent = ({ case DETAILS_FEATURES_ANALYSIS_TAB: return case DETAILS_METRICS_TAB: - return + return case DETAILS_ALERTS_TAB: return // todo [Alerts] in ML-9205 remove the key when alerts are refactored and the issue is fixed by refactoring case DETAILS_PREVIEW_TAB: diff --git a/src/components/DetailsMetrics/DetailsMetrics.jsx b/src/components/DetailsMetrics/DetailsMetrics.jsx index a68d4f7d70..1b037a51ae 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.jsx +++ b/src/components/DetailsMetrics/DetailsMetrics.jsx @@ -42,6 +42,7 @@ import { TIME_FRAME_LIMITS } from '../../utils/datePicker.util' import { + clearMetricsOptions, fetchModelEndpointMetrics, fetchModelEndpointMetricsValues, setDetailsDates, @@ -54,7 +55,12 @@ import MetricsIcon from 'igz-controls/images/metrics-icon.svg?react' import './DetailsMetrics.scss' -const DetailsMetrics = ({ applicationNameProp = '', selectedItem, renderTitle = null }) => { +const DetailsMetrics = ({ + applicationNameProp = '', + selectedItem, + renderTitle = null, + isDetailsPopUp = false +}) => { const [metrics, setMetrics] = useState([]) const [selectedDate, setSelectedDate] = useState('') const [previousTotalInvocation, setPreviousTotalInvocation] = useState(0) @@ -233,6 +239,14 @@ const DetailsMetrics = ({ applicationNameProp = '', selectedItem, renderTitle = metricsValuesAbortController ]) + useEffect(() => { + if (isDetailsPopUp) { + return () => { + dispatch(clearMetricsOptions()) + } + } + }, [dispatch, isDetailsPopUp]) + return (
      @@ -333,7 +347,8 @@ const DetailsMetrics = ({ applicationNameProp = '', selectedItem, renderTitle = DetailsMetrics.propTypes = { applicationNameProp: PropTypes.string, selectedItem: PropTypes.object.isRequired, - renderTitle: PropTypes.func + renderTitle: PropTypes.func, + isDetailsPopUp: PropTypes.bool } export default React.memo(DetailsMetrics) diff --git a/tests/mockServer/data/funcs.json b/tests/mockServer/data/funcs.json index 74a6b50dd7..8546eac84d 100644 --- a/tests/mockServer/data/funcs.json +++ b/tests/mockServer/data/funcs.json @@ -56,6 +56,17 @@ "model_path": "store://llm-prompts/default/my_llm4#0@9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554^d28e010ba24e272a3ba2ba522f6caecde05ff383", "model_class": "MyLLM", "model_endpoint_uid": "c3e9308aaab54e53b1013ecda9234e43" + }, + "my-endpoin2t": { + "inputs": [ ], + "outputs": [ ], + "input_path": null, + "result_path": null, + "creation_strategy": "inplace", + "labels": null, + "model_path": "store://llm-prompts/default/my_llm4#0@9c0c8773-b1ce-4fa0-ac94-2f6c1fb71554^d28e010ba24e272a3ba2ba522f6caecde05ff383", + "model_class": "MyLLM", + "model_endpoint_uid": "a7c95783e6a726a1a233e581ea898ba33fa7e342" } } }, From 0592dc190f63040eb970aa599af1f0762d55480d Mon Sep 17 00:00:00 2001 From: Taras-Hlukhovetskyi <155433425+Taras-Hlukhovetskyi@users.noreply.github.com> Date: Wed, 19 Nov 2025 10:37:35 +0200 Subject: [PATCH 224/228] Fix [Project Monitoring] redundant requests after changing project (#3505) --- src/components/Project/ProjectMonitor.jsx | 10 +++-- src/components/Project/ProjectMonitorView.jsx | 4 +- .../ProjectFunctions/ProjectFunctions.jsx | 25 +++---------- src/elements/ProjectJobs/ProjectJobs.jsx | 37 +++++++++++-------- src/reducers/projectReducer.js | 18 ++++----- 5 files changed, 46 insertions(+), 48 deletions(-) diff --git a/src/components/Project/ProjectMonitor.jsx b/src/components/Project/ProjectMonitor.jsx index 3fac52dd0f..2c4a49732a 100644 --- a/src/components/Project/ProjectMonitor.jsx +++ b/src/components/Project/ProjectMonitor.jsx @@ -38,7 +38,7 @@ import { import { fetchProject, fetchProjectFunctions, - fetchProjectSummary, + fetchProjectSummaryAndNuclioFuncs, removeProjectData, removeProjectSummary } from '../../reducers/projectReducer' @@ -67,6 +67,7 @@ const ProjectMonitor = () => { const projectAbortControllerRef = useRef(new AbortController()) const projectSummariesAbortControllerRef = useRef(new AbortController()) const v3ioStreamsAbortControllerRef = useRef(new AbortController()) + const nuclioFunctionsAbortControllerRef = useRef(new AbortController()) const frontendSpec = useSelector(state => state.appStore.frontendSpec) const functionsStore = useSelector(store => store.functionsStore) const projectStore = useSelector(store => store.projectStore) @@ -127,6 +128,7 @@ const ProjectMonitor = () => { const fetchProjectDataAndSummary = useCallback(() => { projectAbortControllerRef.current = new AbortController() projectSummariesAbortControllerRef.current = new AbortController() + nuclioFunctionsAbortControllerRef.current = new AbortController() Promise.all([ dispatch( @@ -137,9 +139,10 @@ const ProjectMonitor = () => { }) ).unwrap(), dispatch( - fetchProjectSummary({ + fetchProjectSummaryAndNuclioFuncs({ project: params.projectName, - signal: projectSummariesAbortControllerRef.current.signal + projectSummarySignal: projectSummariesAbortControllerRef.current.signal, + functionsSignal: nuclioFunctionsAbortControllerRef.current.signal }) ).unwrap() ]).catch(error => { @@ -156,6 +159,7 @@ const ProjectMonitor = () => { projectAbortControllerRef.current.abort(REQUEST_CANCELED) projectSummariesAbortControllerRef.current.abort(REQUEST_CANCELED) v3ioStreamsAbortControllerRef.current.abort(REQUEST_CANCELED) + nuclioFunctionsAbortControllerRef.current.abort(REQUEST_CANCELED) } }, [params.projectName]) diff --git a/src/components/Project/ProjectMonitorView.jsx b/src/components/Project/ProjectMonitorView.jsx index 308e8321f4..269a7b7931 100644 --- a/src/components/Project/ProjectMonitorView.jsx +++ b/src/components/Project/ProjectMonitorView.jsx @@ -125,10 +125,10 @@ const ProjectMonitorView = ({
      - +
      - +
      diff --git a/src/elements/ProjectFunctions/ProjectFunctions.jsx b/src/elements/ProjectFunctions/ProjectFunctions.jsx index 0ea8104a3c..904b77fdd1 100644 --- a/src/elements/ProjectFunctions/ProjectFunctions.jsx +++ b/src/elements/ProjectFunctions/ProjectFunctions.jsx @@ -34,34 +34,20 @@ import { REQUEST_CANCELED, RUNNING_STATE } from '../../constants' -import { fetchApiGateways, fetchNuclioFunctions } from '../../reducers/nuclioReducer' +import { fetchApiGateways } from '../../reducers/nuclioReducer' import { generateNuclioLink } from '../../utils' import { groupByUniqName } from '../../utils/groupByUniqName' import { typesOfJob } from '../../utils/jobs.util' import { useNuclioMode } from '../../hooks/nuclioMode.hook' -const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { +const ProjectFunctions = ({ nuclioStreamsAreEnabled, project }) => { const params = useParams() const { isNuclioModeDisabled } = useNuclioMode() const nuclioStore = useSelector(store => store.nuclioStore) const dispatch = useDispatch() useEffect(() => { - if (!isNuclioModeDisabled) { - const abortController = new AbortController() - - dispatch( - fetchNuclioFunctions({ project: params.projectName, signal: abortController.signal }) - ) - - return () => { - abortController.abort(REQUEST_CANCELED) - } - } - }, [dispatch, isNuclioModeDisabled, params.projectName]) - - useEffect(() => { - if (!isNuclioModeDisabled) { + if (!isNuclioModeDisabled && project?.data?.metadata?.name === params.projectName) { const abortController = new AbortController() dispatch(fetchApiGateways({ project: params.projectName, signal: abortController.signal })) @@ -70,7 +56,7 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { abortController.abort(REQUEST_CANCELED) } } - }, [dispatch, isNuclioModeDisabled, params.projectName]) + }, [dispatch, isNuclioModeDisabled, params.projectName, project?.data?.metadata?.name]) const functions = useMemo(() => { const groupeFunctionsRunning = groupByUniqName( @@ -207,6 +193,7 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled }) => { } ProjectFunctions.propTypes = { - nuclioStreamsAreEnabled: PropTypes.bool.isRequired + nuclioStreamsAreEnabled: PropTypes.bool.isRequired, + project: PropTypes.object.isRequired } export default React.memo(ProjectFunctions) diff --git a/src/elements/ProjectJobs/ProjectJobs.jsx b/src/elements/ProjectJobs/ProjectJobs.jsx index 40ece40809..a81fea35fb 100644 --- a/src/elements/ProjectJobs/ProjectJobs.jsx +++ b/src/elements/ProjectJobs/ProjectJobs.jsx @@ -21,6 +21,7 @@ import React, { useEffect, useMemo, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import moment from 'moment' +import PropTypes from 'prop-types' import ProjectDataCard from '../ProjectDataCard/ProjectDataCard' @@ -30,7 +31,7 @@ import { PAST_24_HOUR_DATE_OPTION } from '../../utils/datePicker.util' import { getJobsStatistics, getJobsTableData, groupByName, sortByDate } from './projectJobs.utils' import { fetchProjectJobs } from '../../reducers/projectReducer' -const ProjectJobs = () => { +const ProjectJobs = ({ project }) => { const [groupedLatestItem, setGroupedLatestItem] = useState([]) const params = useParams() const dispatch = useDispatch() @@ -43,21 +44,23 @@ const ProjectJobs = () => { }, [projectStore.project?.jobs?.data]) useEffect(() => { - const abortController = new AbortController() - const startTimeFrom = moment().add(-7, 'days').toISOString() - - dispatch( - fetchProjectJobs({ - project: params.projectName, - startTimeFrom, - signal: abortController.signal - }) - ) - - return () => { - abortController.abort(REQUEST_CANCELED) + if (project?.data?.metadata?.name === params.projectName) { + const abortController = new AbortController() + const startTimeFrom = moment().add(-7, 'days').toISOString() + + dispatch( + fetchProjectJobs({ + project: params.projectName, + startTimeFrom, + signal: abortController.signal + }) + ) + + return () => { + abortController.abort(REQUEST_CANCELED) + } } - }, [dispatch, params.projectName]) + }, [dispatch, params.projectName, project?.data?.metadata?.name]) const jobsData = useMemo(() => { const statistics = getJobsStatistics(projectStore.projectSummary, params.projectName) @@ -88,4 +91,8 @@ const ProjectJobs = () => { ) } +ProjectJobs.propTypes = { + project: PropTypes.object.isRequired +} + export default React.memo(ProjectJobs) diff --git a/src/reducers/projectReducer.js b/src/reducers/projectReducer.js index c596a74153..9104540b9a 100644 --- a/src/reducers/projectReducer.js +++ b/src/reducers/projectReducer.js @@ -19,7 +19,6 @@ such restriction. */ import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' -import nuclioApi from '../api/nuclio' import projectsApi from '../api/projects-api' import { hideLoading, showLoading } from './redux.util' import { @@ -33,6 +32,7 @@ import { showErrorNotification } from 'igz-controls/utils/notification.util' import { parseSummaryData } from '../utils/parseSummaryData' import { mlrunUnhealthyErrors } from '../components/ProjectsPage/projects.util' import { aggregateApplicationStatuses, splitApplicationsContent } from '../utils/applications.utils' +import { fetchNuclioFunctions } from './nuclioReducer' const initialState = { deletingProjects: {}, @@ -247,12 +247,12 @@ export const fetchProjectSecrets = createAsyncThunk( return projectsApi.getProjectSecrets(project).catch(error => thunkAPI.rejectWithValue(error)) } ) -export const fetchProjectSummary = createAsyncThunk( - 'fetchProjectSummary', - ({ project, signal }, thunkAPI) => { +export const fetchProjectSummaryAndNuclioFuncs = createAsyncThunk( + 'fetchProjectSummaryAndNuclioFuncs', + ({ project, projectSummarySignal, functionsSignal }, thunkAPI) => { return Promise.all([ - projectsApi.getProjectSummary(project, signal), - nuclioApi.getFunctions(project) + projectsApi.getProjectSummary(project, projectSummarySignal), + thunkAPI.dispatch(fetchNuclioFunctions({ project, signal: functionsSignal })).unwrap() ]) .then(([projectSummary, nuclioFunctions]) => { const parsedProjectSummary = parseSummaryData(projectSummary.data) @@ -524,17 +524,17 @@ const projectStoreSlice = createSlice({ loading: false } }) - builder.addCase(fetchProjectSummary.pending, state => { + builder.addCase(fetchProjectSummaryAndNuclioFuncs.pending, state => { state.projectSummary.loading = true }) - builder.addCase(fetchProjectSummary.fulfilled, (state, action) => { + builder.addCase(fetchProjectSummaryAndNuclioFuncs.fulfilled, (state, action) => { state.projectSummary = { data: action.payload, error: null, loading: false } }) - builder.addCase(fetchProjectSummary.rejected, (state, action) => { + builder.addCase(fetchProjectSummaryAndNuclioFuncs.rejected, (state, action) => { state.projectSummary = { data: [], error: action.payload.message, From cabc368845fd696ebb1a723b8e0fb4ad13cc2f97 Mon Sep 17 00:00:00 2001 From: mariana-furyk Date: Wed, 19 Nov 2025 16:07:29 +0200 Subject: [PATCH 225/228] Impl [Infra] Update MLrun UI React 18 to 19 --- package.json | 111 +- src/common/DatePicker/DatePickerView.jsx | 15 +- src/common/ExpandableText/ExpandableText.jsx | 4 +- src/common/Notifications/Notification.jsx | 2 +- src/common/Pagination/Pagination.jsx | 7 +- src/common/ReactFlow/MlReactFlow.jsx | 4 +- src/common/Search/Search.jsx | 133 +- src/common/Select/Select.jsx | 35 +- src/common/Sort/Sort.jsx | 8 +- src/common/TargetPath/TargetPath.jsx | 77 +- src/components/ActionBar/ActionBar.jsx | 66 +- src/components/Details/Details.jsx | 6 +- .../DetailsPromptTemplate/PromptTab.jsx | 94 +- .../DetailsAnalysis/DetailsAnalysis.jsx | 8 +- src/components/DetailsCode/DetailsCode.jsx | 6 +- .../DetailsFeaturesAnalysis.jsx | 2 +- .../DetailsMetrics/DetailsMetrics.jsx | 8 +- src/components/DetailsPods/DetailsPods.jsx | 10 +- .../DetailsStatistics/DetailsStatistics.jsx | 2 +- .../DetailsStatisticsTableRow.jsx | 5 +- .../DetailsTransformations.jsx | 50 +- .../FeatureSetsPanel/FeatureSetsPanel.jsx | 12 +- .../FeatureSetsPanelTargetStore.jsx | 204 +-- .../FeatureSetsPanelTitle.jsx | 10 +- .../FilterMenuModal/FilterMenuModal.jsx | 26 +- .../FunctionsPanel/FunctionsPanel.jsx | 8 +- src/components/JobWizard/JobWizard.jsx | 18 +- .../JobWizardFunctionSelection.jsx | 2 +- src/components/Jobs/Jobs.jsx | 20 +- .../CreateProjectDialog.jsx | 22 +- .../RegisterArtifactModal.jsx | 53 +- .../DeleteArtifactPopUp.jsx | 33 +- .../DetailsInfoItemChip.jsx | 4 +- .../ArtifactPopUp/ArtifactPopUp.jsx | 4 +- .../FeatureSetPopUp/FeatureSetPopUp.jsx | 4 +- .../FeatureVectorPopUp/FeatureVectorPopUp.jsx | 4 +- .../FunctionPopUp/FunctionPopUp.jsx | 15 +- .../DetailsPopUp/JobPopUp/JobPopUp.jsx | 4 +- .../FormDataInputsRow/FormDataInputsRow.jsx | 4 +- .../FormEnvironmentVariablesRow.jsx | 4 +- .../FormParametersRow/FormParametersRow.jsx | 4 +- .../FormVolumesRow/FormVolumesRow.jsx | 10 +- .../FunctionsPanelCode/FunctionsPanelCode.jsx | 44 +- .../FunctionsPanelEnvironmentVariables.jsx | 4 +- .../MetricsSelector/MetricsSelector.jsx | 34 +- .../NewFunctionPopUp/NewFunctionPopUp.jsx | 16 +- .../PanelCredentialsAccessKey.jsx | 4 +- src/elements/ProjectCard/ProjectCard.jsx | 11 +- src/elements/ProjectJobs/ProjectJobs.jsx | 11 +- .../ProjectStatisticsCounter.jsx | 12 +- .../AlertsCounters.jsx | 21 +- .../ScheduledJobsCounters.jsx | 18 +- src/elements/ReadOnlyChips/ReadOnlyChips.jsx | 10 +- .../RegisterModelModal/RegisterModelModal.jsx | 20 +- .../WorkflowsTable/WorkflowsTable.jsx | 1364 ++++++++--------- src/hooks/mode.hook.js | 6 +- src/hooks/nuclioMode.hook.js | 2 +- src/hooks/openPanel.hook.js | 4 +- src/hooks/useJobsPageData.js | 9 +- src/hooks/useModalBlockHistory.hook.js | 19 +- src/hooks/useRefreshAlerts.hook.js | 4 +- src/hooks/useSortTable.hook.jsx | 65 +- src/hooks/useVirtualization.hook.js | 12 +- src/layout/Page/Page.jsx | 4 +- ...apComponentForNavbarNavigationTracking.jsx | 15 +- 65 files changed, 1467 insertions(+), 1360 deletions(-) diff --git a/package.json b/package.json index 6545c0e419..baecb97278 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "dependencies": { "@monaco-editor/react": "^4.7.0", "@reduxjs/toolkit": "^1.9.5", - "axios": "1.12.0", + "axios": "1.12.2", "bfj": "^7.0.2", "camelcase": "^6.3.0", "chart.js": "^4.4.2", @@ -32,14 +32,14 @@ "prompts": "^2.4.2", "prop-types": "^15.8.1", "qs": "^6.9.6", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", "react-final-form": "^6.5.9", "react-final-form-arrays": "^3.1.4", "react-modal-promise": "^1.0.2", "react-redux": "^7.2.9", "react-refresh": "^0.11.0", - "react-router-dom": "6.22.3", + "react-router-dom": "7.9.4", "react-text-mask": "^5.4.3", "react-transition-group": "^4.4.5", "reactflow": "^11.11.1", @@ -57,6 +57,7 @@ "start": "vite", "build": "vite build", "lint": "eslint .", + "stylelint": "stylelint '**/*.{css,scss}'", "preview": "vite preview", "preinstall": "npx force-resolutions", "test:coverage": "npm run test -- --coverage --watchAll=false", @@ -75,85 +76,73 @@ "nui": "npm unlink iguazio.dashboard-react-controls" }, "devDependencies": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.24.1", - "@babel/node": "^7.14.9", - "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", + "@babel/core": "^7.28.4", + "@babel/node": "^7.28.0", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", "@babel/polyfill": "^7.12.1", - "@babel/preset-env": "^7.13.12", - "@babel/register": "^7.13.14", + "@babel/preset-env": "^7.28.3", + "@babel/preset-react": "^7.27.1", + "@babel/register": "^7.28.3", "@cucumber/cucumber": "^10.3.1", "@d4c/numjs": "^0.17.34", - "@eslint/js": "^9.19.0", - "@storybook/addon-actions": "^8.0.1", - "@storybook/addon-essentials": "^8.0.1", - "@storybook/addon-links": "^8.0.1", + "@eslint/js": "^9.37.0", + "@storybook/addon-docs": "9.1.10", + "@storybook/addon-links": "^9.1.10", + "@storybook/builder-vite": "^9.1.10", "@storybook/preset-scss": "^1.0.3", - "@storybook/react": "^8.0.1", - "@testing-library/react": "^11.0.2", + "@storybook/react-vite": "^9.1.10", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.0", "@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react-swc": "^3.8.0", - "acorn": "^7.4.1", - "babel-jest": "^29.7.0", - "babel-loader": "^8.2.3", + "acorn": "^8.15.0", + "babel-jest": "^30.2.0", "babel-node": "0.0.1-security", - "babel-plugin-inline-react-svg": "^2.0.1", - "babel-plugin-jest-hoist": "^26.2.0", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-plugin-prismjs": "^2.1.0", - "babel-plugin-react-remove-properties": "^0.3.0", - "babel-preset-react-app": "^10.0.1", + "babel-plugin-inline-react-svg": "^2.0.2", + "babel-plugin-jest-hoist": "^30.0.1", "babel-runtime": "^6.26.0", - "body-parser": "^1.19.0", + "body-parser": "^2.2.0", "chai": "^4.3.4", - "chromedriver": "^140.0.0", - "cross-env": "^7.0.3", - "css-loader": "^6.5.1", - "cucumber-html-reporter": "^5.3.0", - "eslint": "^9.13.0", - "eslint-config-prettier": "^9.1.0", + "chromedriver": "^140.0.4", + "cross-env": "^10.0.0", + "cucumber-html-reporter": "^7.2.0", + "eslint": "^9.37.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-babel": "^5.3.1", "eslint-plugin-import": "^2.32.0", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-hooks": "^5.1.0", - "eslint-plugin-react-refresh": "^0.4.14", - "express": "^4.17.1", - "file-loader": "^6.2.0", - "geckodriver": "^3.0.1", - "globals": "^15.14.0", - "http-proxy-middleware": "^2.0.3", - "mime-types": "^2.1.35", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^7.0.0", + "eslint-plugin-react-refresh": "^0.4.23", + "eslint-plugin-storybook": "9.1.10", + "express": "^5.1.0", + "geckodriver": "^6.0.1", + "globals": "^16.4.0", + "mime-types": "^3.0.1", "node": "^21.6.2", - "nodemon": "^3.1.2", + "nodemon": "^3.1.10", "pandas-js": "^0.2.4", - "postcss": "^8.4.36", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^9.5.2", - "postcss-safe-parser": "7.0.0", - "prettier": "^3.3.3", + "prettier": "^3.6.2", "randexp": "^0.5.3", "react-app-polyfill": "^3.0.0", "react-dev-utils": "^12.0.1", - "sass": "^1.72.0", - "sass-loader": "^12.3.2", + "sass": "^1.93.2", "selenium-webdriver": "^4.35.0", - "source-map-loader": "^5.0.0", - "stylelint": "^13.3.3", + "stylelint": "^16.24.0", "stylelint-config-rational-order": "^0.1.2", - "stylelint-config-standard": "^20.0.0", - "stylelint-order": "^4.0.0", - "stylelint-scss": "^3.17.2", + "stylelint-config-standard": "^39.0.0", + "stylelint-config-standard-scss": "^16.0.0", + "stylelint-order": "^7.0.0", + "stylelint-scss": "^6.12.1", "url-loader": "4.1.1", - "vite": "^6.2.0", + "vite": "^6.3.6", "vite-plugin-commonjs": "^0.10.4", "vite-plugin-eslint": "^1.8.1", - "vite-plugin-svgr": "^4.3.0" + "vite-plugin-svgr": "^4.5.0" }, "babel": { "plugins": [ - "@babel/plugin-proposal-logical-assignment-operators" + "@babel/plugin-transform-logical-assignment-operators" ], "presets": [ [ @@ -162,6 +151,10 @@ "useBuiltIns": "usage", "corejs": "^3.23.3" } + ], + [ + "@babel/preset-react", + {} ] ] } diff --git a/src/common/DatePicker/DatePickerView.jsx b/src/common/DatePicker/DatePickerView.jsx index 1b9f143d04..663151720c 100644 --- a/src/common/DatePicker/DatePickerView.jsx +++ b/src/common/DatePicker/DatePickerView.jsx @@ -104,13 +104,10 @@ const DatePickerView = React.forwardRef( isInputInvalid && 'input_invalid' ) const inputLabelClassNames = classnames('input__label', label && 'active-label') + const { datePickerRef, datePickerViewRef } = ref return ( -
      +
      -
      +
      {datePickerOptions.map(option => ( -
      +
      {config.map(item => (
      diff --git a/src/common/ExpandableText/ExpandableText.jsx b/src/common/ExpandableText/ExpandableText.jsx index fe38a4260f..fce738e0ae 100644 --- a/src/common/ExpandableText/ExpandableText.jsx +++ b/src/common/ExpandableText/ExpandableText.jsx @@ -35,7 +35,9 @@ const ExpandableText = ({ useEffect(() => { if (forceExpand || contextForceExpand) { - setExpanded(forceExpand || contextForceExpand) + queueMicrotask(() => { + setExpanded(forceExpand || contextForceExpand) + }) } }, [contextForceExpand, forceExpand]) diff --git a/src/common/Notifications/Notification.jsx b/src/common/Notifications/Notification.jsx index 23ce82c3c3..bbd754e08c 100644 --- a/src/common/Notifications/Notification.jsx +++ b/src/common/Notifications/Notification.jsx @@ -42,7 +42,7 @@ const Notification = ({ notification, timeoutMs = 10000, ...rest }) => { const nodeRef = useRef() const { pauseTimeout, resumeTimeout, cancelTimeout } = useTimeout( - () => handleRemoveNotification(notification.id), + () => dispatch(removeNotification(notification.id)), timeoutMs ) diff --git a/src/common/Pagination/Pagination.jsx b/src/common/Pagination/Pagination.jsx index 65c0ec1dcf..4edf1c8410 100644 --- a/src/common/Pagination/Pagination.jsx +++ b/src/common/Pagination/Pagination.jsx @@ -50,13 +50,11 @@ const Pagination = ({ disableNextDoubleBtn = false, disabledNextDoubleBtnTooltip = '', paginationConfig, - selectedItemName = '', + selectedItemName = '' }) => { const [, setSearchParams] = useSearchParams() const navigate = useNavigate() const paginationPagesRef = useRef() - const leftSideRef = useRef(0) - const rightSideRef = useRef(0) // Total pages are now calculated based on start and end pages const totalPagesCount = useMemo( @@ -118,9 +116,6 @@ const Pagination = ({ leftSide = lastPage - 4 } - rightSideRef.current = rightSide - leftSideRef.current = leftSide - if (leftSide > firstPage + 1) { items.push(threeDotsString) } diff --git a/src/common/ReactFlow/MlReactFlow.jsx b/src/common/ReactFlow/MlReactFlow.jsx index f44552e253..90988f87d1 100644 --- a/src/common/ReactFlow/MlReactFlow.jsx +++ b/src/common/ReactFlow/MlReactFlow.jsx @@ -62,7 +62,9 @@ const MlReactFlow = ({ alignTriggerItem = '', edges, nodes, onNodeClick = () => useEffect(() => { if (reactFlowInstance && !initialGraphViewGenerated && nodes.length > 0) { - setInitialGraphViewGenerated(true) + queueMicrotask(() => { + setInitialGraphViewGenerated(true) + }) } }, [nodes.length, initialGraphViewGenerated, reactFlowInstance]) diff --git a/src/common/Search/Search.jsx b/src/common/Search/Search.jsx index e8cd1fc587..4e4e386130 100644 --- a/src/common/Search/Search.jsx +++ b/src/common/Search/Search.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useState, useEffect, useCallback, useRef } from 'react' +import React, { useState, useEffect, useCallback, useRef, useLayoutEffect } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' @@ -45,37 +45,30 @@ const Search = ({ wrapperClassName = '' }) => { const [searchValue, setSearchValue] = useState(value ?? '') - const [label, setLabel] = useState('') + // const [label, setLabel] = useState('') const [inputIsFocused, setInputFocused] = useState(false) + const [searchWidth, setSearchWidth] = useState(0) + const [hasMatch, setHasMatch] = useState(false) const searchRef = useRef() const popUpRef = useRef() - - const { width: searchWidth } = searchRef?.current?.getBoundingClientRect() || {} - const searchClassNames = classnames('search-container', className) - const handleSearchOnBlur = useCallback( - event => { - if ( - (event.type === 'click' && - searchRef.current && - !searchRef.current.contains(event.target)) || - (event.type === 'scroll' && popUpRef.current && !popUpRef?.current.contains(event.target)) - ) { - setInputFocused(false) - } - }, - [searchRef] - ) + // === Обчислення ширини інпута після монтування === + useLayoutEffect(() => { + if (searchRef.current) { + const { width } = searchRef.current.getBoundingClientRect() + setSearchWidth(width) + } + }, []) - useEffect(() => { - if (matches.length > 0 && searchValue.length > 0) { - setLabel( - matches.find(item => item.toLocaleLowerCase().includes(searchValue.toLocaleLowerCase())) ?? - '' - ) + const handleSearchOnBlur = useCallback(event => { + if ( + (event.type === 'click' && searchRef.current && !searchRef.current.contains(event.target)) || + (event.type === 'scroll' && popUpRef.current && !popUpRef.current.contains(event.target)) + ) { + setInputFocused(false) } - }, [matches, searchValue]) + }, []) useEffect(() => { window.addEventListener('click', handleSearchOnBlur) @@ -87,46 +80,53 @@ const Search = ({ } }, [handleSearchOnBlur]) - const searchOnChange = value => { - if (value.length === 0 && label.length > 0) { - setLabel('') - } - - onChange(value) + // === Основна логіка оновлення значення === + const handleSearchChange = value => { + const cleanValue = deleteUnsafeHtml(value) + setSearchValue(cleanValue) setInputFocused(true) - setSearchValue(deleteUnsafeHtml(value)) + onChange(cleanValue) + + const matchExists = matches.some(item => + item.toLocaleLowerCase().includes(cleanValue.toLocaleLowerCase()) + ) + setHasMatch(matchExists) } - const matchOnClick = item => { - setLabel('') + // === Клік на елемент зі списку === + const handleMatchClick = item => { setSearchValue(item) - onChange(item) + setHasMatch(false) setInputFocused(false) + onChange(item) } - const handleSearchIconClick = event => { + // === Клік по іконці пошуку === + const handleIconClick = event => { event.stopPropagation() - if (searchValue.length > 0) { + if (searchValue.trim().length > 0) { onChange(searchValue) setInputFocused(false) } } useEffect(() => { - if (searchValue.length > 0 && value !== searchValue) { - setSearchValue(value) + if (value !== searchValue) { + queueMicrotask(() => setSearchValue(value ?? '')) } }, [searchValue, value]) + const filteredMatches = inputIsFocused + ? matches.filter(item => item.toLocaleLowerCase().includes(searchValue.toLocaleLowerCase())) + : [] + return (
      { - setInputFocused(true) - }} + onClick={() => setInputFocused(true)} > } iconClass="search-icon" - iconOnClick={handleSearchIconClick} - onChange={searchOnChange} + iconOnClick={handleIconClick} + onChange={handleSearchChange} onFocus={onFocus} focused={inputIsFocused} onKeyDown={event => { - if (event.key === 'Enter' && !searchWhileTyping && searchValue !== '') { + if (event.key === 'Enter' && !searchWhileTyping && searchValue.trim() !== '') { onChange(searchValue) setInputFocused(false) } @@ -150,7 +150,8 @@ const Search = ({ value={searchValue} withoutBorder={withoutBorder} /> - {matches.length > 0 && label.length > 0 && inputIsFocused && ( + + {filteredMatches.length > 0 && hasMatch && (
        - {matches.reduce((options, item, index) => { - if (item?.toLocaleLowerCase().includes(searchValue.toLocaleLowerCase())) { - options.push( - (match ? `${match}` : match) - ) - }} - name={item} - key={item + index} - onClick={() => matchOnClick(item)} - tabIndex={index} - /> - ) - } - - return options - }, [])} + {filteredMatches.map((item, index) => ( + (match ? `${match}` : match) + ) + }} + name={item} + onClick={() => handleMatchClick(item)} + tabIndex={index} + /> + ))}
      )} diff --git a/src/common/Select/Select.jsx b/src/common/Select/Select.jsx index 6a0b9f1840..528ecbd92f 100644 --- a/src/common/Select/Select.jsx +++ b/src/common/Select/Select.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useState, useEffect, useCallback, useRef } from 'react' +import React, { useState, useEffect, useCallback, useRef, useLayoutEffect } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' @@ -56,7 +56,7 @@ const Select = ({ const [isConfirmDialogOpen, setConfirmDialogOpen] = useState(false) const [isOpen, setOpen] = useState(false) const [searchValue, setSearchValue] = useState('') - const { width: dropdownWidth } = selectRef?.current?.getBoundingClientRect() || {} + const [dropdownWidth, setDropdownWidth] = useState(0) const selectClassName = classNames( 'select', className, @@ -77,6 +77,18 @@ const Select = ({ ) const selectedOption = options.find(option => option.id === selectedId) + const clickHandler = event => { + if (selectRef.current !== event.target.closest('.select')) { + setOpen(false) + } + } + + const handleScroll = event => { + if (!event.target.closest('.select__body')) { + setOpen(false) + } + } + useEffect(() => { if (isOpen) { window.addEventListener('scroll', handleScroll, true) @@ -90,18 +102,6 @@ const Select = ({ } }, [isOpen]) - const clickHandler = event => { - if (selectRef.current !== event.target.closest('.select')) { - setOpen(false) - } - } - - const handleScroll = event => { - if (!event.target.closest('.select__body')) { - setOpen(false) - } - } - const toggleOpen = () => { !disabled && setOpen(!isOpen) } @@ -115,6 +115,13 @@ const Select = ({ } }, []) + useLayoutEffect(() => { + if (selectRef.current) { + const { width } = selectRef.current.getBoundingClientRect() + setDropdownWidth(width) + } + }, [selectRef]) + const handleSelectOptionClick = (selectedOption, option) => { if (selectedOption !== selectedId) { option.handler && option.handler() diff --git a/src/common/Sort/Sort.jsx b/src/common/Sort/Sort.jsx index bc08550d2c..22c0774304 100644 --- a/src/common/Sort/Sort.jsx +++ b/src/common/Sort/Sort.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { useEffect, useState } from 'react' +import React from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' @@ -35,16 +35,12 @@ const Sort = ({ selectedId, setIsDescendingOrder }) => { - const [selectedOption, setSelectedOption] = useState(null) + const selectedOption = options.find(option => option.id === selectedId) const arrowDirectionClassName = classNames( 'sort-icon', isDescendingOrder ? 'sort-icon_down' : 'sort-icon_up' ) - useEffect(() => { - setSelectedOption(options.find(option => option.id === selectedId)) - }, [options, selectedId]) - return (
      { + if (value.length !== 0) { + formState.form.change(`${formStateFieldInfo}.value`, value.replace(/[^:/]*:[/]{2,3}/, '')) + formState.form.change(`${formStateFieldInfo}.pathType`, value.match(/^\w*:[/]{2,3}/)[0]) + + if (formStateDataInputState) { + formState.form.change(`${formStateDataInputState}`, dataInputState) + } + } + }, + [dataInputState, formState.form, formStateDataInputState, formStateFieldInfo] + ) + const handleGetProjectsNames = useCallback(() => { getProjectsNames(dispatch, setDataInputState, params.projectName) - }, [dispatch, params.projectName]) + }, [dispatch, setDataInputState, params.projectName]) const handleGetArtifacts = useCallback(() => { getArtifacts(dispatch, dataInputState.project, dataInputState.storePathType, setDataInputState) - }, [dataInputState.project, dataInputState.storePathType, dispatch]) + }, [dataInputState.project, dataInputState.storePathType, dispatch, setDataInputState]) const handleGetFeatureVectors = useCallback(() => { getFeatureVectors(dispatch, dataInputState.project, setDataInputState) - }, [dataInputState.project, dispatch]) + }, [dataInputState.project, dispatch, setDataInputState]) const handleGetArtifact = useCallback(() => { getArtifact(dispatch, dataInputState.project, dataInputState.projectItem, setDataInputState) - }, [dataInputState.project, dataInputState.projectItem, dispatch]) + }, [dataInputState.project, dataInputState.projectItem, dispatch, setDataInputState]) const handleGetFeatureVector = useCallback(() => { getFeatureVector( @@ -103,7 +117,7 @@ const TargetPath = ({ dataInputState.projectItem, setDataInputState ) - }, [dataInputState.project, dataInputState.projectItem, dispatch]) + }, [dataInputState.project, dataInputState.projectItem, dispatch, setDataInputState]) useEffect(() => { if (dataInputState.inputStorePathTypeEntered && dataInputState.projects.length === 0) { @@ -120,24 +134,27 @@ const TargetPath = ({ if ( get(formState.values, `${formStateFieldInfo}.pathType`) === MLRUN_STORAGE_INPUT_PATH_SCHEME ) { - setDataInputState(prev => ({ - ...prev, - comboboxMatches: generateComboboxMatchesList( - dataInputState.artifacts, - dataInputState.artifactsReferences, - dataInputState.featureVectors, - dataInputState.featureVectorsReferences, - dataInputState.inputProjectItemPathEntered, - dataInputState.inputProjectItemReferencePathEntered, - dataInputState.inputProjectPathEntered, - dataInputState.inputStorePathTypeEntered, - dataInputState.project, - dataInputState.projectItem, - dataInputState.projectItemReference, - dataInputState.projects, - dataInputState.storePathType - ) - })) + //TODO + setTimeout(() => { + setDataInputState(prev => ({ + ...prev, + comboboxMatches: generateComboboxMatchesList( + dataInputState.artifacts, + dataInputState.artifactsReferences, + dataInputState.featureVectors, + dataInputState.featureVectorsReferences, + dataInputState.inputProjectItemPathEntered, + dataInputState.inputProjectItemReferencePathEntered, + dataInputState.inputProjectPathEntered, + dataInputState.inputStorePathTypeEntered, + dataInputState.project, + dataInputState.projectItem, + dataInputState.projectItemReference, + dataInputState.projects, + dataInputState.storePathType + ) + })) + }, 0) } }, [ dataInputState.artifacts, @@ -215,20 +232,6 @@ const TargetPath = ({ handleGetFeatureVector ]) - const handlePathChange = useCallback( - value => { - if (value.length !== 0) { - formState.form.change(`${formStateFieldInfo}.value`, value.replace(/[^:/]*:[/]{2,3}/, '')) - formState.form.change(`${formStateFieldInfo}.pathType`, value.match(/^\w*:[/]{2,3}/)[0]) - - if (formStateDataInputState) { - formState.form.change(`${formStateDataInputState}`, dataInputState) - } - } - }, - [dataInputState, formState.form, formStateDataInputState, formStateFieldInfo] - ) - return ( <> { - const initialValues = { + return { [AUTO_REFRESH_ID]: autoRefreshIsEnabled, [INTERNAL_AUTO_REFRESH_ID]: internalAutoRefreshIsEnabled, ...formFiltersInitialValues } - - return initialValues }, [autoRefreshIsEnabled, formFiltersInitialValues, internalAutoRefreshIsEnabled]) - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ initialValues: formInitialValues, mutators: { ...arrayMutators, setFieldState }, onSubmit: () => {} }) - ) + }) const filterMenuModalInitialState = useMemo(() => { return mapValues( @@ -187,7 +184,8 @@ const ActionBar = ({ const applyFilters = useCallback( async (formValues, filters, actionCanBePerformedChecked) => { - const actionCanBePerformed = actionCanBePerformedChecked || await performDetailsActionHelper(changes, dispatch, true) + const actionCanBePerformed = + actionCanBePerformedChecked || (await performDetailsActionHelper(changes, dispatch, true)) const newFilters = { ...filters, ...formValues } if (actionCanBePerformed) { @@ -277,14 +275,14 @@ const ActionBar = ({ } useEffect(() => { - if (!isEqual(formRef.current?.getState().values, filterMenu)) { - formRef.current?.batch(() => { + if (!isEqual(form.getState().values, filterMenu)) { + form.batch(() => { for (const filterName in filterMenu) { - formRef.current?.change(filterName, filterMenu[filterName]) + form.change(filterName, filterMenu[filterName]) } }) } - }, [filterMenu, filtersConfig]) + }, [filterMenu, filtersConfig, form]) useEffect(() => { if ( @@ -294,7 +292,7 @@ const ActionBar = ({ ) { const intervalId = setInterval(() => { if (!autoRefreshIsStopped) { - refresh(formRef.current.getState()) + refresh(form.getState()) } }, 30000) @@ -306,19 +304,24 @@ const ActionBar = ({ refresh, withInternalAutoRefresh, filtersStore.internalAutoRefresh, - filtersStore.autoRefresh + filtersStore.autoRefresh, + form ]) useEffect(() => { if (autoRefreshStopTrigger && filtersStore.internalAutoRefresh) { - formRef.current?.change(INTERNAL_AUTO_REFRESH_ID, false) - setInternalAutoRefreshPrevValue(true) + form.change(INTERNAL_AUTO_REFRESH_ID, false) + queueMicrotask(() => { + setInternalAutoRefreshPrevValue(true) + }) dispatch(toggleInternalAutoRefresh(false)) handleAutoRefreshPrevValueChange && handleAutoRefreshPrevValueChange(true) } else if (!autoRefreshStopTrigger && internalAutoRefreshPrevValue) { - setInternalAutoRefreshPrevValue(false) + queueMicrotask(() => { + setInternalAutoRefreshPrevValue(false) + }) dispatch(toggleInternalAutoRefresh(true)) - formRef.current?.change(INTERNAL_AUTO_REFRESH_ID, true) + form.change(INTERNAL_AUTO_REFRESH_ID, true) handleAutoRefreshPrevValueChange && handleAutoRefreshPrevValueChange(false) } }, [ @@ -326,7 +329,8 @@ const ActionBar = ({ autoRefreshStopTrigger, handleAutoRefreshPrevValueChange, dispatch, - filtersStore.internalAutoRefresh + filtersStore.internalAutoRefresh, + form ]) useEffect(() => { @@ -336,21 +340,21 @@ const ActionBar = ({ }, []) useLayoutEffect(() => { - const prevValues = formRef.current.getState().values + const prevValues = form.getState().values const valuesToReset = { [INTERNAL_AUTO_REFRESH_ID]: prevValues[INTERNAL_AUTO_REFRESH_ID], [AUTO_REFRESH_ID]: prevValues[AUTO_REFRESH_ID], ...formFiltersInitialValues } - formRef.current.reset(valuesToReset) - }, [formFiltersInitialValues]) + form.reset(valuesToReset) + }, [formFiltersInitialValues, form]) useLayoutEffect(() => { - formRef.current?.batch(() => { - formRef.current?.change(AUTO_REFRESH_ID, autoRefreshIsEnabled) - formRef.current?.change(INTERNAL_AUTO_REFRESH_ID, internalAutoRefreshIsEnabled) + form.batch(() => { + form.change(AUTO_REFRESH_ID, autoRefreshIsEnabled) + form.change(INTERNAL_AUTO_REFRESH_ID, internalAutoRefreshIsEnabled) }) - }, [autoRefreshIsEnabled, internalAutoRefreshIsEnabled]) + }, [autoRefreshIsEnabled, form, internalAutoRefreshIsEnabled]) useEffect(() => { dispatch(toggleAutoRefresh(false)) @@ -358,7 +362,7 @@ const ActionBar = ({ }, [dispatch, params.projectName]) return ( -
      {}}> + {}}> {formState => (
      @@ -404,7 +408,9 @@ const ActionBar = ({
      {!isEmpty(filterMenuModalInitialState) && ( applyFilters(formState.values, filterMenuModal, actionCanBePerformedChecked)} + applyChanges={(filterMenuModal, actionCanBePerformedChecked) => + applyFilters(formState.values, filterMenuModal, actionCanBePerformedChecked) + } initialValues={filterMenuModalInitialState} values={filterMenuModal} detailsChanges={changes} diff --git a/src/components/Details/Details.jsx b/src/components/Details/Details.jsx index 1bed60c636..10617d5f5e 100644 --- a/src/components/Details/Details.jsx +++ b/src/components/Details/Details.jsx @@ -81,7 +81,7 @@ const Details = ({ detailsRef, commonDetailsStore, doNotLeavePage, - formRef, + form, handleShowWarning, leavePage, location, @@ -180,7 +180,7 @@ const Details = ({ detailsStore={detailsStore} commonDetailsStore={commonDetailsStore} doNotLeavePage={doNotLeavePage} - formRef={formRef} + form={form} isDetailsPopUp={isDetailsPopUp} leavePage={leavePage} renderHeader={() => ( @@ -201,7 +201,7 @@ const Details = ({ withActionMenu={withActionMenu} /> )} - renderTabsContent={(formState) => ( + renderTabsContent={formState => ( { - if (!isEmpty(selectedItem.prompt_template)) { - if (!isPromptTemplateValid(selectedItem.prompt_template)) { - setShowError(true) - } else { - setPromptTemplate( - generateJsxContent(selectedItem.prompt_template, selectedItem.prompt_legend) - ) - } - } else if (isEmpty(artifactsStore.LLMPrompts.promptTemplate)) { - if ( - !selectedItem.target_path.endsWith('.txt') && - !selectedItem.target_path.endsWith('.json') - ) { - setShowError(true) - } else { - setLoading(true) - dispatch( - fetchLLMPromptTemplate({ - project: selectedItem.project, - config: { - params: { - path: selectedItem.target_path + queueMicrotask(() => { + if (!isEmpty(selectedItem.prompt_template)) { + if (!isPromptTemplateValid(selectedItem.prompt_template)) { + setShowError(true) + } else { + setPromptTemplate( + generateJsxContent(selectedItem.prompt_template, selectedItem.prompt_legend) + ) + } + } else if (isEmpty(artifactsStore.LLMPrompts.promptTemplate)) { + if ( + !selectedItem.target_path.endsWith('.txt') && + !selectedItem.target_path.endsWith('.json') + ) { + setShowError(true) + } else { + setLoading(true) + dispatch( + fetchLLMPromptTemplate({ + project: selectedItem.project, + config: { + params: { + path: selectedItem.target_path + } } - } - }) - ) - .unwrap() - .then(response => { - if (!isPromptTemplateValid(response.data)) { - setShowError(true) - } else { - setPromptTemplate(generateJsxContent(response.data, selectedItem.prompt_legend)) - } - }) - .catch(() => setShowError(true)) - .finally(() => { - setLoading(false) - }) - } - } else if (!isEmpty(artifactsStore.LLMPrompts.promptTemplate)) { - if (!isPromptTemplateValid(artifactsStore.LLMPrompts.promptTemplate)) { - return setShowError(true) - } else { - setPromptTemplate( - generateJsxContent(artifactsStore.LLMPrompts.promptTemplate, selectedItem.prompt_legend) - ) + }) + ) + .unwrap() + .then(response => { + if (!isPromptTemplateValid(response.data)) { + setShowError(true) + } else { + setPromptTemplate(generateJsxContent(response.data, selectedItem.prompt_legend)) + } + }) + .catch(() => setShowError(true)) + .finally(() => { + setLoading(false) + }) + } + } else if (!isEmpty(artifactsStore.LLMPrompts.promptTemplate)) { + if (!isPromptTemplateValid(artifactsStore.LLMPrompts.promptTemplate)) { + return setShowError(true) + } else { + setPromptTemplate( + generateJsxContent(artifactsStore.LLMPrompts.promptTemplate, selectedItem.prompt_legend) + ) + } } - } + }) }, [ selectedItem.prompt_template, selectedItem.prompt_legend, diff --git a/src/components/DetailsAnalysis/DetailsAnalysis.jsx b/src/components/DetailsAnalysis/DetailsAnalysis.jsx index 83f91a6eba..3db8deaffd 100644 --- a/src/components/DetailsAnalysis/DetailsAnalysis.jsx +++ b/src/components/DetailsAnalysis/DetailsAnalysis.jsx @@ -63,12 +63,16 @@ const DetailsAnalysis = ({ artifact }) => { fetchPreviewFromAnalysis() } else { showErrorNotification(dispatch, '', '', 'The analysis type is malformed. Expected dict') - setNoData(true) + queueMicrotask(() => { + setNoData(true) + }) } previewIsFetchedRef.current = true } else if (!artifact.analysis || isEmpty(artifact.analysis)) { - setNoData(true) + queueMicrotask(() => { + setNoData(true) + }) } }, [artifact.analysis, fetchPreviewFromAnalysis, preview.length, frontendSpec, dispatch]) diff --git a/src/components/DetailsCode/DetailsCode.jsx b/src/components/DetailsCode/DetailsCode.jsx index b97ebbd6fd..7e873556fc 100644 --- a/src/components/DetailsCode/DetailsCode.jsx +++ b/src/components/DetailsCode/DetailsCode.jsx @@ -32,7 +32,9 @@ const DetailsCode = ({ code = '' }) => { }, [code]) useEffect(() => { - decodeCode() + queueMicrotask(() => { + decodeCode() + }) }, [decodeCode]) const html = Prism.highlight(decoded, Prism.languages.py, 'py') @@ -53,7 +55,7 @@ const DetailsCode = ({ code = '' }) => { } DetailsCode.propTypes = { - code: PropTypes.string, + code: PropTypes.string } export default DetailsCode diff --git a/src/components/DetailsFeaturesAnalysis/DetailsFeaturesAnalysis.jsx b/src/components/DetailsFeaturesAnalysis/DetailsFeaturesAnalysis.jsx index bef5e7d90d..95756b78f0 100644 --- a/src/components/DetailsFeaturesAnalysis/DetailsFeaturesAnalysis.jsx +++ b/src/components/DetailsFeaturesAnalysis/DetailsFeaturesAnalysis.jsx @@ -33,7 +33,7 @@ import './detailsFeaturesAnalysis.scss' const DetailsFeaturesAnalysis = ({ selectedItem }) => { const table = generateFeaturesAnalysis(selectedItem) const amethystColor = useMemo(() => getScssVariableValue('--amethystColor'), []) - const chartConfig = useMemo(getHistogramChartConfig, []) + const chartConfig = useMemo(() => getHistogramChartConfig, []) return (
      diff --git a/src/components/DetailsMetrics/DetailsMetrics.jsx b/src/components/DetailsMetrics/DetailsMetrics.jsx index b88f8122e1..35db1e995b 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.jsx +++ b/src/components/DetailsMetrics/DetailsMetrics.jsx @@ -130,7 +130,9 @@ const DetailsMetrics = ({ applicationNameProp = '', selectedItem, renderTitle = const selectedDate = detailsStore.dates.selectedOptionId if (!selectedDate || !(selectedDate in timeRangeMapping)) return - setSelectedDate(timeRangeMapping[selectedDate]) + queueMicrotask(() => { + setSelectedDate(timeRangeMapping[selectedDate]) + }) }, [detailsStore.dates.selectedOptionId]) const fetchData = useCallback( @@ -214,7 +216,9 @@ const DetailsMetrics = ({ applicationNameProp = '', selectedItem, renderTitle = selectedItem.metadata.uid ) } else { - setMetrics([]) + queueMicrotask(() => { + setMetrics([]) + }) } return () => { diff --git a/src/components/DetailsPods/DetailsPods.jsx b/src/components/DetailsPods/DetailsPods.jsx index b947d8b8bd..c9dcbf8d55 100644 --- a/src/components/DetailsPods/DetailsPods.jsx +++ b/src/components/DetailsPods/DetailsPods.jsx @@ -31,7 +31,7 @@ import { generatePods } from './detailsPods.util' import './detailsPods.scss' -const DetailsPods = ({ isDetailsPopUp = false, noDataMessage = ''}) => { +const DetailsPods = ({ isDetailsPopUp = false, noDataMessage = '' }) => { const [selectedPod, setSelectedPod] = useState(null) const [table, setTable] = useState([]) const params = useParams() @@ -42,7 +42,9 @@ const DetailsPods = ({ isDetailsPopUp = false, noDataMessage = ''}) => { }, [detailsStore.detailsJobPods, detailsStore.pods, isDetailsPopUp]) useEffect(() => { - setTable(generatePods(podsData)) + queueMicrotask(() => { + setTable(generatePods(podsData)) + }) return () => { setSelectedPod(null) @@ -51,7 +53,9 @@ const DetailsPods = ({ isDetailsPopUp = false, noDataMessage = ''}) => { useEffect(() => { if (!selectedPod) { - setSelectedPod(table[0]) + queueMicrotask(() => { + setSelectedPod(table[0]) + }) } }, [selectedPod, table]) diff --git a/src/components/DetailsStatistics/DetailsStatistics.jsx b/src/components/DetailsStatistics/DetailsStatistics.jsx index e764adc51d..aebfee8431 100644 --- a/src/components/DetailsStatistics/DetailsStatistics.jsx +++ b/src/components/DetailsStatistics/DetailsStatistics.jsx @@ -58,7 +58,7 @@ const DetailsStatistics = ({ selectedItem }) => { }), [detailsStatisticsHeaderRowHeight, detailsStatisticsRowHeight] ) - const chartConfig = useMemo(getHistogramChartConfig, []) + const chartConfig = useMemo(() => getHistogramChartConfig, []) const headers = useMemo( () => Object.entries(statistics[0]).map(([label, value]) => ({ diff --git a/src/components/DetailsStatistics/DetailsStatisticsTableRow.jsx b/src/components/DetailsStatistics/DetailsStatisticsTableRow.jsx index c7edce2eed..1d496a454d 100644 --- a/src/components/DetailsStatistics/DetailsStatisticsTableRow.jsx +++ b/src/components/DetailsStatistics/DetailsStatisticsTableRow.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React, { memo, useMemo } from 'react' +import React, { memo, useId, useMemo } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' @@ -30,6 +30,7 @@ import './detailsStatistics.scss' const DetailsStatisticsTableRow = ({ statisticsItem, headers, chartConfig }) => { const amethystColor = useMemo(() => getScssVariableValue('--amethystColor'), []) + const id = useId() return (
      @@ -79,7 +80,7 @@ const DetailsStatisticsTableRow = ({ statisticsItem, headers, chartConfig }) => } return ( -
      +
      {statisticsValue.type.match(/icon/) && !statisticsValue.hidden && statisticsValue.value} {statisticsValue.type === 'chart' && statisticsValue.value[1]?.length > 0 && ( diff --git a/src/components/DetailsTransformations/DetailsTransformations.jsx b/src/components/DetailsTransformations/DetailsTransformations.jsx index 3918c4febd..525ea19560 100644 --- a/src/components/DetailsTransformations/DetailsTransformations.jsx +++ b/src/components/DetailsTransformations/DetailsTransformations.jsx @@ -155,34 +155,40 @@ const DetailsTransformations = ({ selectedItem }) => { }, [states, targets, selectedStep]) useEffect(() => { - setStates(cloneDeep(selectedItem.graph?.steps)) - setTargets(cloneDeep(selectedItem.targets)) + queueMicrotask(() => { + setStates(cloneDeep(selectedItem.graph?.steps)) + setTargets(cloneDeep(selectedItem.targets)) + }) }, [selectedItem.graph, selectedItem.targets]) useEffect(() => { - let stepsList = reject(steps, ['id', selectedStep]) + queueMicrotask(() => { + let stepsList = reject(steps, ['id', selectedStep]) - setErrorSteps(reject(stepsList, ['id', 'Source'])) - stepsList.unshift({ - id: 'Source', - label: 'Source' - }) + setErrorSteps(reject(stepsList, ['id', 'Source'])) + stepsList.unshift({ + id: 'Source', + label: 'Source' + }) - setAfterSteps(stepsList) + setAfterSteps(stepsList) + }) }, [steps, selectedStep]) useEffect(() => { - setNodes(nodes => { - return map(nodes, node => { - return { - ...node, - className: - node.id === selectedStep - ? node.className - ? (node.className += ' selected') - : 'selected' - : node.className?.replace('selected', '') - } + queueMicrotask(() => { + setNodes(nodes => { + return map(nodes, node => { + return { + ...node, + className: + node.id === selectedStep + ? node.className + ? (node.className += ' selected') + : 'selected' + : node.className?.replace('selected', '') + } + }) }) }) }, [selectedStep]) @@ -193,7 +199,9 @@ const DetailsTransformations = ({ selectedItem }) => { useEffect(() => { if (selectedItem.uid !== selectedItemUid) { - setSelectedItemUid(selectedItem.uid) + queueMicrotask(() => { + setSelectedItemUid(selectedItem.uid) + }) } }, [selectedItem, selectedItemUid]) diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanel.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanel.jsx index b864ff6c12..dbbed3bcee 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanel.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanel.jsx @@ -73,13 +73,13 @@ const FeatureSetsPanel = ({ closePanel, createFeatureSetSuccess, project }) => { const [accessKeyRequired, setAccessKeyRequired] = useState(false) const navigate = useNavigate() const dispatch = useDispatch() - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ initialValues: { labels: [] }, mutators: { ...arrayMutators, setFieldState }, onSubmit: () => {} }) - ) + }) const handleSave = () => { let data = { @@ -87,7 +87,7 @@ const FeatureSetsPanel = ({ closePanel, createFeatureSetSuccess, project }) => { ...featureStore.newFeatureSet, metadata: { ...featureStore.newFeatureSet.metadata, - labels: convertChipsData(formRef.current.getFieldState('labels')?.value), + labels: convertChipsData(form.getFieldState('labels')?.value), tag: featureStore.newFeatureSet.metadata.tag || TAG_FILTER_LATEST } } @@ -171,7 +171,7 @@ const FeatureSetsPanel = ({ closePanel, createFeatureSetSuccess, project }) => { } return createPortal( - {}}> + {}}> {formState => { return ( <> @@ -195,7 +195,7 @@ const FeatureSetsPanel = ({ closePanel, createFeatureSetSuccess, project }) => { { - const areLabelsValid = formRef.current?.getFieldState?.('labels')?.valid ?? true + const areLabelsValid = form?.getFieldState?.('labels')?.valid ?? true setValidation(prevState => { if (prevState.areLabelsValid === areLabelsValid) { return prevState diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStore.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStore.jsx index a8ed0bec34..8afe73cdc0 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStore.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelTargetStore/FeatureSetsPanelTargetStore.jsx @@ -92,37 +92,39 @@ const FeatureSetsPanelTargetStore = ({ ) useEffect(() => { - if (!targetsPathEditData.online.isModified && !targetsPathEditData.online.isEditMode) { - setData(state => ({ - ...state, - online: { - ...state.online, - path: generatePath( - frontendSpec.feature_store_data_prefixes, - project, - state.online.kind, - featureStore.newFeatureSet.metadata.name, - '' - ) - } - })) - } + queueMicrotask(() => { + if (!targetsPathEditData.online.isModified && !targetsPathEditData.online.isEditMode) { + setData(state => ({ + ...state, + online: { + ...state.online, + path: generatePath( + frontendSpec.feature_store_data_prefixes, + project, + state.online.kind, + featureStore.newFeatureSet.metadata.name, + '' + ) + } + })) + } - if (!targetsPathEditData.parquet.isModified && !targetsPathEditData.parquet.isEditMode) { - setData(state => ({ - ...state, - parquet: { - ...state.parquet, - path: generatePath( - frontendSpec.feature_store_data_prefixes, - project, - PARQUET, - featureStore.newFeatureSet.metadata.name, - state.parquet?.partitioned ? '' : PARQUET - ) - } - })) - } + if (!targetsPathEditData.parquet.isModified && !targetsPathEditData.parquet.isEditMode) { + setData(state => ({ + ...state, + parquet: { + ...state.parquet, + path: generatePath( + frontendSpec.feature_store_data_prefixes, + project, + PARQUET, + featureStore.newFeatureSet.metadata.name, + state.parquet?.partitioned ? '' : PARQUET + ) + } + })) + } + }) }, [ featureStore.newFeatureSet.metadata.name, featureStore.newFeatureSet.spec.source.kind, @@ -207,29 +209,31 @@ const FeatureSetsPanelTargetStore = ({ ]) useEffect(() => { - if (isEmpty(frontendSpec.feature_store_data_prefixes)) { - setTargetsPathEditData(state => ({ - ...state, - [PARQUET]: { - ...state[PARQUET], - isEditMode: true - }, - [ONLINE]: { - ...state[ONLINE], - isEditMode: true - } - })) - setDisableButtons(state => ({ - ...state, - isOfflineTargetPathEditModeClosed: false, - isOnlineTargetPathEditModeClosed: false - })) - setValidation(state => ({ - ...state, - isOfflineTargetPathValid: false, - isOnlineTargetPathValid: false - })) - } + queueMicrotask(() => { + if (isEmpty(frontendSpec.feature_store_data_prefixes)) { + setTargetsPathEditData(state => ({ + ...state, + [PARQUET]: { + ...state[PARQUET], + isEditMode: true + }, + [ONLINE]: { + ...state[ONLINE], + isEditMode: true + } + })) + setDisableButtons(state => ({ + ...state, + isOfflineTargetPathEditModeClosed: false, + isOnlineTargetPathEditModeClosed: false + })) + setValidation(state => ({ + ...state, + isOfflineTargetPathValid: false, + isOnlineTargetPathValid: false + })) + } + }) }, [frontendSpec.feature_store_data_prefixes, setDisableButtons, setValidation]) useEffect(() => { @@ -674,56 +678,58 @@ const FeatureSetsPanelTargetStore = ({ ]) useEffect(() => { - if (featureStore.newFeatureSet.spec.passthrough && !passthroughtEnabled) { - setPreviousTargets({ - data: { - ...data, - [PARQUET]: { - ...data[PARQUET], - path: data[PARQUET].path ?? offlineTarget.path - }, - [ONLINE]: { - ...data[ONLINE], - path: data[ONLINE].path ?? onlineTarget.path - } - }, - featureSetTargets: featureStore.newFeatureSet.spec.targets, - selectedPartitionKind, - selectedTargetKind, - partitionRadioButtonsState - }) - - setPassThrouthEnabled(true) - - if (selectedTargetKind.includes(ONLINE)) { - openPopUp(ConfirmDialog, { - confirmButton: { - label: 'Unset online-target', - variant: PRIMARY_BUTTON, - handler: () => { - clearTargets(false) - } - }, - cancelButton: { - label: 'Keep online-target set', - variant: TERTIARY_BUTTON, - handler: () => { - clearTargets(true) + queueMicrotask(() => { + if (featureStore.newFeatureSet.spec.passthrough && !passthroughtEnabled) { + setPreviousTargets({ + data: { + ...data, + [PARQUET]: { + ...data[PARQUET], + path: data[PARQUET].path ?? offlineTarget.path + }, + [ONLINE]: { + ...data[ONLINE], + path: data[ONLINE].path ?? onlineTarget.path } }, - closePopUp: () => { - dispatch(setNewFeatureSetPassthrough(false)) - }, - message: - 'Passthrough set to "enabled" while online-target is set. Do you want to unset online-target?' + featureSetTargets: featureStore.newFeatureSet.spec.targets, + selectedPartitionKind, + selectedTargetKind, + partitionRadioButtonsState }) - } else { - clearTargets(false) + + setPassThrouthEnabled(true) + + if (selectedTargetKind.includes(ONLINE)) { + openPopUp(ConfirmDialog, { + confirmButton: { + label: 'Unset online-target', + variant: PRIMARY_BUTTON, + handler: () => { + clearTargets(false) + } + }, + cancelButton: { + label: 'Keep online-target set', + variant: TERTIARY_BUTTON, + handler: () => { + clearTargets(true) + } + }, + closePopUp: () => { + dispatch(setNewFeatureSetPassthrough(false)) + }, + message: + 'Passthrough set to "enabled" while online-target is set. Do you want to unset online-target?' + }) + } else { + clearTargets(false) + } + } else if (!featureStore.newFeatureSet.spec.passthrough && passthroughtEnabled) { + restoreTargets() + setPassThrouthEnabled(false) } - } else if (!featureStore.newFeatureSet.spec.passthrough && passthroughtEnabled) { - restoreTargets() - setPassThrouthEnabled(false) - } + }) }, [ clearTargets, data, diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelTitle/FeatureSetsPanelTitle.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanelTitle/FeatureSetsPanelTitle.jsx index 63ce585c5d..f19114c299 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelTitle/FeatureSetsPanelTitle.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelTitle/FeatureSetsPanelTitle.jsx @@ -62,10 +62,12 @@ const FeatureSetsPanelTitle = ({ useEffect(() => { if (featureStore.newFeatureSet.spec.passthrough !== Boolean(data.passthrough)) { - setData(state => ({ - ...state, - passthrough: featureStore.newFeatureSet.spec.passthrough ? 'passthrough' : '' - })) + queueMicrotask(() => { + setData(state => ({ + ...state, + passthrough: featureStore.newFeatureSet.spec.passthrough ? 'passthrough' : '' + })) + }) } }, [data.passthrough, featureStore.newFeatureSet.spec.passthrough]) diff --git a/src/components/FilterMenuModal/FilterMenuModal.jsx b/src/components/FilterMenuModal/FilterMenuModal.jsx index fce14451d9..9c8325cc3b 100644 --- a/src/components/FilterMenuModal/FilterMenuModal.jsx +++ b/src/components/FilterMenuModal/FilterMenuModal.jsx @@ -52,14 +52,14 @@ const FilterMenuModal = ({ wizardClassName = '' }) => { const [filtersWizardIsShown, setFiltersWizardIsShown] = useState(false) - const filtersIconButtonRef = useRef() - const dispatch = useDispatch() - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ onSubmit: () => {}, initialValues }) - ) + }) + const filtersIconButtonRef = useRef() + const dispatch = useDispatch() const filtersIconClassnames = classnames( 'filters-button', !isEqual(values, initialValues) && 'filters-button_applied' @@ -68,14 +68,14 @@ const FilterMenuModal = ({ const filtersWizardClassnames = classnames('filters-wizard', wizardClassName) useEffect(() => { - if (!isEqual(formRef.current?.getState().values, values)) { - formRef.current?.batch(() => { + if (!isEqual(form.getState().values, values)) { + form.batch(() => { for (const filterName in values) { - formRef.current?.change(filterName, values[filterName]) + form.change(filterName, values[filterName]) } }) } - }, [values]) + }, [form, values]) const hideFiltersWizard = useCallback(event => { if ( @@ -102,8 +102,8 @@ const FilterMenuModal = ({ }, [hideFiltersWizard]) useLayoutEffect(() => { - formRef.current.reset(initialValues) - }, [initialValues]) + form.reset(initialValues) + }, [form, initialValues]) const getFilterCounter = formState => { const initialValuesLocal = applyChanges ? initialValues : formState.initialValues @@ -144,7 +144,7 @@ const FilterMenuModal = ({ } if (actionCanBePerformed) { - formRef.current.restart(initialValues) + form.restart(initialValues) setFiltersWizardIsShown(false) if (counter > 0) { @@ -164,7 +164,7 @@ const FilterMenuModal = ({ } return ( - {}}> + {}}> {formState => { const counter = getFilterCounter(formState) return ( diff --git a/src/components/FunctionsPanel/FunctionsPanel.jsx b/src/components/FunctionsPanel/FunctionsPanel.jsx index a6de059def..03bc6da589 100644 --- a/src/components/FunctionsPanel/FunctionsPanel.jsx +++ b/src/components/FunctionsPanel/FunctionsPanel.jsx @@ -90,15 +90,15 @@ const FunctionsPanel = ({ ) const params = useParams() const navigate = useNavigate() - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ initialValues: { labels: parseChipsData(defaultData?.labels || {}, frontendSpec.internal_labels) }, mutators: { ...arrayMutators, setFieldState }, onSubmit: () => {} }) - ) + }) const dispatch = useDispatch() const functionsStore = useSelector(store => store.functionsStore) const appStore = useSelector(store => store.appStore) @@ -306,7 +306,7 @@ const FunctionsPanel = ({ } return createPortal( - {}}> + {}}> {formState => { return ( <> diff --git a/src/components/JobWizard/JobWizard.jsx b/src/components/JobWizard/JobWizard.jsx index 5025bc91f8..82d4005754 100644 --- a/src/components/JobWizard/JobWizard.jsx +++ b/src/components/JobWizard/JobWizard.jsx @@ -95,13 +95,13 @@ const JobWizard = ({ prePopulatedData = {}, wizardTitle = 'Batch run' }) => { - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ onSubmit: () => {}, mutators: { ...arrayMutators, setFieldState }, initialValues: {} }) - ) + }) const isEditMode = useMemo(() => mode === PANEL_EDIT_MODE || mode === PANEL_RERUN_MODE, [mode]) const isRunMode = useMemo(() => mode === PANEL_FUNCTION_CREATE_MODE, [mode]) const projectIsLoading = useSelector(store => store.projectStore.project.loading) @@ -134,7 +134,7 @@ const JobWizard = ({ onWizardClose && onWizardClose() }, [dispatch, onResolve, onWizardClose, showSchedule]) - const { handleCloseModal, resolveModal } = useModalBlockHistory(closeModal, formRef.current) + const { handleCloseModal, resolveModal } = useModalBlockHistory(closeModal, form) useEffect(() => { if (!isEditMode) { @@ -188,9 +188,11 @@ const JobWizard = ({ useEffect(() => { if (!isEmpty(jobsStore.jobFunc)) { - setSelectedFunctionData({ - name: jobsStore.jobFunc.metadata.name, - functions: [jobsStore.jobFunc] + queueMicrotask(() => { + setSelectedFunctionData({ + name: jobsStore.jobFunc.metadata.name, + functions: [jobsStore.jobFunc] + }) }) } }, [isEditMode, isRunMode, jobsStore.jobFunc]) @@ -467,7 +469,7 @@ const JobWizard = ({ ) return ( - {}}> + {}}> {formState => { formStateRef.current = formState diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx index 086d8601b6..f454b85256 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.jsx @@ -297,7 +297,7 @@ const JobWizardFunctionSelection = ({ .catch(() => { setFunctions([]) }) - + //TODO: formState.initialValues[FUNCTION_SELECTION_STEP].projectName = currentValue } diff --git a/src/components/Jobs/Jobs.jsx b/src/components/Jobs/Jobs.jsx index 80feb7b0ca..bf4a916c07 100644 --- a/src/components/Jobs/Jobs.jsx +++ b/src/components/Jobs/Jobs.jsx @@ -162,13 +162,15 @@ const Jobs = () => { }, [getWorkflows, handleRefreshJobs, initialTabData, refreshScheduled]) useLayoutEffect(() => { - setSelectedTab( - location.pathname.includes(`${JOBS_PAGE_PATH}/${MONITOR_JOBS_TAB}`) - ? MONITOR_JOBS_TAB - : location.pathname.includes(`${JOBS_PAGE_PATH}/${SCHEDULE_TAB}`) - ? SCHEDULE_TAB - : MONITOR_WORKFLOWS_TAB - ) + queueMicrotask(() => { + setSelectedTab( + location.pathname.includes(`${JOBS_PAGE_PATH}/${MONITOR_JOBS_TAB}`) + ? MONITOR_JOBS_TAB + : location.pathname.includes(`${JOBS_PAGE_PATH}/${SCHEDULE_TAB}`) + ? SCHEDULE_TAB + : MONITOR_WORKFLOWS_TAB + ) + }) }, [location.pathname]) useEffect(() => { @@ -252,7 +254,9 @@ const Jobs = () => { setSearchParams={setSearchParams} tab={selectedTab} withAutoRefresh={selectedTab === MONITOR_JOBS_TAB} - withInternalAutoRefresh={Boolean(selectedTab === MONITOR_JOBS_TAB && params.jobName)} + withInternalAutoRefresh={Boolean( + selectedTab === MONITOR_JOBS_TAB && params.jobName + )} withRefreshButton withoutExpandButton > diff --git a/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.jsx b/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.jsx index 640db4dcde..cce04c73e3 100644 --- a/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.jsx +++ b/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React from 'react' +import React, { useState } from 'react' import PropTypes from 'prop-types' import arrayMutators from 'final-form-arrays' import { Form } from 'react-final-form' @@ -46,7 +46,7 @@ import { useModalBlockHistory } from '../../../hooks/useModalBlockHistory.hook' import './createProjectDialog.scss' -const CreateProjectDialog = ({ closeNewProjectPopUp, handleCreateProject, isOpen = false}) => { +const CreateProjectDialog = ({ closeNewProjectPopUp, handleCreateProject, isOpen = false }) => { const projectStore = useSelector(store => store.projectStore) const frontendSpec = useSelector(store => store.appStore.frontendSpec) const initialValues = { @@ -55,15 +55,23 @@ const CreateProjectDialog = ({ closeNewProjectPopUp, handleCreateProject, isOpen labels: [] } - const formRef = React.useRef( - createForm({ + // const formRef = React.useRef( + // createForm({ + // initialValues, + // mutators: { ...arrayMutators, setFieldState }, + // onSubmit: handleCreateProject + // }) + // ) + + const [form] = useState(() => { + return createForm({ initialValues, mutators: { ...arrayMutators, setFieldState }, onSubmit: handleCreateProject }) - ) + }) const dispatch = useDispatch() - const { handleCloseModal } = useModalBlockHistory(closeNewProjectPopUp, formRef.current) + const { handleCloseModal } = useModalBlockHistory(closeNewProjectPopUp, form) return ( {projectStore.loading && } - + {formState => { return ( <> diff --git a/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx b/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx index da496174e5..83f52772c6 100644 --- a/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx +++ b/src/components/RegisterArtifactModal/RegisterArtifactModal.jsx @@ -70,16 +70,17 @@ const RegisterArtifactModal = ({ } } } - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ initialValues, mutators: { ...arrayMutators, setFieldState }, onSubmit: () => {} }) - ) + }) + const location = useLocation() const dispatch = useDispatch() - const { handleCloseModal, resolveModal } = useModalBlockHistory(onResolve, formRef.current) + const { handleCloseModal, resolveModal } = useModalBlockHistory(onResolve, form) const messagesByKind = useMemo(() => { return createArtifactMessages[artifactKind.toLowerCase()] }, [artifactKind]) @@ -136,7 +137,7 @@ const RegisterArtifactModal = ({ }, onErrorCallback: resolveModal, showLoader: () => setIsLoading(true), - hideLoader: () => setIsLoading(false), + hideLoader: () => setIsLoading(false) }) } @@ -160,30 +161,30 @@ const RegisterArtifactModal = ({ } return ( - + {formState => { return ( <> - {isLoading && } - - - + {isLoading && } + + + ) }} diff --git a/src/elements/DeleteArtifactPopUp/DeleteArtifactPopUp.jsx b/src/elements/DeleteArtifactPopUp/DeleteArtifactPopUp.jsx index f61c13ca67..44f674bfed 100644 --- a/src/elements/DeleteArtifactPopUp/DeleteArtifactPopUp.jsx +++ b/src/elements/DeleteArtifactPopUp/DeleteArtifactPopUp.jsx @@ -52,10 +52,8 @@ const DeleteArtifactPopUp = ({ }) => { const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(true) const [disableConfirmButton, setDisableConfirmButton] = useState(false) - const dispatch = useDispatch() - const params = useParams() - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ initialValues: { deletion_strategy: 'metadata-only', extended_deletion_strategy: false, @@ -64,7 +62,9 @@ const DeleteArtifactPopUp = ({ mutators: { ...arrayMutators, setFieldState }, onSubmit: () => {} }) - ) + }) + const dispatch = useDispatch() + const params = useParams() const handleCancel = () => { setIsConfirmDialogOpen(false) @@ -73,7 +73,7 @@ const DeleteArtifactPopUp = ({ const handleDelete = useCallback(() => { const secrets = {} - formRef.current.getState().values.secrets.forEach(secret => { + form.getState().values.secrets.forEach(secret => { secrets[secret.data.key] = secret.data.value }) @@ -88,28 +88,29 @@ const DeleteArtifactPopUp = ({ artifactType, category, false, - formRef.current.getState().values.deletion_strategy, + form.getState().values.deletion_strategy, secrets ).then(() => { setIsConfirmDialogOpen(false) }) }, [ + form, + dispatch, + params.projectName, artifact.db_key, artifact.uid, - artifactType, - category, - dispatch, - filters, refreshArtifacts, refreshAfterDeleteCallback, - params.projectName + filters, + artifactType, + category ]) const toggleExtendedDeletionStrategy = value => { - formRef.current.change('deletion_strategy', value ? '' : 'metadata-only') + form.change('deletion_strategy', value ? '' : 'metadata-only') - if (formRef.current.getState().values.secrets.length > 0) { - formRef.current.change('secrets', []) + if (form.getState().values.secrets.length > 0) { + form.change('secrets', []) } setDisableConfirmButton(value) @@ -138,7 +139,7 @@ const DeleteArtifactPopUp = ({ isOpen={Boolean(isConfirmDialogOpen)} message={`Are you sure you want to delete the ${artifactType} "${artifact.db_key}" metadata? Deleted metadata can not be restored.`} > - {}}> + {}}> {formState => { const extended_deletion_strategy = formState.values.extended_deletion_strategy diff --git a/src/elements/DetailsInfoItemChip/DetailsInfoItemChip.jsx b/src/elements/DetailsInfoItemChip/DetailsInfoItemChip.jsx index 2532afb5ff..29f422fb7a 100644 --- a/src/elements/DetailsInfoItemChip/DetailsInfoItemChip.jsx +++ b/src/elements/DetailsInfoItemChip/DetailsInfoItemChip.jsx @@ -76,15 +76,15 @@ const DetailsInfoItemChip = ({ handleFinishEdit(item.fieldData.name) } }, [ + commonDetailsStore.changes.data, currentField, detailsInfoDispatch, - commonDetailsStore.changes.data, dispatch, formState.form, formState.values, handleFinishEdit, isFieldInEditMode, - item?.editModeType, + item.editModeType, item.fieldData.name ]) diff --git a/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx b/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx index 4bbb0a7933..e28b7a5a1f 100644 --- a/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx +++ b/src/elements/DetailsPopUp/ArtifactPopUp/ArtifactPopUp.jsx @@ -207,7 +207,9 @@ const ArtifactPopUp = ({ artifactData, isOpen, onResolve }) => { useEffect(() => { if (isEmpty(selectedArtifact)) { - fetchArtifact() + queueMicrotask(() => { + fetchArtifact() + }) } }, [fetchArtifact, selectedArtifact]) diff --git a/src/elements/DetailsPopUp/FeatureSetPopUp/FeatureSetPopUp.jsx b/src/elements/DetailsPopUp/FeatureSetPopUp/FeatureSetPopUp.jsx index 7a0826247c..8e8e485826 100644 --- a/src/elements/DetailsPopUp/FeatureSetPopUp/FeatureSetPopUp.jsx +++ b/src/elements/DetailsPopUp/FeatureSetPopUp/FeatureSetPopUp.jsx @@ -82,7 +82,9 @@ const FeatureSetPopUp = ({ featureSetData, isOpen, onResolve }) => { useEffect(() => { if (isEmpty(selectedFeatureSet)) { - fetchFeatureSetData() + queueMicrotask(() => { + fetchFeatureSetData() + }) } }, [fetchFeatureSetData, selectedFeatureSet]) diff --git a/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx b/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx index 7559c04f65..45f67380d0 100644 --- a/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx +++ b/src/elements/DetailsPopUp/FeatureVectorPopUp/FeatureVectorPopUp.jsx @@ -92,7 +92,9 @@ const FeatureVectorPopUp = ({ featureVectorData, isOpen, onResolve }) => { useEffect(() => { if (isEmpty(selectedFeatureVector)) { - fetchFeatureVector() + queueMicrotask(() => { + fetchFeatureVector() + }) } }, [fetchFeatureVector, selectedFeatureVector]) diff --git a/src/elements/DetailsPopUp/FunctionPopUp/FunctionPopUp.jsx b/src/elements/DetailsPopUp/FunctionPopUp/FunctionPopUp.jsx index 9a2314f217..d0357de0bd 100644 --- a/src/elements/DetailsPopUp/FunctionPopUp/FunctionPopUp.jsx +++ b/src/elements/DetailsPopUp/FunctionPopUp/FunctionPopUp.jsx @@ -43,6 +43,7 @@ const FunctionPopUp = ({ funcTag = '', funcUri = null, isOpen, onResolve }) => { const { isDemoMode, isStagingMode } = useMode() const [isLoading, setIsLoading] = useState(true) const [selectedFunction, setSelectedFunction] = useState({}) + const [pageData, setPageData] = useState({}) const fetchFunctionLogsTimeout = useRef(null) const fetchFunctionNuclioLogsTimeout = useRef(null) const toggleConvertedYaml = useCallback( @@ -100,8 +101,8 @@ const FunctionPopUp = ({ funcTag = '', funcUri = null, isOpen, onResolve }) => { [dispatch, isDemoMode, isStagingMode, toggleConvertedYaml, selectedFunction, fetchFunction] ) - const pageData = useMemo( - () => + useEffect(() => { + setPageData( generateFunctionsPageData( dispatch, selectedFunction, @@ -109,13 +110,15 @@ const FunctionPopUp = ({ funcTag = '', funcUri = null, isOpen, onResolve }) => { fetchFunctionNuclioLogsTimeout, navigate, fetchFunction - ), - [dispatch, fetchFunction, navigate, selectedFunction] - ) + ) + ) + }, [dispatch, fetchFunction, navigate, selectedFunction]) useEffect(() => { if (isEmpty(selectedFunction)) { - fetchFunction() + queueMicrotask(() => { + fetchFunction() + }) } }, [fetchFunction, selectedFunction]) diff --git a/src/elements/DetailsPopUp/JobPopUp/JobPopUp.jsx b/src/elements/DetailsPopUp/JobPopUp/JobPopUp.jsx index f3798b26ec..727764aef4 100644 --- a/src/elements/DetailsPopUp/JobPopUp/JobPopUp.jsx +++ b/src/elements/DetailsPopUp/JobPopUp/JobPopUp.jsx @@ -125,7 +125,9 @@ const JobPopUp = ({ isOpen, jobData, onResolve }) => { useEffect(() => { if (isEmpty(selectedJob)) { - handleFetchJob() + queueMicrotask(() => { + handleFetchJob() + }) } }, [handleFetchJob, selectedJob]) diff --git a/src/elements/FormDataInputsTable/FormDataInputsRow/FormDataInputsRow.jsx b/src/elements/FormDataInputsTable/FormDataInputsRow/FormDataInputsRow.jsx index fc6dba1831..3c5300e645 100644 --- a/src/elements/FormDataInputsTable/FormDataInputsRow/FormDataInputsRow.jsx +++ b/src/elements/FormDataInputsTable/FormDataInputsRow/FormDataInputsRow.jsx @@ -66,7 +66,9 @@ const FormDataInputsRow = ({ const [fieldData, setFieldData] = useState(fields.value[index]) useEffect(() => { - setFieldData(fields.value[index]) + queueMicrotask(() => { + setFieldData(fields.value[index]) + }) }, [fields.value, index]) const isRowDisabled = () => { diff --git a/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx b/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx index 5a90803056..95acb1e88d 100644 --- a/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx +++ b/src/elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesRow/FormEnvironmentVariablesRow.jsx @@ -71,7 +71,9 @@ const FormEnvironmentVariablesRow = ({ ) useEffect(() => { - setFieldData(fields.value[index]) + queueMicrotask(() => { + setFieldData(fields.value[index]) + }) }, [fields.value, index]) const handleTypeChange = useCallback( diff --git a/src/elements/FormParametersTable/FormParametersRow/FormParametersRow.jsx b/src/elements/FormParametersTable/FormParametersRow/FormParametersRow.jsx index efde4d0717..ca54492856 100644 --- a/src/elements/FormParametersTable/FormParametersRow/FormParametersRow.jsx +++ b/src/elements/FormParametersTable/FormParametersRow/FormParametersRow.jsx @@ -265,7 +265,9 @@ const FormParametersRow = ({ } useEffect(() => { - setFieldData(fields.value[index]) + queueMicrotask(() => { + setFieldData(fields.value[index]) + }) }, [fields.value, index]) return ( diff --git a/src/elements/FormVolumesTable/FormVolumesRow/FormVolumesRow.jsx b/src/elements/FormVolumesTable/FormVolumesRow/FormVolumesRow.jsx index 60b35d3097..bfbe02bb52 100644 --- a/src/elements/FormVolumesTable/FormVolumesRow/FormVolumesRow.jsx +++ b/src/elements/FormVolumesTable/FormVolumesRow/FormVolumesRow.jsx @@ -68,10 +68,12 @@ const FormVolumesRow = ({ ) useLayoutEffect(() => { - setFieldRowData( - generateVolumeInputsData(fields.value[index], fields, editingItem, accessKeyFocusHandler) - ) - setFieldData(fields.value[index]) + queueMicrotask(() => { + setFieldRowData( + generateVolumeInputsData(fields.value[index], fields, editingItem, accessKeyFocusHandler) + ) + setFieldData(fields.value[index]) + }) }, [accessKeyFocusHandler, editingItem, fields, index]) const handleTypeChange = useCallback(() => { diff --git a/src/elements/FunctionsPanelCode/FunctionsPanelCode.jsx b/src/elements/FunctionsPanelCode/FunctionsPanelCode.jsx index 0086b98760..7b01c64bf0 100644 --- a/src/elements/FunctionsPanelCode/FunctionsPanelCode.jsx +++ b/src/elements/FunctionsPanelCode/FunctionsPanelCode.jsx @@ -93,11 +93,15 @@ const FunctionsPanelCode = ({ ) ) setImageType(EXISTING_IMAGE) - setData(state => ({ - ...state, - image: - appStore.frontendSpec?.default_function_image_by_kind?.[functionsStore.newFunction.kind] - })) + queueMicrotask(() => { + setData(state => ({ + ...state, + image: + appStore.frontendSpec?.default_function_image_by_kind?.[ + functionsStore.newFunction.kind + ] + })) + }) } else { const buildImage = (appStore.frontendSpec?.function_deployment_target_image_template || '') .replace('{project}', params.projectName) @@ -118,15 +122,17 @@ const FunctionsPanelCode = ({ ) ) dispatch(setNewFunctionBuildImage(buildImage)) - setData(state => ({ - ...state, - requirements: appStore.frontendSpec?.function_deployment_mlrun_requirement ?? '', - base_image: - appStore.frontendSpec?.default_function_image_by_kind?.[ - functionsStore.newFunction.kind - ] ?? '', - build_image: buildImage - })) + queueMicrotask(() => { + setData(state => ({ + ...state, + requirements: appStore.frontendSpec?.function_deployment_mlrun_requirement ?? '', + base_image: + appStore.frontendSpec?.default_function_image_by_kind?.[ + functionsStore.newFunction.kind + ] ?? '', + build_image: buildImage + })) + }) } } else if ( (defaultData.image?.length > 0 || @@ -138,10 +144,12 @@ const FunctionsPanelCode = ({ ) { dispatch(setNewFunctionImage(defaultData.image || DEFAULT_IMAGE)) setImageType(EXISTING_IMAGE) - setData(state => ({ - ...state, - image: defaultData.image || DEFAULT_IMAGE - })) + queueMicrotask(() => { + setData(state => ({ + ...state, + image: defaultData.image || DEFAULT_IMAGE + })) + }) } else if (imageType.length === 0) { setImageType(NEW_IMAGE) } diff --git a/src/elements/FunctionsPanelEnvironmentVariables/FunctionsPanelEnvironmentVariables.jsx b/src/elements/FunctionsPanelEnvironmentVariables/FunctionsPanelEnvironmentVariables.jsx index 8db17fc58d..015f7c413e 100644 --- a/src/elements/FunctionsPanelEnvironmentVariables/FunctionsPanelEnvironmentVariables.jsx +++ b/src/elements/FunctionsPanelEnvironmentVariables/FunctionsPanelEnvironmentVariables.jsx @@ -34,7 +34,9 @@ const FunctionsPanelEnvironmentVariables = () => { const functionsStore = useSelector(store => store.functionsStore) useEffect(() => { - setEnvVariables(parseEnvVariables(functionsStore.newFunction.spec.env)) + queueMicrotask(() => { + setEnvVariables(parseEnvVariables(functionsStore.newFunction.spec.env)) + }) }, [functionsStore.newFunction.spec.env]) const handleAddNewEnv = env => { diff --git a/src/elements/MetricsSelector/MetricsSelector.jsx b/src/elements/MetricsSelector/MetricsSelector.jsx index 2ac8fdd30c..7342df448f 100644 --- a/src/elements/MetricsSelector/MetricsSelector.jsx +++ b/src/elements/MetricsSelector/MetricsSelector.jsx @@ -61,9 +61,8 @@ const MetricsSelector = ({ const [nameFilter, setNameFilter] = useState('') const [isOpen, setIsOpen] = useState(false) const [appliedMetrics, setAppliedMetrics] = useState([]) - const selectorFieldRef = useRef() - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ initialValues: { metrics: [], metricSearchName: '' @@ -71,7 +70,8 @@ const MetricsSelector = ({ mutators: { ...arrayMutators }, onSubmit: () => {} }) - ) + }) + const selectorFieldRef = useRef() const generatedMetrics = useMemo(() => { return groupMetricByApplication(metrics) @@ -97,26 +97,30 @@ const MetricsSelector = ({ useEffect(() => { if (!isOpen) { - formRef.current?.batch(() => { - formRef.current.change( + form.batch(() => { + form.change( 'metrics', appliedMetrics.map(metricItem => metricItem.full_name) ) - formRef.current.change('metricSearchName', '') + form.change('metricSearchName', '') }) - setNameFilter('') + queueMicrotask(() => { + setNameFilter('') + }) } - }, [appliedMetrics, isOpen]) + }, [appliedMetrics, form, isOpen]) useEffect(() => { if (preselectedMetrics) { - formRef.current.reset({ + form.reset({ metrics: preselectedMetrics.map(metricItem => metricItem.full_name) }) - setAppliedMetrics(preselectedMetrics) + queueMicrotask(() => { + setAppliedMetrics(preselectedMetrics) + }) } - }, [preselectedMetrics]) + }, [form, preselectedMetrics]) const windowClickHandler = useCallback( event => { @@ -155,7 +159,7 @@ const MetricsSelector = ({ const handleApply = () => { const newAppliedMetrics = - formRef.current?.getFieldState('metrics')?.value?.map(metricFullName => { + form.getFieldState('metrics')?.value?.map(metricFullName => { return metrics.find(metric => metric.full_name === metricFullName) }) || [] @@ -165,7 +169,7 @@ const MetricsSelector = ({ } const handleClear = () => { - formRef.current?.change('metrics', []) + form.change('metrics', []) } const getSelectValue = () => { @@ -202,7 +206,7 @@ const MetricsSelector = ({ } return ( - {}}> + {}}> {formState => ( ) : ( [ -
      +
      {counterObject.loading ? ( ) : ( @@ -95,7 +99,7 @@ const ProjectStatisticsCounter = ({ counterObject }) => {
      ,
      {counterObject.label} {counterObject.status && } diff --git a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx index 11236643e8..b99d25ae7d 100644 --- a/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/AlertsCounters.jsx @@ -51,7 +51,10 @@ const AlertsCounters = () => { } const alertsData = useMemo(() => { - const projectName = paramProjectName ? paramProjectName : '*' + const projectName = paramProjectName || '*' + const summaryData = projectStore?.projectSummary?.data + const alerts = projectStore?.jobsMonitoringData?.alerts + const defaultAlertData = { endpoint: 0, jobs: 0, @@ -60,9 +63,9 @@ const AlertsCounters = () => { } if (projectName !== '*') { - const endpoint = projectStore?.projectSummary?.data?.endpoint_alerts_count || 0 - const jobs = projectStore?.projectSummary?.data?.job_alerts_count || 0 - const application = projectStore?.projectSummary?.data?.other_alerts_count || 0 + const endpoint = summaryData?.endpoint_alerts_count || 0 + const jobs = summaryData?.job_alerts_count || 0 + const application = summaryData?.other_alerts_count || 0 return { projectName, @@ -77,15 +80,9 @@ const AlertsCounters = () => { return { projectName, - data: defaults({}, projectStore?.jobsMonitoringData?.alerts, defaultAlertData) + data: defaults({}, alerts, defaultAlertData) } - }, [ - paramProjectName, - projectStore?.jobsMonitoringData?.alerts, - projectStore?.projectSummary?.data?.endpoint_alerts_count, - projectStore?.projectSummary?.data?.job_alerts_count, - projectStore?.projectSummary?.data?.other_alerts_count - ]) + }, [paramProjectName, projectStore.projectSummary?.data, projectStore.jobsMonitoringData?.alerts]) const alertsStats = useMemo( () => generateAlertsStats(alertsData.data, navigate, alertsData.projectName), diff --git a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx index 0bb0d3e39c..3061866bed 100644 --- a/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx +++ b/src/elements/ProjectsMonitoringCounters/ScheduledJobsCounters.jsx @@ -49,10 +49,12 @@ const ScheduledJobsCounters = () => { } const scheduledData = useMemo(() => { + const summaryData = projectStore.projectSummary?.data + const scheduled = projectStore.jobsMonitoringData?.scheduled + if (projectName) { - const jobs = projectStore.projectSummary?.data?.distinct_scheduled_jobs_pending_count || 0 - const workflows = - projectStore.projectSummary?.data?.distinct_scheduled_pipelines_pending_count || 0 + const jobs = summaryData?.distinct_scheduled_jobs_pending_count || 0 + const workflows = summaryData?.distinct_scheduled_pipelines_pending_count || 0 return { jobs, @@ -60,19 +62,15 @@ const ScheduledJobsCounters = () => { total: jobs + workflows } } + return ( - projectStore?.jobsMonitoringData.scheduled || { + scheduled || { jobs: 0, workflows: 0, total: 0 } ) - }, [ - projectName, - projectStore.projectSummary?.data?.distinct_scheduled_jobs_pending_count, - projectStore.projectSummary?.data?.distinct_scheduled_pipelines_pending_count, - projectStore.jobsMonitoringData?.scheduled - ]) + }, [projectName, projectStore.projectSummary?.data, projectStore.jobsMonitoringData?.scheduled]) const scheduledStats = useMemo( () => diff --git a/src/elements/ReadOnlyChips/ReadOnlyChips.jsx b/src/elements/ReadOnlyChips/ReadOnlyChips.jsx index ee13d06ad5..fd058733f2 100644 --- a/src/elements/ReadOnlyChips/ReadOnlyChips.jsx +++ b/src/elements/ReadOnlyChips/ReadOnlyChips.jsx @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import React from 'react' +import React, { useState } from 'react' import { Form } from 'react-final-form' import { createForm } from 'final-form' import PropTypes from 'prop-types' @@ -30,16 +30,16 @@ import { setFieldState } from 'igz-controls/utils/form.util' import { CHIP_OPTIONS } from 'igz-controls/types' const ReadOnlyChips = ({ labels = [], chipOptions = getChipOptions('metrics'), ...args }) => { - const formRef = React.useRef( - createForm({ + const [form] = useState(() => { + return createForm({ initialValues: { labels: labels }, mutators: { ...arrayMutators, setFieldState }, onSubmit: () => {} }) - ) + }) return ( - {}}> + {}}> {formState => { return ( { + return createForm({ initialValues, mutators: { ...arrayMutators, setFieldState }, onSubmit: () => {} }) - ) + }) + const location = useLocation() - const { handleCloseModal, resolveModal } = useModalBlockHistory(onResolve, formRef.current) + const { handleCloseModal, resolveModal } = useModalBlockHistory(onResolve, form) const dispatch = useDispatch() const registerModel = values => { @@ -154,7 +162,7 @@ function RegisterModelModal({ actions = null, isOpen, onResolve, params, refresh } return ( - + {formState => { return ( <> diff --git a/src/elements/WorkflowsTable/WorkflowsTable.jsx b/src/elements/WorkflowsTable/WorkflowsTable.jsx index 8a69eb466c..e102d9b06c 100644 --- a/src/elements/WorkflowsTable/WorkflowsTable.jsx +++ b/src/elements/WorkflowsTable/WorkflowsTable.jsx @@ -77,548 +77,520 @@ import { useSortTable } from '../../hooks/useSortTable.hook' import './workflowsTable.scss' -const WorkflowsTable = React.forwardRef( - ( - { - backLink, - context, - filters, - filtersConfig, - getWorkflows, - itemIsSelected, - requestErrorMessage, - selectedFunction, - selectedJob, - setItemIsSelected, - setSelectedFunction, - setSelectedJob, - setWorkflowIsLoaded, - tableContent = [], - workflowIsLoaded +const WorkflowsTable = ( + { + ref: abortJobRef, + backLink, + context, + filters, + filtersConfig, + getWorkflows, + itemIsSelected, + requestErrorMessage, + selectedFunction, + selectedJob, + setItemIsSelected, + setSelectedFunction, + setSelectedJob, + setWorkflowIsLoaded, + tableContent = [], + workflowIsLoaded + } +) => { + const [dataIsLoading, setDataIsLoading] = useState(false) + const [rerunIsDisabled, setRerunIsDisabled] = useState(false) + const [workflowsViewMode, setWorkflowsViewMode] = useState(WORKFLOW_GRAPH_VIEW) + const workflowsStore = useSelector(state => state.workflowsStore) + const filtersStore = useSelector(state => state.filtersStore) + const appStore = useSelector(store => store.appStore) + const params = useParams() + const dispatch = useDispatch() + const navigate = useNavigate() + const location = useLocation() + const fetchJobFunctionsPromiseRef = useRef() + let fetchFunctionLogsTimeout = useRef(null) + const accessibleProjectsMap = useSelector(state => state.projectStore.accessibleProjectsMap) + const [permissionsLoading, setPermissionsLoading] = useState(false) + + useEffect(() => { + const projectNames = workflowsStore.workflows.data.map(workflow => workflow.project) + setPermissionsLoading(true) + projectNames && + fetchMissingProjectsPermissions(projectNames, accessibleProjectsMap, dispatch).finally( + () => { + setPermissionsLoading(false) + } + ) + }, [dispatch, workflowsStore.workflows.data, accessibleProjectsMap]) + + const monitorWorkflowsRowHeight = useMemo( + () => getScssVariableValue('--monitorWorkflowsRowHeight'), + [] + ) + const monitorWorkflowsRowHeightExtended = useMemo( + () => getScssVariableValue('--monitorWorkflowsRowHeightExtended'), + [] + ) + const monitorWorkflowsHeaderRowHeight = useMemo( + () => getScssVariableValue('--monitorWorkflowsHeaderRowHeight'), + [] + ) + + const { + editableItem, + handleMonitoring, + handleRerunJob, + jobWizardIsOpened, + jobWizardMode, + setConfirmData, + setEditableItem, + setJobWizardIsOpened, + setJobWizardMode + } = React.useContext(context) + + const { sortedTableContent } = useSortTable({ + headers: tableContent[0]?.content, + content: tableContent, + sortConfig: { defaultSortBy: 'createdat', defaultDirection: 'desc' } + }) + + const handleRetry = useCallback(() => { + getWorkflows(filters) + }, [filters, getWorkflows]) + + const handleFetchFunctionLogs = useCallback( + (item, projectName, setDetailsLogs) => { + return getFunctionLogs( + dispatch, + fetchFunctionLogsTimeout, + projectName, + item.name, + item.tag, + setDetailsLogs + ) }, - abortJobRef - ) => { - const [dataIsLoading, setDataIsLoading] = useState(false) - const [rerunIsDisabled, setRerunIsDisabled] = useState(false) - const [workflowsViewMode, setWorkflowsViewMode] = useState(WORKFLOW_GRAPH_VIEW) - const workflowsStore = useSelector(state => state.workflowsStore) - const filtersStore = useSelector(state => state.filtersStore) - const appStore = useSelector(store => store.appStore) - const params = useParams() - const dispatch = useDispatch() - const navigate = useNavigate() - const location = useLocation() - const fetchJobFunctionsPromiseRef = useRef() - let fetchFunctionLogsTimeout = useRef(null) - const accessibleProjectsMap = useSelector(state => state.projectStore.accessibleProjectsMap) - const [permissionsLoading, setPermissionsLoading] = useState(false) - - useEffect(() => { - const projectNames = workflowsStore.workflows.data.map(workflow => workflow.project) - setPermissionsLoading(true) - projectNames && - fetchMissingProjectsPermissions(projectNames, accessibleProjectsMap, dispatch).finally( - () => { - setPermissionsLoading(false) - } - ) - }, [dispatch, workflowsStore.workflows.data, accessibleProjectsMap]) - - const monitorWorkflowsRowHeight = useMemo( - () => getScssVariableValue('--monitorWorkflowsRowHeight'), - [] - ) - const monitorWorkflowsRowHeightExtended = useMemo( - () => getScssVariableValue('--monitorWorkflowsRowHeightExtended'), - [] - ) - const monitorWorkflowsHeaderRowHeight = useMemo( - () => getScssVariableValue('--monitorWorkflowsHeaderRowHeight'), - [] - ) + [fetchFunctionLogsTimeout, dispatch] + ) - const { - editableItem, - handleMonitoring, - handleRerunJob, - jobWizardIsOpened, - jobWizardMode, - setConfirmData, - setEditableItem, - setJobWizardIsOpened, - setJobWizardMode - } = React.useContext(context) - - const { sortedTableContent } = useSortTable({ - headers: tableContent[0]?.content, - content: tableContent, - sortConfig: { defaultSortBy: 'createdat', defaultDirection: 'desc' } - }) - - const handleRetry = useCallback(() => { - getWorkflows(filters) - }, [filters, getWorkflows]) - - const handleFetchFunctionLogs = useCallback( - (item, projectName, setDetailsLogs) => { - return getFunctionLogs( - dispatch, - fetchFunctionLogsTimeout, - projectName, - item.name, - item.tag, - setDetailsLogs - ) - }, - [fetchFunctionLogsTimeout, dispatch] - ) + const handleFetchJobLogs = useCallback( + (item, projectName, setDetailsLogs, streamLogsRef) => { + return getJobLogs(item.uid, projectName, streamLogsRef, setDetailsLogs, dispatch) + }, + [dispatch] + ) - const handleFetchJobLogs = useCallback( - (item, projectName, setDetailsLogs, streamLogsRef) => { - return getJobLogs(item.uid, projectName, streamLogsRef, setDetailsLogs, dispatch) - }, - [dispatch] - ) + const toggleConvertedYaml = useCallback( + data => { + return dispatch(toggleYaml(data)) + }, + [dispatch] + ) - const toggleConvertedYaml = useCallback( - data => { - return dispatch(toggleYaml(data)) - }, - [dispatch] - ) + const handleRemoveFunctionLogs = useCallback(() => { + clearTimeout(fetchFunctionLogsTimeout.current) + }, [fetchFunctionLogsTimeout]) - const handleRemoveFunctionLogs = useCallback(() => { - clearTimeout(fetchFunctionLogsTimeout.current) - }, [fetchFunctionLogsTimeout]) - - const pageData = useMemo( - () => - generatePageData( - selectedFunction, - handleFetchFunctionLogs, - handleFetchJobLogs, - handleRemoveFunctionLogs, - selectedJob - ), - [ - handleFetchJobLogs, + const pageData = useMemo( + () => + generatePageData( + selectedFunction, handleFetchFunctionLogs, + handleFetchJobLogs, handleRemoveFunctionLogs, - selectedFunction, selectedJob - ] + ), + [ + handleFetchJobLogs, + handleFetchFunctionLogs, + handleRemoveFunctionLogs, + selectedFunction, + selectedJob + ] + ) + + const refreshWorkflow = useCallback(() => { + return dispatch( + fetchWorkflow({ + project: params.workflowProjectName || params.projectName, + workflowId: params.workflowId + }) ) - - const refreshWorkflow = useCallback(() => { - return dispatch( - fetchWorkflow({ - project: params.workflowProjectName || params.projectName, - workflowId: params.workflowId - }) - ) - .unwrap() - .catch(error => { - showErrorNotification(dispatch, error, 'Failed to fetch workflow') - navigate(backLink, { - replace: true - }) + .unwrap() + .catch(error => { + showErrorNotification(dispatch, error, 'Failed to fetch workflow') + navigate(backLink, { + replace: true }) - }, [ - backLink, - dispatch, - navigate, - params.projectName, - params.workflowId, - params.workflowProjectName - ]) - - const handlePollAbortingJob = useCallback( - (jobRun, refresh) => { - if (jobRun.abortTaskId && jobRun.state.value === 'aborting') { - const abortingJob = { - [jobRun.abortTaskId]: { - uid: jobRun.uid, - name: jobRun.name - } + }) + }, [ + backLink, + dispatch, + navigate, + params.projectName, + params.workflowId, + params.workflowProjectName + ]) + + const handlePollAbortingJob = useCallback( + (jobRun, refresh) => { + if (jobRun.abortTaskId && jobRun.state.value === 'aborting') { + const abortingJob = { + [jobRun.abortTaskId]: { + uid: jobRun.uid, + name: jobRun.name } + } - pollAbortingJobs( - params.workflowProjectName || params.projectName, - abortJobRef, - abortingJob, - refresh, - dispatch - ) + pollAbortingJobs( + params.workflowProjectName || params.projectName, + abortJobRef, + abortingJob, + refresh, + dispatch + ) + } + }, + [abortJobRef, dispatch, params.projectName, params.workflowProjectName] + ) + + const modifyAndSelectRun = useCallback( + (jobRun, refresh) => { + return enrichRunWithFunctionFields(dispatch, jobRun, fetchJobFunctionsPromiseRef).then( + jobRun => { + setSelectedJob(jobRun) + setSelectedFunction({}) + setItemIsSelected(true) + + if (refresh) { + handlePollAbortingJob(jobRun, refresh) + } } - }, - [abortJobRef, dispatch, params.projectName, params.workflowProjectName] - ) + ) + }, + [dispatch, handlePollAbortingJob, setItemIsSelected, setSelectedFunction, setSelectedJob] + ) - const modifyAndSelectRun = useCallback( - (jobRun, refresh) => { - return enrichRunWithFunctionFields(dispatch, jobRun, fetchJobFunctionsPromiseRef).then( - jobRun => { - setSelectedJob(jobRun) - setSelectedFunction({}) - setItemIsSelected(true) + const findSelectedWorkflowJob = useCallback(() => { + if (workflowsStore.activeWorkflow?.data) { + const workflow = { ...workflowsStore.activeWorkflow.data } - if (refresh) { - handlePollAbortingJob(jobRun, refresh) - } + return find( + workflow.graph, + workflowItem => workflowItem.run_type === 'run' && workflowItem.run_uid === params.jobId + ) + } + }, [params.jobId, workflowsStore.activeWorkflow.data]) + + const getPipelineError = useCallback( + isErrorState => { + return isErrorState && + workflowsStore.activeWorkflow?.data?.run?.error && + workflowsStore.activeWorkflow.data.run.error !== 'None' + ? { + title: 'Pipeline error - ', + message: workflowsStore.activeWorkflow.data.run.error } - ) - }, - [dispatch, handlePollAbortingJob, setItemIsSelected, setSelectedFunction, setSelectedJob] - ) - - const findSelectedWorkflowJob = useCallback(() => { - if (workflowsStore.activeWorkflow?.data) { - const workflow = { ...workflowsStore.activeWorkflow.data } + : {} + }, + [workflowsStore.activeWorkflow.data] + ) - return find( - workflow.graph, - workflowItem => workflowItem.run_type === 'run' && workflowItem.run_uid === params.jobId - ) - } - }, [params.jobId, workflowsStore.activeWorkflow.data]) - - const getPipelineError = useCallback( - isErrorState => { - return isErrorState && - workflowsStore.activeWorkflow?.data?.run?.error && - workflowsStore.activeWorkflow.data.run.error !== 'None' - ? { - title: 'Pipeline error - ', - message: workflowsStore.activeWorkflow.data.run.error - } - : {} - }, - [workflowsStore.activeWorkflow.data] + const fetchRun = useCallback(() => { + return dispatch( + fetchJob({ project: params.workflowProjectName || params.projectName, jobId: params.jobId }) ) - - const fetchRun = useCallback(() => { - return dispatch( - fetchJob({ project: params.workflowProjectName || params.projectName, jobId: params.jobId }) - ) - .unwrap() - .then(job => { - const selectedJob = findSelectedWorkflowJob() - const graphJobState = selectedJob?.phase?.toLowerCase() - const isErrorState = [FAILED_STATE, ERROR_STATE].includes(graphJobState) - const customJobState = isErrorState ? graphJobState : '' - - return modifyAndSelectRun( - parseJob(job, MONITOR_WORKFLOWS_TAB, customJobState, getPipelineError(isErrorState)), - fetchRun - ) - }) - .catch(() => - navigate(backLink, { - replace: true - }) + .unwrap() + .then(job => { + const selectedJob = findSelectedWorkflowJob() + const graphJobState = selectedJob?.phase?.toLowerCase() + const isErrorState = [FAILED_STATE, ERROR_STATE].includes(graphJobState) + const customJobState = isErrorState ? graphJobState : '' + + return modifyAndSelectRun( + parseJob(job, MONITOR_WORKFLOWS_TAB, customJobState, getPipelineError(isErrorState)), + fetchRun ) - .finally(() => { - fetchJobFunctionsPromiseRef.current = null + }) + .catch(() => + navigate(backLink, { + replace: true }) - }, [ - backLink, - dispatch, - findSelectedWorkflowJob, - modifyAndSelectRun, - navigate, - params.jobId, - params.projectName, - params.workflowProjectName, - getPipelineError - ]) - - const setJobStatusAborting = useCallback( - task => { - setSelectedJob(state => ({ - ...state, - abortTaskId: task, - state: getState('aborting', JOBS_PAGE, JOB_KIND_JOB) - })) - }, - [setSelectedJob] - ) + ) + .finally(() => { + fetchJobFunctionsPromiseRef.current = null + }) + }, [ + backLink, + dispatch, + findSelectedWorkflowJob, + modifyAndSelectRun, + navigate, + params.jobId, + params.projectName, + params.workflowProjectName, + getPipelineError + ]) + + const setJobStatusAborting = useCallback( + task => { + setSelectedJob(state => ({ + ...state, + abortTaskId: task, + state: getState('aborting', JOBS_PAGE, JOB_KIND_JOB) + })) + }, + [setSelectedJob] + ) + + const onAbortJob = useCallback( + job => { + const refresh = () => { + refreshWorkflow() + fetchRun() + } - const onAbortJob = useCallback( - job => { - const refresh = () => { - refreshWorkflow() - fetchRun() + handleAbortJob( + job, + setNotification, + refresh, + setConfirmData, + dispatch, + abortJobRef, + setJobStatusAborting + ) + }, + [abortJobRef, dispatch, fetchRun, refreshWorkflow, setConfirmData, setJobStatusAborting] + ) + + const handleConfirmAbortJob = useCallback( + job => { + setConfirmData({ + item: job, + header: 'Abort job?', + message: ( +
      + Are you sure you want to abort the job "{job.name}"?
      + {isJobKindLocal(job) && + 'This is a local run. You can abort the run, though the actual process will continue.'} +
      + ), + btnConfirmLabel: 'Abort', + btnConfirmType: DANGER_BUTTON, + rejectHandler: () => { + setConfirmData(null) + }, + confirmHandler: () => { + onAbortJob(job) + setConfirmData(null) } + }) + }, + [onAbortJob, setConfirmData] + ) - handleAbortJob( - job, - setNotification, - refresh, - setConfirmData, - dispatch, - abortJobRef, - setJobStatusAborting + const onTerminateWorkflow = useCallback( + job => { + handleTerminateWorkflow(job, dispatch) + }, + [dispatch] + ) + + const onDeleteJob = useCallback( + job => { + handleDeleteJob(false, job, refreshWorkflow, null, filters, dispatch).then(() => { + navigate( + location.pathname + .split('/') + .splice(0, location.pathname.split('/').indexOf(params.workflowId) + 1) + .join('/') + window.location.search ) - }, - [abortJobRef, dispatch, fetchRun, refreshWorkflow, setConfirmData, setJobStatusAborting] - ) + }) + }, + [dispatch, filters, location.pathname, navigate, params.workflowId, refreshWorkflow] + ) + + const handleConfirmDeleteJob = useCallback( + job => { + setConfirmData({ + item: job, + header: 'Delete job?', + message: `Are you sure you want to delete the job "${job.name}"? Deleted jobs can not be restored.`, + btnConfirmLabel: 'Delete', + btnConfirmType: DANGER_BUTTON, + rejectHandler: () => { + setConfirmData(null) + }, + confirmHandler: () => { + onDeleteJob(job) + setConfirmData(null) + } + }) + }, + [onDeleteJob, setConfirmData] + ) + + const handleConfirmTerminateWorkflow = useCallback( + job => { + setConfirmData({ + item: job, + header: 'Terminate workflow', + message: `Are you sure you want to terminate the workflow "${job.name}" (stop its execution)? Workflows termination cannot be undone.`, + btnConfirmLabel: 'Terminate', + btnConfirmType: DANGER_BUTTON, + rejectHandler: () => { + setConfirmData(null) + }, + confirmHandler: () => { + onTerminateWorkflow(job) + setConfirmData(null) + } + }) + }, + [onTerminateWorkflow, setConfirmData] + ) - const handleConfirmAbortJob = useCallback( - job => { - setConfirmData({ - item: job, - header: 'Abort job?', - message: ( -
      - Are you sure you want to abort the job "{job.name}"?
      - {isJobKindLocal(job) && - 'This is a local run. You can abort the run, though the actual process will continue.'} -
      - ), - btnConfirmLabel: 'Abort', - btnConfirmType: DANGER_BUTTON, - rejectHandler: () => { - setConfirmData(null) - }, - confirmHandler: () => { - onAbortJob(job) - setConfirmData(null) - } + const handleRerun = useCallback( + workflow => { + dispatch(rerunWorkflow({ project: workflow.project, workflowId: workflow.id })) + .unwrap() + .then(() => { + handleRetry() + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: 'Workflow run successfully.' + }) + ) }) - }, - [onAbortJob, setConfirmData] - ) - - const onTerminateWorkflow = useCallback( - job => { - handleTerminateWorkflow(job, dispatch) - }, - [dispatch] - ) - - const onDeleteJob = useCallback( - job => { - handleDeleteJob(false, job, refreshWorkflow, null, filters, dispatch).then(() => { - navigate( - location.pathname - .split('/') - .splice(0, location.pathname.split('/').indexOf(params.workflowId) + 1) - .join('/') + window.location.search + .catch(error => { + showErrorNotification(dispatch, error, 'Workflow did not run successfully', '', () => + handleRerun(workflow) ) }) - }, - [dispatch, filters, location.pathname, navigate, params.workflowId, refreshWorkflow] - ) + }, + [dispatch, handleRetry] + ) + + const actionsMenu = useMemo(() => { + return job => + generateActionsMenu( + job, + handleRerunJob, + appStore.frontendSpec.jobs_dashboard_url, + handleMonitoring, + appStore.frontendSpec.abortable_function_kinds, + appStore?.frontendSpec?.ce?.version, + handleConfirmAbortJob, + handleConfirmDeleteJob, + handleConfirmTerminateWorkflow, + accessibleProjectsMap, + toggleConvertedYaml, + handleRerun, + rerunIsDisabled + ) + }, [ + handleRerunJob, + appStore.frontendSpec.jobs_dashboard_url, + appStore.frontendSpec.abortable_function_kinds, + appStore.frontendSpec?.ce?.version, + handleMonitoring, + handleConfirmAbortJob, + handleConfirmDeleteJob, + handleConfirmTerminateWorkflow, + accessibleProjectsMap, + toggleConvertedYaml, + handleRerun, + rerunIsDisabled + ]) + + const handleCancel = useCallback(() => { + setSelectedJob({}) + setSelectedFunction({}) + setItemIsSelected(false) + }, [setItemIsSelected, setSelectedFunction, setSelectedJob]) + + const findSelectedWorkflowFunction = useCallback( + withoutRunType => { + if (workflowsStore.activeWorkflow?.data) { + const workflow = { ...workflowsStore.activeWorkflow.data } - const handleConfirmDeleteJob = useCallback( - job => { - setConfirmData({ - item: job, - header: 'Delete job?', - message: `Are you sure you want to delete the job "${job.name}"? Deleted jobs can not be restored.`, - btnConfirmLabel: 'Delete', - btnConfirmType: DANGER_BUTTON, - rejectHandler: () => { - setConfirmData(null) - }, - confirmHandler: () => { - onDeleteJob(job) - setConfirmData(null) - } - }) - }, - [onDeleteJob, setConfirmData] - ) + return find(workflow.graph, workflowItem => { + let workflowItemIsFound = + workflowItem.function?.includes(`${params.functionName}@${params.functionHash}`) || + workflowItem.function?.includes(params.functionName) || + workflowItem.function?.includes(params.jobId) - const handleConfirmTerminateWorkflow = useCallback( - job => { - setConfirmData({ - item: job, - header: 'Terminate workflow', - message: `Are you sure you want to terminate the workflow "${job.name}" (stop its execution)? Workflows termination cannot be undone.`, - btnConfirmLabel: 'Terminate', - btnConfirmType: DANGER_BUTTON, - rejectHandler: () => { - setConfirmData(null) - }, - confirmHandler: () => { - onTerminateWorkflow(job) - setConfirmData(null) + if (withoutRunType) { + workflowItemIsFound = workflowItemIsFound && workflowItem.run_type !== 'run' } - }) - }, - [onTerminateWorkflow, setConfirmData] - ) - - const handleRerun = useCallback( - workflow => { - dispatch(rerunWorkflow({ project: workflow.project, workflowId: workflow.id })) - .unwrap() - .then(() => { - handleRetry() - dispatch( - setNotification({ - status: 200, - id: Math.random(), - message: 'Workflow run successfully.' - }) - ) - }) - .catch(error => { - showErrorNotification(dispatch, error, 'Workflow did not run successfully', '', () => - handleRerun(workflow) - ) - }) - }, - [dispatch, handleRetry] - ) - - const actionsMenu = useMemo(() => { - return job => - generateActionsMenu( - job, - handleRerunJob, - appStore.frontendSpec.jobs_dashboard_url, - handleMonitoring, - appStore.frontendSpec.abortable_function_kinds, - appStore?.frontendSpec?.ce?.version, - handleConfirmAbortJob, - handleConfirmDeleteJob, - handleConfirmTerminateWorkflow, - accessibleProjectsMap, - toggleConvertedYaml, - handleRerun, - rerunIsDisabled - ) - }, [ - handleRerunJob, - appStore.frontendSpec.jobs_dashboard_url, - appStore.frontendSpec.abortable_function_kinds, - appStore.frontendSpec?.ce?.version, - handleMonitoring, - handleConfirmAbortJob, - handleConfirmDeleteJob, - handleConfirmTerminateWorkflow, - accessibleProjectsMap, - toggleConvertedYaml, - handleRerun, - rerunIsDisabled - ]) - - const handleCancel = useCallback(() => { - setSelectedJob({}) - setSelectedFunction({}) - setItemIsSelected(false) - }, [setItemIsSelected, setSelectedFunction, setSelectedJob]) - - const findSelectedWorkflowFunction = useCallback( - withoutRunType => { - if (workflowsStore.activeWorkflow?.data) { - const workflow = { ...workflowsStore.activeWorkflow.data } - return find(workflow.graph, workflowItem => { - let workflowItemIsFound = - workflowItem.function?.includes(`${params.functionName}@${params.functionHash}`) || - workflowItem.function?.includes(params.functionName) || - workflowItem.function?.includes(params.jobId) - - if (withoutRunType) { - workflowItemIsFound = workflowItemIsFound && workflowItem.run_type !== 'run' - } - - return workflowItemIsFound - }) - } - }, - [params.functionName, params.functionHash, params.jobId, workflowsStore.activeWorkflow.data] - ) - - const checkIfWorkflowItemIsJob = useCallback(() => { - if (workflowsStore.activeWorkflow?.data?.graph) { - let selectedWorkflowItem = findSelectedWorkflowFunction(true) + return workflowItemIsFound + }) + } + }, + [params.functionName, params.functionHash, params.jobId, workflowsStore.activeWorkflow.data] + ) - if (isEmpty(selectedWorkflowItem)) { - selectedWorkflowItem = findSelectedWorkflowFunction(false) - } + const checkIfWorkflowItemIsJob = useCallback(() => { + if (workflowsStore.activeWorkflow?.data?.graph) { + let selectedWorkflowItem = findSelectedWorkflowFunction(true) - return !['deploy', 'build'].includes(selectedWorkflowItem?.run_type) + if (isEmpty(selectedWorkflowItem)) { + selectedWorkflowItem = findSelectedWorkflowFunction(false) } - }, [workflowsStore.activeWorkflow.data.graph, findSelectedWorkflowFunction]) - const handleCatchRequest = useCallback( - (error, message) => { - showErrorNotification(dispatch, error, message, '') - navigate( - location.pathname - .split('/') - .splice(0, location.pathname.split('/').indexOf(params.workflowId) + 1) - .join('/') + window.location.search - ) - }, - [dispatch, location.pathname, navigate, params.workflowId] - ) + return !['deploy', 'build'].includes(selectedWorkflowItem?.run_type) + } + }, [workflowsStore.activeWorkflow.data.graph, findSelectedWorkflowFunction]) + + const handleCatchRequest = useCallback( + (error, message) => { + showErrorNotification(dispatch, error, message, '') + navigate( + location.pathname + .split('/') + .splice(0, location.pathname.split('/').indexOf(params.workflowId) + 1) + .join('/') + window.location.search + ) + }, + [dispatch, location.pathname, navigate, params.workflowId] + ) + + useEffect(() => { + if ( + !fetchJobFunctionsPromiseRef.current && + params.jobId && + (isEmpty(selectedJob) || params.jobId !== selectedJob.uid) && + checkIfWorkflowItemIsJob() && + !dataIsLoading + ) { + setDataIsLoading(true) + fetchRun().finally(() => setDataIsLoading(false)) + } + }, [fetchRun, params.jobId, selectedJob, checkIfWorkflowItemIsJob, dataIsLoading]) + + useEffect(() => { + const functionToBeSelected = findSelectedWorkflowFunction(true) + + if (isWorkflowStepExecutable(functionToBeSelected)) { + const workflow = { ...workflowsStore.activeWorkflow?.data } + const graphFunctionState = functionToBeSelected?.phase?.toLowerCase() + const isErrorState = [FAILED_STATE, ERROR_STATE].includes(graphFunctionState) + const customFunctionState = isErrorState ? graphFunctionState : '' + const pipelineError = getPipelineError(isErrorState) - useEffect(() => { if ( - !fetchJobFunctionsPromiseRef.current && - params.jobId && - (isEmpty(selectedJob) || params.jobId !== selectedJob.uid) && - checkIfWorkflowItemIsJob() && - !dataIsLoading + workflow.graph && + params.functionHash && + (isEmpty(selectedFunction) || params.functionHash !== selectedFunction.hash) ) { - setDataIsLoading(true) - fetchRun().finally(() => setDataIsLoading(false)) - } - }, [fetchRun, params.jobId, selectedJob, checkIfWorkflowItemIsJob, dataIsLoading]) - - useEffect(() => { - const functionToBeSelected = findSelectedWorkflowFunction(true) - - if (isWorkflowStepExecutable(functionToBeSelected)) { - const workflow = { ...workflowsStore.activeWorkflow?.data } - const graphFunctionState = functionToBeSelected?.phase?.toLowerCase() - const isErrorState = [FAILED_STATE, ERROR_STATE].includes(graphFunctionState) - const customFunctionState = isErrorState ? graphFunctionState : '' - const pipelineError = getPipelineError(isErrorState) - - if ( - workflow.graph && - params.functionHash && - (isEmpty(selectedFunction) || params.functionHash !== selectedFunction.hash) - ) { - if (params.functionName !== selectedFunction.name) { - dispatch( - fetchFunction({ - project: params.workflowProjectName || params.projectName, - name: params.functionName, - hash: params.functionHash === 'latest' ? '' : params.functionHash - }) - ) - .unwrap() - .then(func => { - setSelectedFunction( - parseFunction( - func, - params.workflowProjectName || params.projectName, - customFunctionState, - pipelineError - ) - ) - setItemIsSelected(true) - setSelectedJob({}) - }) - .catch(error => handleCatchRequest(error, 'Failed to fetch function')) - } - } else if ( - workflow.graph && - params.jobId && - (isEmpty(selectedFunction) || params.jobId !== selectedFunction.name) && - !checkIfWorkflowItemIsJob() - ) { + if (params.functionName !== selectedFunction.name) { dispatch( fetchFunction({ project: params.workflowProjectName || params.projectName, - name: params.jobId + name: params.functionName, + hash: params.functionHash === 'latest' ? '' : params.functionHash }) ) .unwrap() @@ -636,191 +608,217 @@ const WorkflowsTable = React.forwardRef( }) .catch(error => handleCatchRequest(error, 'Failed to fetch function')) } - } - }, [ - findSelectedWorkflowFunction, - handleCatchRequest, - params.functionHash, - params.functionName, - params.projectName, - selectedFunction, - workflowsStore.activeWorkflow, - checkIfWorkflowItemIsJob, - params.jobId, - dispatch, - setSelectedFunction, - setItemIsSelected, - setSelectedJob, - params.workflowProjectName, - getPipelineError - ]) - - useEffect(() => { - if ((params.jobId || params.functionHash) && pageData.details.menu.length > 0) { - isDetailsTabExists(params.tab, pageData.details.menu, navigate, location) - } - }, [navigate, pageData.details.menu, location, params.jobId, params.functionHash, params.tab]) - - useEffect(() => { - const workflow = { ...workflowsStore.activeWorkflow?.data } - - if (!params.workflowId && workflow.graph) { - dispatch(resetWorkflow()) - } - - if (!workflow.graph && params.workflowId && !workflowIsLoaded) { - refreshWorkflow() - setWorkflowIsLoaded(true) - } - - if ( - ['Running', 'None'].includes(workflow?.run?.status) && - params.workflowId && - workflow.graph - ) { - const timeout = setTimeout(refreshWorkflow, 10000) - - return () => clearTimeout(timeout) - } - }, [ - refreshWorkflow, - dispatch, - workflowIsLoaded, - params.workflowId, - workflowsStore.activeWorkflow, - setWorkflowIsLoaded - ]) - - useEffect(() => { - if ( - jobWizardMode && - !jobWizardIsOpened && - ((jobWizardMode === PANEL_RERUN_MODE && editableItem?.rerun_object) || - jobWizardMode !== PANEL_RERUN_MODE) + } else if ( + workflow.graph && + params.jobId && + (isEmpty(selectedFunction) || params.jobId !== selectedFunction.name) && + !checkIfWorkflowItemIsJob() ) { - openPopUp(JobWizard, { - params: { - ...params, - projectName: editableItem?.rerun_object?.task?.metadata?.project || params.projectName - }, - onWizardClose: () => { - setEditableItem(null) - setJobWizardMode(null) - setJobWizardIsOpened(false) - }, - defaultData: jobWizardMode === PANEL_RERUN_MODE ? editableItem?.rerun_object : {}, - mode: jobWizardMode, - wizardTitle: jobWizardMode === PANEL_RERUN_MODE ? 'Batch re-run' : undefined - }) - - setJobWizardIsOpened(true) - } - }, [ - editableItem?.rerun_object, - filters, - jobWizardIsOpened, - jobWizardMode, - params, - setEditableItem, - setJobWizardIsOpened, - setJobWizardMode - ]) - - useEffect(() => { - abortJobRef.current?.() - }, [abortJobRef, params.jobId]) - - useEffect(() => { - if (!params.functionHash && !params.jobId) { - setItemIsSelected(false) - setSelectedJob({}) - setSelectedFunction({}) - } - }, [params.functionHash, params.jobId, setItemIsSelected, setSelectedFunction, setSelectedJob]) - - useEffect(() => { - if (workflowsStore.workflows.rerunInProgress) { - setRerunIsDisabled(true) - setTimeout(() => { - setRerunIsDisabled(false) - }, 5000) - } - }, [workflowsStore.workflows.rerunInProgress]) - - const virtualizationConfig = useVirtualization({ - rowsData: { - content: tableContent - }, - heightData: { - headerRowHeight: monitorWorkflowsHeaderRowHeight, - rowHeight: monitorWorkflowsRowHeight, - rowHeightExtended: monitorWorkflowsRowHeightExtended + dispatch( + fetchFunction({ + project: params.workflowProjectName || params.projectName, + name: params.jobId + }) + ) + .unwrap() + .then(func => { + setSelectedFunction( + parseFunction( + func, + params.workflowProjectName || params.projectName, + customFunctionState, + pipelineError + ) + ) + setItemIsSelected(true) + setSelectedJob({}) + }) + .catch(error => handleCatchRequest(error, 'Failed to fetch function')) } - }) - - return ( - <> - {(workflowsStore.workflows.loading || permissionsLoading) && } - {workflowsStore.workflows.loading ? null : (!workflowsStore.workflows.loading && - !params.workflowId && - workflowsStore.workflows.data.length === 0) || - requestErrorMessage ? ( - - ) : ( - <> - {params.workflowId ? ( - - ) : ( - - {sortedTableContent.map( - (tableItem, index) => - isRowRendered(virtualizationConfig, index) && ( - - ) - )} -
      - )} - - )} - - ) - } -) + } + }, [ + findSelectedWorkflowFunction, + handleCatchRequest, + params.functionHash, + params.functionName, + params.projectName, + selectedFunction, + workflowsStore.activeWorkflow, + checkIfWorkflowItemIsJob, + params.jobId, + dispatch, + setSelectedFunction, + setItemIsSelected, + setSelectedJob, + params.workflowProjectName, + getPipelineError + ]) + + useEffect(() => { + if ((params.jobId || params.functionHash) && pageData.details.menu.length > 0) { + isDetailsTabExists(params.tab, pageData.details.menu, navigate, location) + } + }, [navigate, pageData.details.menu, location, params.jobId, params.functionHash, params.tab]) + + useEffect(() => { + const workflow = { ...workflowsStore.activeWorkflow?.data } + + if (!params.workflowId && workflow.graph) { + dispatch(resetWorkflow()) + } + + if (!workflow.graph && params.workflowId && !workflowIsLoaded) { + refreshWorkflow() + setWorkflowIsLoaded(true) + } + + if ( + ['Running', 'None'].includes(workflow?.run?.status) && + params.workflowId && + workflow.graph + ) { + const timeout = setTimeout(refreshWorkflow, 10000) + + return () => clearTimeout(timeout) + } + }, [ + refreshWorkflow, + dispatch, + workflowIsLoaded, + params.workflowId, + workflowsStore.activeWorkflow, + setWorkflowIsLoaded + ]) + + useEffect(() => { + if ( + jobWizardMode && + !jobWizardIsOpened && + ((jobWizardMode === PANEL_RERUN_MODE && editableItem?.rerun_object) || + jobWizardMode !== PANEL_RERUN_MODE) + ) { + openPopUp(JobWizard, { + params: { + ...params, + projectName: editableItem?.rerun_object?.task?.metadata?.project || params.projectName + }, + onWizardClose: () => { + setEditableItem(null) + setJobWizardMode(null) + setJobWizardIsOpened(false) + }, + defaultData: jobWizardMode === PANEL_RERUN_MODE ? editableItem?.rerun_object : {}, + mode: jobWizardMode, + wizardTitle: jobWizardMode === PANEL_RERUN_MODE ? 'Batch re-run' : undefined + }) + + setJobWizardIsOpened(true) + } + }, [ + editableItem?.rerun_object, + filters, + jobWizardIsOpened, + jobWizardMode, + params, + setEditableItem, + setJobWizardIsOpened, + setJobWizardMode + ]) + + useEffect(() => { + abortJobRef.current?.() + }, [abortJobRef, params.jobId]) + + useEffect(() => { + if (!params.functionHash && !params.jobId) { + setItemIsSelected(false) + setSelectedJob({}) + setSelectedFunction({}) + } + }, [params.functionHash, params.jobId, setItemIsSelected, setSelectedFunction, setSelectedJob]) + + useEffect(() => { + if (workflowsStore.workflows.rerunInProgress) { + setRerunIsDisabled(true) + setTimeout(() => { + setRerunIsDisabled(false) + }, 5000) + } + }, [workflowsStore.workflows.rerunInProgress]) + + const virtualizationConfig = useVirtualization({ + rowsData: { + content: tableContent + }, + heightData: { + headerRowHeight: monitorWorkflowsHeaderRowHeight, + rowHeight: monitorWorkflowsRowHeight, + rowHeightExtended: monitorWorkflowsRowHeightExtended + } + }) + + return ( + <> + {(workflowsStore.workflows.loading || permissionsLoading) && } + {workflowsStore.workflows.loading ? null : (!workflowsStore.workflows.loading && + !params.workflowId && + workflowsStore.workflows.data.length === 0) || + requestErrorMessage ? ( + + ) : ( + <> + {params.workflowId ? ( + + ) : ( + + {sortedTableContent.map( + (tableItem, index) => + isRowRendered(virtualizationConfig, index) && ( + + ) + )} +
      + )} + + )} + + ) +} WorkflowsTable.displayName = 'WorkflowsTable' diff --git a/src/hooks/mode.hook.js b/src/hooks/mode.hook.js index a2ac86def2..604c71d134 100644 --- a/src/hooks/mode.hook.js +++ b/src/hooks/mode.hook.js @@ -41,11 +41,11 @@ export const useMode = () => { const urlMode = getUrlMode(window.location.search) useLayoutEffect(() => { - if (urlMode) { + if (urlMode && urlMode !== mode) { localStorageService.setStorageValue('mode', urlMode) - setMode(urlMode) + queueMicrotask(() => setMode(urlMode)) } - }, [urlMode]) + }, [mode, urlMode]) return { isDemoMode: mode === 'demo', diff --git a/src/hooks/nuclioMode.hook.js b/src/hooks/nuclioMode.hook.js index 88c5fea164..d7813b6546 100644 --- a/src/hooks/nuclioMode.hook.js +++ b/src/hooks/nuclioMode.hook.js @@ -37,7 +37,7 @@ export const useNuclioMode = () => { useLayoutEffect(() => { if (mode !== window.mlrunConfig.nuclioMode) { - setMode(window.mlrunConfig.nuclioMode) + queueMicrotask(() => setMode(window.mlrunConfig.nuclioMode)) } }, [mode]) diff --git a/src/hooks/openPanel.hook.js b/src/hooks/openPanel.hook.js index fc981e275f..943d0bb578 100644 --- a/src/hooks/openPanel.hook.js +++ b/src/hooks/openPanel.hook.js @@ -27,7 +27,9 @@ export const useOpenPanel = () => { const location = useLocation() useLayoutEffect(() => { - setPanelOpened(isPanelOpened(location.search)) + queueMicrotask(() => { + setPanelOpened(isPanelOpened(location.search)) + }) }, [location.search]) return panelOpened diff --git a/src/hooks/useJobsPageData.js b/src/hooks/useJobsPageData.js index db077b3a86..c661fd98c5 100644 --- a/src/hooks/useJobsPageData.js +++ b/src/hooks/useJobsPageData.js @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { useCallback, useMemo, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useLocation, useParams } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import { isEmpty } from 'lodash' @@ -61,6 +61,7 @@ export const useJobsPageData = (initialTabData, selectedTab) => { const location = useLocation() const appStore = useSelector(store => store.appStore) const lastCheckedJobIdRef = useRef(null) + const refreshJobsRef = useRef() const historyBackLink = useMemo(() => { const queryParams = getSavedSearchParams(location.search) @@ -158,7 +159,7 @@ export const useJobsPageData = (initialTabData, selectedTab) => { filters.project?.toLowerCase?.() || params.projectName || '*', abortJobRef, responseAbortingJobs, - () => refreshJobs(filters), + () => refreshJobsRef.current?.(filters), dispatch ) } @@ -191,6 +192,10 @@ export const useJobsPageData = (initialTabData, selectedTab) => { [dispatch, params.jobName, params.projectName, terminateAbortTasksPolling] ) + useEffect(() => { + refreshJobsRef.current = refreshJobs + }, [refreshJobs]) + const refreshScheduled = useCallback( filters => { setScheduledJobs([]) diff --git a/src/hooks/useModalBlockHistory.hook.js b/src/hooks/useModalBlockHistory.hook.js index 7d903db25d..765fa8b112 100644 --- a/src/hooks/useModalBlockHistory.hook.js +++ b/src/hooks/useModalBlockHistory.hook.js @@ -24,17 +24,20 @@ import { defaultCloseModalHandler } from '../utils/defaultCloseModalHandler' import { areFormValuesChanged } from 'igz-controls/utils/form.util' export const useModalBlockHistory = (closeModal, form) => { - const shouldBlock = useCallback(({ currentLocation, nextLocation }) => { - const { initialValues, values } = form.getState() + const shouldBlock = useCallback( + ({ currentLocation, nextLocation }) => { + const { initialValues, values } = form.getState() - const isFormDirty = areFormValuesChanged(initialValues, values) + const isFormDirty = areFormValuesChanged(initialValues, values) - if (!isFormDirty && currentLocation.pathname !== nextLocation.pathname) { - closeModal() - } + if (!isFormDirty && currentLocation.pathname !== nextLocation.pathname) { + closeModal() + } - return isFormDirty && currentLocation.pathname !== nextLocation.pathname - }, [closeModal, form]) + return isFormDirty && currentLocation.pathname !== nextLocation.pathname + }, + [closeModal, form] + ) let blocker = useBlocker(shouldBlock) diff --git a/src/hooks/useRefreshAlerts.hook.js b/src/hooks/useRefreshAlerts.hook.js index 4836fb319c..46e145b7fd 100644 --- a/src/hooks/useRefreshAlerts.hook.js +++ b/src/hooks/useRefreshAlerts.hook.js @@ -90,7 +90,9 @@ export const useRefreshAlerts = (filters, isAlertsPage) => { ) useEffect(() => { - !isAlertsPage && refreshAlerts(filters) + queueMicrotask(() => { + !isAlertsPage && refreshAlerts(filters) + }) }, [isAlertsPage, refreshAlerts, filters]) return { diff --git a/src/hooks/useSortTable.hook.jsx b/src/hooks/useSortTable.hook.jsx index ea87085c13..34523e8be0 100644 --- a/src/hooks/useSortTable.hook.jsx +++ b/src/hooks/useSortTable.hook.jsx @@ -17,8 +17,8 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { useCallback, useEffect, useState, useMemo } from 'react' -import { isEmpty, isNumber, orderBy, isEqual } from 'lodash' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { isEmpty, isEqual, isNumber, orderBy } from 'lodash' import ArrowIcon from 'igz-controls/images/back-arrow.svg?react' @@ -38,7 +38,9 @@ export const useSortTable = ({ headers, content, sortConfig = {} }) => { useEffect(() => { if (!isEqual(config, sortConfig)) { - setConfig(sortConfig) + queueMicrotask(() => { + setConfig(sortConfig) + }) } }, [sortConfig, config]) @@ -87,16 +89,13 @@ export const useSortTable = ({ headers, content, sortConfig = {} }) => { ) const isSortableByIndex = useCallback(() => { - let isSortByIndex = - isNumber(allowSortBy) || isNumber(excludeSortBy) - ? true - : Array.isArray(allowSortBy) - ? allowSortBy.every(allowedIndex => isNumber(allowedIndex)) - : Array.isArray(excludeSortBy) - ? excludeSortBy.every(allowedIndex => isNumber(allowedIndex)) - : false - - return isSortByIndex + return isNumber(allowSortBy) || isNumber(excludeSortBy) + ? true + : Array.isArray(allowSortBy) + ? allowSortBy.every(allowedIndex => isNumber(allowedIndex)) + : Array.isArray(excludeSortBy) + ? excludeSortBy.every(allowedIndex => isNumber(allowedIndex)) + : false }, [allowSortBy, excludeSortBy]) const isSortable = useCallback( @@ -202,28 +201,32 @@ export const useSortTable = ({ headers, content, sortConfig = {} }) => { } useEffect(() => { - if (direction && selectedColumnName) { - sortTable(selectedColumnName, direction) - } else if (defaultSortBy !== null && (!direction || defaultDirection) && content.length > 0) { - sortTable( - selectedColumnName - ? selectedColumnName - : isNumber(defaultSortBy) - ? headers[defaultSortBy].headerId - : defaultSortBy, - defaultDirection - ) - } else { - setSortedTableContent(content) - } + queueMicrotask(() => { + if (direction && selectedColumnName) { + sortTable(selectedColumnName, direction) + } else if (defaultSortBy !== null && (!direction || defaultDirection) && content.length > 0) { + sortTable( + selectedColumnName + ? selectedColumnName + : isNumber(defaultSortBy) + ? headers[defaultSortBy].headerId + : defaultSortBy, + defaultDirection + ) + } else { + setSortedTableContent(content) + } + }) }, [content, defaultDirection, defaultSortBy, direction, headers, selectedColumnName, sortTable]) useEffect(() => { - if (headers && headers.length > 0 && (excludeSortBy || allowSortBy)) { - const header = getSortableHeaders() + queueMicrotask(() => { + if (headers && headers.length > 0 && (excludeSortBy || allowSortBy)) { + const header = getSortableHeaders() - setSortedTableHeaders(header) - } + setSortedTableHeaders(header) + } + }) }, [allowSortBy, excludeSortBy, getSortableHeaders, headers]) return { sortTable, selectedColumnName, getSortingIcon, sortedTableContent, sortedTableHeaders } diff --git a/src/hooks/useVirtualization.hook.js b/src/hooks/useVirtualization.hook.js index 41184a7233..6882c00ef4 100644 --- a/src/hooks/useVirtualization.hook.js +++ b/src/hooks/useVirtualization.hook.js @@ -245,7 +245,9 @@ export const useVirtualization = ({ useLayoutEffect(() => { if (isEmpty(rowsData.content) && !isEqual(rowsSizes, rowsSizesLocal)) { - setRowsSizesLocal(rowsSizes) + queueMicrotask(() => { + setRowsSizesLocal(rowsSizes) + }) } }, [rowsSizesLocal, rowsData, rowsSizes]) @@ -260,7 +262,9 @@ export const useVirtualization = ({ ) if (!isEqual(rowsSizesLocal, newRowsSizes)) { - setRowsSizesLocal(newRowsSizes) + queueMicrotask(() => { + setRowsSizesLocal(newRowsSizes) + }) } } }, [ @@ -355,7 +359,9 @@ export const useVirtualization = ({ tableElement.addEventListener('scroll', calculateVirtualizationConfig) window.addEventListener('resize', calculateVirtualizationConfig) } else { - setVirtualizationConfig(virtualizationConfigInitialState) + queueMicrotask(() => { + setVirtualizationConfig(virtualizationConfigInitialState) + }) } return () => { diff --git a/src/layout/Page/Page.jsx b/src/layout/Page/Page.jsx index 20ba4df3f2..1882191b79 100644 --- a/src/layout/Page/Page.jsx +++ b/src/layout/Page/Page.jsx @@ -77,7 +77,9 @@ const Page = () => { navigate('/projects') }) } else { - setProjectFetched(true) + queueMicrotask(() => { + setProjectFetched(true) + }) } }, [dispatch, location.pathname, navigate, projectName, projectsList.length]) diff --git a/src/utils/wrapComponentForNavbarNavigationTracking.jsx b/src/utils/wrapComponentForNavbarNavigationTracking.jsx index 26cd2e304f..c76ef67c48 100644 --- a/src/utils/wrapComponentForNavbarNavigationTracking.jsx +++ b/src/utils/wrapComponentForNavbarNavigationTracking.jsx @@ -17,19 +17,22 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -import { useMemo, useRef } from 'react' +import { useEffect, useRef, useState } from 'react' import { useLocation } from 'react-router-dom' const wrapComponentForNavbarNavigationTracking = WrappedComponent => { const Wrap = props => { const location = useLocation() const savedKeyRef = useRef(0) - const key = useMemo(() => { + const [key, setKey] = useState(0) + + useEffect(() => { if (location.state?.navbarNavigate) { - return ++savedKeyRef.current + savedKeyRef.current += 1 + setKey(savedKeyRef.current) + } else { + setKey(savedKeyRef.current) } - - return savedKeyRef.current }, [location.state?.navbarNavigate]) return @@ -38,4 +41,4 @@ const wrapComponentForNavbarNavigationTracking = WrappedComponent => { return Wrap } -export default wrapComponentForNavbarNavigationTracking \ No newline at end of file +export default wrapComponentForNavbarNavigationTracking From be765df5dd2e9b02a9f38941fa609da8488ac24f Mon Sep 17 00:00:00 2001 From: Olena Zhelnytska Date: Fri, 21 Nov 2025 14:54:12 +0100 Subject: [PATCH 226/228] update install dependencies --- .github/workflows/build.yaml | 2 +- .github/workflows/ci.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 89fca01428..c55235665f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -78,7 +78,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v3 with: - node-version: '16' + node-version: '21' - name: Docker login (ghcr) uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0079dd9e75..0ac6bb4a93 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -122,13 +122,13 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: '16' + node-version: '21' - name: get needs object run: echo "${{toJson(needs)}}" - name: Install dependencies - run: npm install + run: npm install --legacy-peer-deps - name: Run ESLint run: | From bbf274dfe2af26859d7a8866688a52f651487bab Mon Sep 17 00:00:00 2001 From: Olena Zhelnytska Date: Fri, 21 Nov 2025 15:07:24 +0100 Subject: [PATCH 227/228] test install dependencies --- tests/features/alerts.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/features/alerts.feature b/tests/features/alerts.feature index 31dc72b71b..4881e919e4 100644 --- a/tests/features/alerts.feature +++ b/tests/features/alerts.feature @@ -359,6 +359,7 @@ Feature: Alerts Page @MLAlert @smoke + @uniqueTag Scenario: MLAlert007 - Check components on Endpoints alert detail pane on Alerts page Given open url And wait load page From 7368e1c2b3438b87eea4e81f1f7bf39b9edcc5fa Mon Sep 17 00:00:00 2001 From: Olena Zhelnytska Date: Fri, 21 Nov 2025 15:13:08 +0100 Subject: [PATCH 228/228] test-2 install dependencies --- tests/features/alerts.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/features/alerts.feature b/tests/features/alerts.feature index 4881e919e4..31dc72b71b 100644 --- a/tests/features/alerts.feature +++ b/tests/features/alerts.feature @@ -359,7 +359,6 @@ Feature: Alerts Page @MLAlert @smoke - @uniqueTag Scenario: MLAlert007 - Check components on Endpoints alert detail pane on Alerts page Given open url And wait load page