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 01/10] 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 02/10] 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 03/10] 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 04/10] 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 05/10] 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 06/10] 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 07/10] 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 08/10] 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 09/10] 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 613ec0c65f48a61e147d2c012b61348f51c3ecf7 Mon Sep 17 00:00:00 2001 From: Andrii Mavdryk Date: Tue, 3 Jun 2025 15:36:38 +0300 Subject: [PATCH 10/10] [UI] Move `Table` components to DRC --- package.json | 2 +- 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 +- .../MonitoringApplication.util.jsx | 4 +- .../MonitoringApplicationCard.jsx | 3 +- .../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/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 | 4 +- .../ConsumerGroupTableRow.jsx | 4 +- .../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/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 +- 242 files changed, 1138 insertions(+), 6556 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/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/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/MonitoringApplication/MonitoringApplication.util.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx index 06aed80dd0..e654fed442 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication.util.jsx @@ -20,9 +20,9 @@ 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 { 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.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..18640c695a 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 { showErrorNotification } from 'igz-controls/utils/notification.util' -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 { 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 && ( { return ( !rowItemProp.hidden && ( { 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 44e36ae564..d522250ec1 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, @@ -66,8 +66,8 @@ import { isWorkflowStepExecutable } from '../../components/Workflow/workflow.uti 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 bce1e7b2c9..e3a303f796 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 10a31f8eac..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 ce145446f0..17c1d2d155 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 96c76bd266..5fc5b67adb 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/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'