From 0b91e9b488b7923803557a4918c507cac57849d9 Mon Sep 17 00:00:00 2001 From: "illia.prokopchuk" Date: Tue, 18 Mar 2025 15:51:32 +0200 Subject: [PATCH 01/30] Cleanup [Jobs panel] remove redundant components --- .../ScheduleFeatureSet/recurringReducer.js | 27 +++ src/components/ScheduleJob/ScheduleJob.js | 154 ----------------- src/components/ScheduleJob/ScheduleJobView.js | 142 --------------- .../ScheduleJob/recurringReducer.js | 161 ------------------ src/components/ScheduleJob/scheduleJob.scss | 7 - src/components/ScheduleJob/scheduleJobData.js | 23 --- .../ScheduleJobSimple/ScheduleJobSimple.js | 80 --------- .../SheduleWizard/ScheduleWizard.js | 3 +- .../SheduleWizard/scheduleWizard.util.js | 5 + .../JobsPanelCredentialsAccessKey.js | 79 --------- .../jobsPanelCredentialsAccessKey.scss | 8 - .../ScheduleRecurring/ScheduleRecurring.js | 18 +- src/utils/getDefaultSchedule.js | 2 +- 13 files changed, 43 insertions(+), 666 deletions(-) delete mode 100644 src/components/ScheduleJob/ScheduleJob.js delete mode 100644 src/components/ScheduleJob/ScheduleJobView.js delete mode 100644 src/components/ScheduleJob/recurringReducer.js delete mode 100644 src/components/ScheduleJob/scheduleJob.scss delete mode 100644 src/components/ScheduleJob/scheduleJobData.js delete mode 100644 src/components/ScheduleJobSimple/ScheduleJobSimple.js delete mode 100644 src/elements/JobsPanelCredentialsAccessKey/JobsPanelCredentialsAccessKey.js delete mode 100644 src/elements/JobsPanelCredentialsAccessKey/jobsPanelCredentialsAccessKey.scss diff --git a/src/components/FeatureSetsPanel/ScheduleFeatureSet/recurringReducer.js b/src/components/FeatureSetsPanel/ScheduleFeatureSet/recurringReducer.js index def05c80c2..2afe166447 100644 --- a/src/components/FeatureSetsPanel/ScheduleFeatureSet/recurringReducer.js +++ b/src/components/FeatureSetsPanel/ScheduleFeatureSet/recurringReducer.js @@ -44,8 +44,11 @@ export const scheduleActionType = { SCHEDULE_REPEAT_ACTIVE_OPTION: 'SCHEDULE_REPEAT_ACTIVE_OPTION', SCHEDULE_REPEAT_DAY: 'SCHEDULE_REPEAT_DAY', SCHEDULE_REPEAT_DAYS_OF_WEEK: 'SCHEDULE_REPEAT_DAYS_OF_WEEK', + SCHEDULE_REPEAT_END_ACTIVE_OPTION: 'SCHEDULE_REPEAT_END_ACTIVE_OPTION', + SCHEDULE_REPEAT_END_DATE: 'SCHEDULE_REPEAT_END_DATE', SCHEDULE_REPEAT_DAY_TIME: 'SCHEDULE_REPEAT_DAY_TIME', SCHEDULE_REPEAT_MONTH_TIME: 'SCHEDULE_REPEAT_MONTH_TIME', + SCHEDULE_REPEAT_END_OCCURRENCES: 'SCHEDULE_REPEAT_END_OCCURRENCES', SCHEDULE_REPEAT_HOUR: 'SCHEDULE_REPEAT_HOUR', SCHEDULE_REPEAT_MINUTE: 'SCHEDULE_REPEAT_MINUTE', SCHEDULE_REPEAT_WEEK_TIME: 'SCHEDULE_REPEAT_WEEK_TIME' @@ -128,6 +131,30 @@ export const recurringReducer = (state, action) => { } } } + case scheduleActionType.SCHEDULE_REPEAT_END_ACTIVE_OPTION: + return { + ...state, + scheduleRepeatEnd: { + ...state.scheduleRepeatEnd, + activeOption: action.payload + } + } + case scheduleActionType.SCHEDULE_REPEAT_END_OCCURRENCES: + return { + ...state, + scheduleRepeatEnd: { + ...state.scheduleRepeatEnd, + occurrences: action.payload + } + } + case scheduleActionType.SCHEDULE_REPEAT_END_DATE: + return { + ...state, + scheduleRepeatEnd: { + ...state.scheduleRepeatEnd, + date: action.payload + } + } default: return state } diff --git a/src/components/ScheduleJob/ScheduleJob.js b/src/components/ScheduleJob/ScheduleJob.js deleted file mode 100644 index 4d509d001b..0000000000 --- a/src/components/ScheduleJob/ScheduleJob.js +++ /dev/null @@ -1,154 +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, useReducer, useEffect } from 'react' -import PropTypes from 'prop-types' - -import ScheduleJobView from './ScheduleJobView' - -import { initialState, recurringReducer, scheduleActionType } from './recurringReducer' -import { decodeLocale, getWeekDays, getWeekStart } from '../../utils/datePicker.util' -import { tabs } from './scheduleJobData' -import { getFormatTime } from '../../utils' -import { generateCronInitialValue } from '../../utils/generateCronInitialValue' -import { getDefaultSchedule } from '../../utils/getDefaultSchedule' - -const ScheduleJob = ({ - defaultCron = '', - handleEditJob = () => {}, - handleRunJob, - panelDispatch, - panelState, - setOpenScheduleJob, - setValidation, - validation -}) => { - const [activeTab, setActiveTab] = useState(tabs[0].id) - const [cron, setCron] = useState(defaultCron || '10 * * * *') - const [date, setDate] = useState('') - const [time, setTime] = useState('') - const [isRecurring, setIsRecurring] = useState('recurring') - const [recurringState, recurringDispatch] = useReducer(recurringReducer, initialState) - const startWeek = getWeekStart(decodeLocale(navigator.language)) - const daysOfWeek = getWeekDays(startWeek) - - const handleDaysOfWeek = day => { - const { - scheduleRepeat: { week } - } = recurringState - let distinctWeek = week.days - - distinctWeek = week.days.includes(day) - ? distinctWeek.filter(item => item !== day) - : [...week.days, day] - - let days = daysOfWeek - .filter(day => distinctWeek.includes(day.id)) - .map(day => (day.index + 6) % 7) // temporarily make Monday=0, Tuesday=1, ..., Sunday=6 - .sort() - .join(',') - - days = days || '*' - - const { hour, minute } = getFormatTime( - recurringState.scheduleRepeat[recurringState.scheduleRepeat.activeOption].time - ) - - setCron(`${minute} ${hour} * * ${days}`) - - recurringDispatch({ - type: scheduleActionType.SCHEDULE_REPEAT_DAYS_OF_WEEK, - payload: distinctWeek - }) - } - - const onHandleDateChange = dates => { - setDate(dates[0]) - } - - const onHandleTimeChange = time => { - setTime(time) - } - - const onSchedule = useCallback( - event => { - if (defaultCron) { - handleEditJob(event, cron) - } else { - handleRunJob(event, cron) - } - - setOpenScheduleJob(false) - }, - [cron, defaultCron, handleEditJob, handleRunJob, setOpenScheduleJob] - ) - - useEffect(() => { - if (activeTab === tabs[0].id) { - generateCronInitialValue( - recurringState.scheduleRepeat.activeOption, - cron, - recurringState.scheduleRepeat, - daysOfWeek, - setCron - ) - } - }, [activeTab, cron, daysOfWeek, recurringState.scheduleRepeat]) - - useEffect(() => { - if (defaultCron) { - getDefaultSchedule(defaultCron, recurringDispatch) - } - }, [defaultCron]) - - return ( - - ) -} - -ScheduleJob.propTypes = { - defaultCron: PropTypes.string, - handleEditJob: PropTypes.func, - handleRunJob: PropTypes.func.isRequired, - panelDispatch: PropTypes.func.isRequired, - panelState: PropTypes.shape({}).isRequired, - setOpenScheduleJob: PropTypes.func.isRequired -} - -export default ScheduleJob diff --git a/src/components/ScheduleJob/ScheduleJobView.js b/src/components/ScheduleJob/ScheduleJobView.js deleted file mode 100644 index 4f82efcca8..0000000000 --- a/src/components/ScheduleJob/ScheduleJobView.js +++ /dev/null @@ -1,142 +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 ScheduleJobSimple from '../ScheduleJobSimple/ScheduleJobSimple' -import ScheduleCron from '../ScheduleCron/ScheduleCron' -import { Button } from 'igz-controls/components' - -import { PRIMARY_BUTTON } from 'igz-controls/constants' -import { tabs } from './scheduleJobData' - -import { ReactComponent as Schedule } from 'igz-controls/images/clock.svg' - -import './scheduleJob.scss' -import JobsPanelCredentialsAccessKey from '../../elements/JobsPanelCredentialsAccessKey/JobsPanelCredentialsAccessKey' - -const ScheduleJobView = ({ - activeTab, - cron, - date, - daysOfWeek, - handleDaysOfWeek, - isRecurring, - onSchedule, - panelDispatch, - panelState, - recurringDispatch, - recurringState, - setActiveTab, - setCron, - setDate, - setIsRecurring, - setTime, - setValidation, - validation, - time -}) => { - return ( -
-
- {tabs.map(tab => { - const tabItemClassNames = classnames( - 'schedule-tabs__item', - activeTab === tab.id && 'schedule-tabs__item_active' - ) - - return ( -
setActiveTab(tab.id)} - > - {tab.label} -
- ) - })} -
-
-

- {activeTab === tabs[0].id ? 'Simple ' : 'Advanced '} - Schedule -

- {activeTab === tabs[0].id && ( - - )} - {activeTab === tabs[1].id && ( - - )} -
- -
- ) -} - -ScheduleJobView.propTypes = { - activeTab: PropTypes.string.isRequired, - cron: PropTypes.string.isRequired, - date: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({})]), - daysOfWeek: PropTypes.array.isRequired, - handleDaysOfWeek: PropTypes.func.isRequired, - isRecurring: PropTypes.string.isRequired, - onSchedule: PropTypes.func.isRequired, - panelDispatch: PropTypes.func.isRequired, - panelState: PropTypes.shape({}).isRequired, - recurringDispatch: PropTypes.func.isRequired, - recurringState: PropTypes.shape({}).isRequired, - setActiveTab: PropTypes.func.isRequired, - setCron: PropTypes.func.isRequired, - setDate: PropTypes.func.isRequired, - setIsRecurring: PropTypes.func.isRequired, - setTime: PropTypes.func.isRequired, - time: PropTypes.string.isRequired -} - -export default ScheduleJobView diff --git a/src/components/ScheduleJob/recurringReducer.js b/src/components/ScheduleJob/recurringReducer.js deleted file mode 100644 index 2afe166447..0000000000 --- a/src/components/ScheduleJob/recurringReducer.js +++ /dev/null @@ -1,161 +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 initialState = { - scheduleRepeat: { - activeOption: 'minute', - minute: 10, - hour: 1, - week: { - days: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], - time: '00:00' - }, - day: { - time: '00:00' - }, - month: { - time: '00:00' - } - }, - scheduleRepeatEnd: { - activeOption: 'never', - occurrences: '1', - date: '' - } -} - -export const scheduleActionType = { - SCHEDULE_REPEAT_ACTIVE_OPTION: 'SCHEDULE_REPEAT_ACTIVE_OPTION', - SCHEDULE_REPEAT_DAY: 'SCHEDULE_REPEAT_DAY', - SCHEDULE_REPEAT_DAYS_OF_WEEK: 'SCHEDULE_REPEAT_DAYS_OF_WEEK', - SCHEDULE_REPEAT_END_ACTIVE_OPTION: 'SCHEDULE_REPEAT_END_ACTIVE_OPTION', - SCHEDULE_REPEAT_END_DATE: 'SCHEDULE_REPEAT_END_DATE', - SCHEDULE_REPEAT_DAY_TIME: 'SCHEDULE_REPEAT_DAY_TIME', - SCHEDULE_REPEAT_MONTH_TIME: 'SCHEDULE_REPEAT_MONTH_TIME', - SCHEDULE_REPEAT_END_OCCURRENCES: 'SCHEDULE_REPEAT_END_OCCURRENCES', - SCHEDULE_REPEAT_HOUR: 'SCHEDULE_REPEAT_HOUR', - SCHEDULE_REPEAT_MINUTE: 'SCHEDULE_REPEAT_MINUTE', - SCHEDULE_REPEAT_WEEK_TIME: 'SCHEDULE_REPEAT_WEEK_TIME' -} - -export const recurringReducer = (state, action) => { - switch (action.type) { - case scheduleActionType.SCHEDULE_REPEAT_ACTIVE_OPTION: - return { - ...state, - scheduleRepeat: { - ...state.scheduleRepeat, - activeOption: action.payload - } - } - case scheduleActionType.SCHEDULE_REPEAT_MINUTE: - return { - ...state, - scheduleRepeat: { - ...state.scheduleRepeat, - minute: action.payload - } - } - case scheduleActionType.SCHEDULE_REPEAT_HOUR: - return { - ...state, - scheduleRepeat: { - ...state.scheduleRepeat, - hour: action.payload - } - } - case scheduleActionType.SCHEDULE_REPEAT_DAY: - return { - ...state, - scheduleRepeat: { - ...state.scheduleRepeat, - day: action.payload - } - } - case scheduleActionType.SCHEDULE_REPEAT_DAY_TIME: - return { - ...state, - scheduleRepeat: { - ...state.scheduleRepeat, - day: { - time: action.payload - } - } - } - case scheduleActionType.SCHEDULE_REPEAT_DAYS_OF_WEEK: { - return { - ...state, - scheduleRepeat: { - ...state.scheduleRepeat, - week: { - ...state.scheduleRepeat.week, - days: action.payload - } - } - } - } - case scheduleActionType.SCHEDULE_REPEAT_WEEK_TIME: - return { - ...state, - scheduleRepeat: { - ...state.scheduleRepeat, - week: { - ...state.scheduleRepeat.week, - time: action.payload - } - } - } - case scheduleActionType.SCHEDULE_REPEAT_MONTH_TIME: - return { - ...state, - scheduleRepeat: { - ...state.scheduleRepeat, - month: { - time: action.payload - } - } - } - case scheduleActionType.SCHEDULE_REPEAT_END_ACTIVE_OPTION: - return { - ...state, - scheduleRepeatEnd: { - ...state.scheduleRepeatEnd, - activeOption: action.payload - } - } - case scheduleActionType.SCHEDULE_REPEAT_END_OCCURRENCES: - return { - ...state, - scheduleRepeatEnd: { - ...state.scheduleRepeatEnd, - occurrences: action.payload - } - } - case scheduleActionType.SCHEDULE_REPEAT_END_DATE: - return { - ...state, - scheduleRepeatEnd: { - ...state.scheduleRepeatEnd, - date: action.payload - } - } - default: - return state - } -} diff --git a/src/components/ScheduleJob/scheduleJob.scss b/src/components/ScheduleJob/scheduleJob.scss deleted file mode 100644 index 10ac8f5543..0000000000 --- a/src/components/ScheduleJob/scheduleJob.scss +++ /dev/null @@ -1,7 +0,0 @@ -@import '~igz-controls/scss/colors'; -@import '~igz-controls/scss/borders'; -@import '~igz-controls/scss/mixins'; - -.jobs-panel__schedule { - @include schedule; -} diff --git a/src/components/ScheduleJob/scheduleJobData.js b/src/components/ScheduleJob/scheduleJobData.js deleted file mode 100644 index 9b53c641f5..0000000000 --- a/src/components/ScheduleJob/scheduleJobData.js +++ /dev/null @@ -1,23 +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 tabs = [ - { label: 'Simple', id: 'simple' }, - { label: 'Cronstring', id: 'cronstring' } -] diff --git a/src/components/ScheduleJobSimple/ScheduleJobSimple.js b/src/components/ScheduleJobSimple/ScheduleJobSimple.js deleted file mode 100644 index 2b8cb22769..0000000000 --- a/src/components/ScheduleJobSimple/ScheduleJobSimple.js +++ /dev/null @@ -1,80 +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 CheckBox from '../../common/CheckBox/CheckBox' -import ScheduleRecurring from '../../elements/ScheduleRecurring/ScheduleRecurring' -import DatePicker from '../../common/DatePicker/DatePicker' -import TimePicker from '../../common/TimePicker/TimePicker' - -const ScheduleJobSimple = ({ - date, - daysOfWeek, - handleDaysOfWeek, - isRecurring, - recurringDispatch, - recurringState, - setDate, - setIsRecurring, - setTime, - time -}) => { - return ( - <> -
- - -
-
- - setIsRecurring(state => (state === recurring ? '' : recurring)) - } - selectedId={isRecurring} - /> -
- {isRecurring && ( - - )} - - ) -} - -ScheduleJobSimple.propTypes = { - date: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]), - daysOfWeek: PropTypes.array.isRequired, - handleDaysOfWeek: PropTypes.func.isRequired, - isRecurring: PropTypes.string.isRequired, - recurringDispatch: PropTypes.func.isRequired, - recurringState: PropTypes.shape({}).isRequired, - setDate: PropTypes.func.isRequired, - setIsRecurring: PropTypes.func.isRequired, - setTime: PropTypes.func.isRequired, - time: PropTypes.string.isRequired -} - -export default ScheduleJobSimple diff --git a/src/components/SheduleWizard/ScheduleWizard.js b/src/components/SheduleWizard/ScheduleWizard.js index 8b841560ec..e68edcd0df 100644 --- a/src/components/SheduleWizard/ScheduleWizard.js +++ b/src/components/SheduleWizard/ScheduleWizard.js @@ -26,12 +26,11 @@ import ScheduleWizardSimple from './ScheduleWizardSimple' import ScheduleWizardCronstring from './ScheduleWizardCronstring' import ErrorMessage from '../../common/ErrorMessage/ErrorMessage' -import { tabs } from '../ScheduleJob/scheduleJobData' import { decodeLocale, getWeekDays, getWeekStart } from '../../utils/datePicker.util' import { getFormatTime } from '../../utils' import { generateCronInitialValue } from '../../utils/generateCronInitialValue' import { PRIMARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' -import { getDefaultSchedule, scheduleDataInitialState } from './scheduleWizard.util' +import { getDefaultSchedule, scheduleDataInitialState, tabs } from './scheduleWizard.util' import { SCHEDULE_DATA } from '../../types' import { SIMPLE_SCHEDULE, CRONSTRING_SCHEDULE } from '../../constants' diff --git a/src/components/SheduleWizard/scheduleWizard.util.js b/src/components/SheduleWizard/scheduleWizard.util.js index 2cceb30ed2..ffbc26633c 100644 --- a/src/components/SheduleWizard/scheduleWizard.util.js +++ b/src/components/SheduleWizard/scheduleWizard.util.js @@ -101,3 +101,8 @@ export const getDefaultSchedule = defaultCron => { return scheduleData } + +export const tabs = [ + { label: 'Simple', id: 'simple' }, + { label: 'Cronstring', id: 'cronstring' } +] diff --git a/src/elements/JobsPanelCredentialsAccessKey/JobsPanelCredentialsAccessKey.js b/src/elements/JobsPanelCredentialsAccessKey/JobsPanelCredentialsAccessKey.js deleted file mode 100644 index 0ecdca4821..0000000000 --- a/src/elements/JobsPanelCredentialsAccessKey/JobsPanelCredentialsAccessKey.js +++ /dev/null @@ -1,79 +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 { connect } from 'react-redux' -import classnames from 'classnames' -import PropTypes from 'prop-types' - -import PanelCredentialsAccessKey from '../PanelCredentialsAccessKey/PanelCredentialsAccessKey' - -import jobsActions from '../../actions/jobs' -import { panelActions } from '../../components/JobsPanel/panelReducer' -import { PANEL_DEFAULT_ACCESS_KEY } from '../../constants' - -import './jobsPanelCredentialsAccessKey.scss' - -const JobsPanelCredentialsAccessKey = ({ - isScheduled = false, - panelDispatch, - panelState, - setNewJobCredentialsAccessKey, - setValidation, - validation -}) => { - const accessKeyClassNames = classnames(isScheduled && 'without-padding', 'job-panel__item') - - const handleSetCredentialsAccessKey = value => { - panelDispatch({ - type: panelActions.SET_ACCESS_KEY, - payload: value - }) - panelDispatch({ - type: panelActions.SET_PREVIOUS_PANEL_DATA_ACCESS_KEY, - payload: value - }) - setNewJobCredentialsAccessKey(value) - } - - return ( - - ) -} - -JobsPanelCredentialsAccessKey.propTypes = { - isScheduled: PropTypes.bool, - panelDispatch: PropTypes.func.isRequired, - panelState: PropTypes.shape({}).isRequired, - setNewJobCredentialsAccessKey: PropTypes.func.isRequired, - setValidation: PropTypes.func.isRequired, - validation: PropTypes.shape({}).isRequired -} - -export default connect(jobsStore => ({ ...jobsStore }), { ...jobsActions })( - JobsPanelCredentialsAccessKey -) diff --git a/src/elements/JobsPanelCredentialsAccessKey/jobsPanelCredentialsAccessKey.scss b/src/elements/JobsPanelCredentialsAccessKey/jobsPanelCredentialsAccessKey.scss deleted file mode 100644 index 4e1c6ea9c2..0000000000 --- a/src/elements/JobsPanelCredentialsAccessKey/jobsPanelCredentialsAccessKey.scss +++ /dev/null @@ -1,8 +0,0 @@ -.job-panel__item.access-key { - height: 64px; - padding: 22px 40px; - - &.without-padding { - padding: 0; - } -} diff --git a/src/elements/ScheduleRecurring/ScheduleRecurring.js b/src/elements/ScheduleRecurring/ScheduleRecurring.js index 4e3d8c4794..c5fbee6a74 100644 --- a/src/elements/ScheduleRecurring/ScheduleRecurring.js +++ b/src/elements/ScheduleRecurring/ScheduleRecurring.js @@ -25,7 +25,7 @@ import Select from '../../common/Select/Select' import DatePicker from '../../common/DatePicker/DatePicker' import TimePicker from '../../common/TimePicker/TimePicker' -import { scheduleActionType } from '../../components/ScheduleJob/recurringReducer' +import { scheduleActionType } from '../../components/FeatureSetsPanel/ScheduleFeatureSet/recurringReducer' import { selectOptions } from './scheduleRecurring.util' import './scheduleRecurring.scss' @@ -44,8 +44,8 @@ const ScheduleRecurring = ({ daysOfWeek, handleDaysOfWeek, recurringDispatch, re selectedOption === 'minute' ? scheduleActionType.SCHEDULE_REPEAT_MINUTE : selectedOption === 'hour' - ? scheduleActionType.SCHEDULE_REPEAT_HOUR - : null, + ? scheduleActionType.SCHEDULE_REPEAT_HOUR + : null, payload: parseInt(value) }) } @@ -103,10 +103,10 @@ const ScheduleRecurring = ({ daysOfWeek, handleDaysOfWeek, recurringDispatch, re {scheduleRepeatActiveOption === 'minute' ? 'minutes' : scheduleRepeatActiveOption === 'hour' - ? 'hours at minute 0 past the hour' - : scheduleRepeatActiveOption === 'month' - ? 'on the 1st day in every month at' - : 'at'} + ? 'hours at minute 0 past the hour' + : scheduleRepeatActiveOption === 'month' + ? 'on the 1st day in every month at' + : 'at'} {['day', 'month', 'week'].includes(scheduleRepeatActiveOption) && ( { let cron = defaultCron.split(' ') From 8c18597bed7156152d54d10829dddd4119fbb5ce Mon Sep 17 00:00:00 2001 From: alxtkr77 <3098237+alxtkr77@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:42:12 +0300 Subject: [PATCH 02/30] Fix [Feature vectors] usage example (#3186) --- src/utils/generateUsageSnippets.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/generateUsageSnippets.js b/src/utils/generateUsageSnippets.js index 2f807d0172..4f012d12c2 100644 --- a/src/utils/generateUsageSnippets.js +++ b/src/utils/generateUsageSnippets.js @@ -31,13 +31,13 @@ features = [ ] vector = fs.FeatureVector("",features=features,description="this is my vector") -resp = fs.FeatureVector.get_offline_features(vector) +resp = vector.get_offline_features() #Preview the dataset resp.to_dataframe().tail(5)` }, { title: 'Getting online features:', - code: `svc = fs.FeatureVector.get_online_feature_service("") + code: `svc = fs.get_feature_vector("").get_online_feature_service() resp = svc.get([{"${selectedItem.entities[0]?.name ?? ''}": }])` } ] @@ -50,11 +50,11 @@ resp = svc.get([{"${selectedItem.entities[0]?.name ?? ''}": }])` { title: 'Getting offline & online features:', code: `import mlrun.feature_store as fs -resp = fs.FeatureVector.get_offline_features("${uri}") +resp = fs.get_feature_vector("${uri}").get_offline_features() #Preview the dataset resp.to_dataframe().tail(5) -svc = fs.FeatureVector.get_online_feature_service("${uri}") +svc = fs.get_feature_vector("${uri}").get_online_feature_service() resp = svc.get([{"customer_id": "42"}, {"customer_id": "50"}])` } ] From 979f1ba2167c5191d0810d1415b273f8054e38f6 Mon Sep 17 00:00:00 2001 From: illia-prokopchuk <78905712+illia-prokopchuk@users.noreply.github.com> Date: Thu, 3 Apr 2025 13:59:44 +0300 Subject: [PATCH 03/30] Fix [Jobs monitoring] failed to load job artifact preview (#3190) --- src/components/DetailsPreview/DetailsPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DetailsPreview/DetailsPreview.js b/src/components/DetailsPreview/DetailsPreview.js index 8ce9cb6f68..1bde07c149 100644 --- a/src/components/DetailsPreview/DetailsPreview.js +++ b/src/components/DetailsPreview/DetailsPreview.js @@ -64,7 +64,7 @@ const DetailsPreview = ({ artifact, handlePreview }) => { previewAbortControllerRef.current = new AbortController() getArtifactPreview( - params.projectName, + artifact.project || params.projectName, artifact, noData, setNoData, From e6fb8812c54cbeacabff96655e9b5b78213dde11 Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Fri, 4 Apr 2025 14:19:30 +0300 Subject: [PATCH 04/30] Impl [Projects] Move Redux to RTK (#3145) --- src/actions/projects.js | 664 ---------- src/common/Breadcrumbs/Breadcrumbs.js | 10 +- src/common/TargetPath/targetPath.util.js | 17 +- src/components/Alerts/Alerts.js | 12 +- .../FeatureSetsPanelDataSource.js | 8 +- .../FeatureSetsPanel/UrlPath.utils.js | 11 +- src/components/JobWizard/JobWizard.js | 15 +- .../JobWizardFunctionSelection.js | 21 +- src/components/Project/ProjectMonitor.js | 84 +- .../ProjectOverview/ProjectOverview.js | 27 +- .../ProjectSettings/ProjectSettings.js | 4 +- .../ProjectsJobsMonitoring.js | 9 +- .../CreateProjectDialog.js | 15 +- src/components/ProjectsPage/Projects.js | 124 +- src/components/ProjectsPage/ProjectsView.js | 3 - src/components/ProjectsPage/projects.util.js | 28 +- src/constants.js | 70 - src/elements/ProjectCard/ProjectCard.js | 25 +- src/elements/ProjectJobs/ProjectJobs.js | 31 +- .../ProjectSettingsGeneral.js | 36 +- .../ProjectSettingsSecrets.js | 65 +- src/reducers/featureStoreReducer.js | 15 +- src/reducers/projectReducer.js | 1125 +++++++---------- 23 files changed, 713 insertions(+), 1706 deletions(-) delete mode 100644 src/actions/projects.js diff --git a/src/actions/projects.js b/src/actions/projects.js deleted file mode 100644 index e2f5fbc895..0000000000 --- a/src/actions/projects.js +++ /dev/null @@ -1,664 +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 projectsApi from '../api/projects-api' -import workflowsApi from '../api/workflow-api' -import { - CHANGE_PROJECT_STATE_BEGIN, - CHANGE_PROJECT_STATE_FAILURE, - CHANGE_PROJECT_STATE_SUCCESS, - CREATE_PROJECT_BEGIN, - CREATE_PROJECT_FAILURE, - CREATE_PROJECT_SUCCESS, - DELETE_PROJECT_BEGIN, - DELETE_PROJECT_FAILURE, - DELETE_PROJECT_SUCCESS, - FETCH_PROJECT_BEGIN, - FETCH_PROJECT_SUMMARY_BEGIN, - FETCH_PROJECT_SUMMARY_FAILURE, - FETCH_PROJECT_SUMMARY_SUCCESS, - FETCH_PROJECT_DATASETS_BEGIN, - FETCH_PROJECT_DATASETS_FAILURE, - FETCH_PROJECT_DATASETS_SUCCESS, - FETCH_PROJECT_FAILED_JOBS_BEGIN, - FETCH_PROJECT_FAILED_JOBS_FAILURE, - FETCH_PROJECT_FAILED_JOBS_SUCCESS, - FETCH_PROJECT_FAILURE, - FETCH_PROJECT_FEATURE_SETS_BEGIN, - FETCH_PROJECT_FEATURE_SETS_FAILURE, - FETCH_PROJECT_FEATURE_SETS_SUCCESS, - FETCH_PROJECT_FILES_BEGIN, - FETCH_PROJECT_FILES_FAILURE, - FETCH_PROJECT_FILES_SUCCESS, - FETCH_PROJECT_FUNCTIONS_BEGIN, - FETCH_PROJECT_FUNCTIONS_FAILURE, - FETCH_PROJECT_FUNCTIONS_SUCCESS, - FETCH_PROJECT_JOBS_BEGIN, - FETCH_PROJECT_JOBS_FAILURE, - FETCH_PROJECT_JOBS_SUCCESS, - FETCH_PROJECT_MODELS_BEGIN, - FETCH_PROJECT_MODELS_FAILURE, - FETCH_PROJECT_MODELS_SUCCESS, - FETCH_PROJECT_RUNNING_JOBS_BEGIN, - FETCH_PROJECT_RUNNING_JOBS_FAILURE, - FETCH_PROJECT_RUNNING_JOBS_SUCCESS, - FETCH_PROJECT_SCHEDULED_JOBS_BEGIN, - FETCH_PROJECT_SCHEDULED_JOBS_FAILURE, - FETCH_PROJECT_SCHEDULED_JOBS_SUCCESS, - FETCH_PROJECT_SUCCESS, - FETCH_PROJECTS_SUMMARY_BEGIN, - FETCH_PROJECTS_SUMMARY_FAILURE, - FETCH_PROJECTS_SUMMARY_SUCCESS, - FETCH_PROJECT_WORKFLOWS_BEGIN, - FETCH_PROJECT_WORKFLOWS_FAILURE, - FETCH_PROJECT_WORKFLOWS_SUCCESS, - FETCH_PROJECTS_BEGIN, - FETCH_PROJECTS_FAILURE, - FETCH_PROJECTS_SUCCESS, - REMOVE_NEW_PROJECT_ERROR, - REMOVE_PROJECT_SUMMARY, - REMOVE_PROJECT_DATA, - REMOVE_PROJECTS, - FETCH_PROJECTS_NAMES_BEGIN, - FETCH_PROJECTS_NAMES_FAILURE, - FETCH_PROJECTS_NAMES_SUCCESS, - FETCH_PROJECT_SECRETS_BEGIN, - FETCH_PROJECT_SECRETS_FAILURE, - FETCH_PROJECT_SECRETS_SUCCESS, - PROJECT_ONLINE_STATUS, - SET_JOBS_MONITORING_DATA, - SET_MLRUN_IS_UNHEALTHY, - SET_MLRUN_UNHEALTHY_RETRYING, - REQUEST_CANCELED, - DEFAULT_ABORT_MSG, - SET_DELETING_PROJECTS -} from '../constants' -import { - CONFLICT_ERROR_STATUS_CODE, - INTERNAL_SERVER_ERROR_STATUS_CODE, - FORBIDDEN_ERROR_STATUS_CODE -} from 'igz-controls/constants' - -import { parseSummaryData } from '../utils/parseSummaryData' -import { showErrorNotification } from '../utils/notifications.util' -import { mlrunUnhealthyErrors } from '../components/ProjectsPage/projects.util' -import { parseProjects } from '../utils/parseProjects' - -let firstServerErrorTimestamp = null - -const projectsAction = { - changeProjectState: (project, status) => dispatch => { - dispatch(projectsAction.changeProjectStateBegin()) - - return projectsApi - .changeProjectState(project, status) - .then(() => dispatch(projectsAction.changeProjectStateSuccess())) - .catch(error => { - dispatch(projectsAction.changeProjectStateFailure()) - throw error - }) - }, - changeProjectStateBegin: () => ({ type: CHANGE_PROJECT_STATE_BEGIN }), - changeProjectStateFailure: () => ({ type: CHANGE_PROJECT_STATE_FAILURE }), - changeProjectStateSuccess: () => ({ type: CHANGE_PROJECT_STATE_SUCCESS }), - createNewProject: postData => dispatch => { - dispatch(projectsAction.createProjectBegin()) - - return projectsApi - .createProject(postData) - .then(result => { - dispatch(projectsAction.createProjectSuccess()) - - return result.data - }) - .catch(error => { - const message = - error.response?.status === CONFLICT_ERROR_STATUS_CODE - ? `A project named "${postData.metadata.name}" already exists.` - : error.response?.status === FORBIDDEN_ERROR_STATUS_CODE - ? 'You don’t have permission to create a project.' - : error.response?.status === INTERNAL_SERVER_ERROR_STATUS_CODE - ? error.response.data?.detail || - 'The system already has the maximum number of projects. An existing project must be deleted before you can create another.' - : error.message - - dispatch(projectsAction.createProjectFailure(message)) - }) - }, - createProjectBegin: () => ({ type: CREATE_PROJECT_BEGIN }), - createProjectFailure: error => ({ - type: CREATE_PROJECT_FAILURE, - payload: error - }), - createProjectSuccess: () => ({ type: CREATE_PROJECT_SUCCESS }), - deleteProject: (projectName, deleteNonEmpty) => dispatch => { - dispatch(projectsAction.deleteProjectBegin(projectName)) - - return projectsApi - .deleteProject(projectName, deleteNonEmpty) - .then(response => { - dispatch(projectsAction.deleteProjectSuccess(projectName)) - - return response - }) - .catch(error => { - dispatch(projectsAction.deleteProjectFailure(projectName)) - - throw error - }) - }, - deleteProjectBegin: (projectName) => ({ - type: DELETE_PROJECT_BEGIN, - payload: projectName - }), - deleteProjectFailure: (projectName) => ({ - type: DELETE_PROJECT_FAILURE, - payload: projectName - }), - deleteProjectSuccess: (projectName) => ({ - type: DELETE_PROJECT_SUCCESS, - payload: projectName - }), - fetchProject: (project, params, signal) => dispatch => { - dispatch(projectsAction.fetchProjectBegin()) - - return projectsApi - .getProject(project, params, signal) - .then(response => { - dispatch(projectsAction.fetchProjectSuccess(response?.data)) - return response - }) - .catch(error => { - if (![REQUEST_CANCELED, DEFAULT_ABORT_MSG].includes(error.message)) { - dispatch(projectsAction.fetchProjectFailure(error)) - - throw error - } - }) - }, - fetchProjectBegin: () => ({ type: FETCH_PROJECT_BEGIN }), - fetchProjectFailure: error => ({ - type: FETCH_PROJECT_FAILURE, - payload: error - }), - fetchProjectSuccess: project => ({ - type: FETCH_PROJECT_SUCCESS, - payload: project - }), - fetchProjectDataSets: project => dispatch => { - dispatch(projectsAction.fetchProjectDataSetsBegin()) - - return projectsApi - .getProjectDataSets(project) - .then(response => { - dispatch(projectsAction.fetchProjectDataSetsSuccess(response?.data.artifacts)) - - return response?.data.artifacts - }) - .catch(error => { - dispatch(projectsAction.fetchProjectDataSetsFailure(error.message)) - - throw error.message - }) - }, - fetchProjectDataSetsBegin: () => ({ type: FETCH_PROJECT_DATASETS_BEGIN }), - fetchProjectDataSetsFailure: error => ({ - type: FETCH_PROJECT_DATASETS_FAILURE, - payload: error - }), - fetchProjectDataSetsSuccess: datasets => ({ - type: FETCH_PROJECT_DATASETS_SUCCESS, - payload: datasets - }), - fetchProjectFailedJobs: (project, signal) => dispatch => { - dispatch(projectsAction.fetchProjectFailedJobsBegin()) - - return projectsApi - .getProjectFailedJobs(project, signal) - .then(response => { - dispatch(projectsAction.fetchProjectFailedJobsSuccess(response?.data.runs)) - - return response?.data.runs - }) - .catch(error => { - dispatch(projectsAction.fetchProjectFailedJobsFailure(error.message)) - - throw error.message - }) - }, - fetchProjectFailedJobsBegin: () => ({ - type: FETCH_PROJECT_FAILED_JOBS_BEGIN - }), - fetchProjectFailedJobsFailure: error => ({ - type: FETCH_PROJECT_FAILED_JOBS_FAILURE, - payload: error - }), - fetchProjectFailedJobsSuccess: jobs => ({ - type: FETCH_PROJECT_FAILED_JOBS_SUCCESS, - payload: jobs - }), - fetchProjectFiles: project => dispatch => { - dispatch(projectsAction.fetchProjectFilesBegin()) - - projectsApi - .getProjectFiles(project) - .then(response => { - dispatch(projectsAction.fetchProjectFilesSuccess(response?.data.artifacts)) - }) - .catch(error => { - dispatch(projectsAction.fetchProjectFilesFailure(error.message)) - }) - }, - fetchProjectFeatureSets: (project, signal) => dispatch => { - dispatch(projectsAction.fetchProjectFeatureSetsBegin()) - - return projectsApi - .getProjectFeatureSets(project, signal) - .then(response => { - dispatch(projectsAction.fetchProjectFeatureSetsSuccess(response.data?.feature_sets)) - - return response.data?.feature_sets - }) - .catch(error => { - dispatch(projectsAction.fetchProjectFeatureSetsFailure(error.message)) - - throw error.message - }) - }, - fetchProjectFeatureSetsBegin: () => ({ - type: FETCH_PROJECT_FEATURE_SETS_BEGIN - }), - fetchProjectFeatureSetsFailure: error => ({ - type: FETCH_PROJECT_FEATURE_SETS_FAILURE, - payload: error - }), - fetchProjectFeatureSetsSuccess: featureSets => ({ - type: FETCH_PROJECT_FEATURE_SETS_SUCCESS, - payload: featureSets - }), - fetchProjectFilesBegin: () => ({ type: FETCH_PROJECT_FILES_BEGIN }), - fetchProjectFilesFailure: error => ({ - type: FETCH_PROJECT_FILES_FAILURE, - payload: error - }), - fetchProjectFilesSuccess: files => ({ - type: FETCH_PROJECT_FILES_SUCCESS, - payload: files - }), - fetchProjectFunctions: (project, signal) => dispatch => { - dispatch(projectsAction.fetchProjectFunctionsBegin()) - - return projectsApi - .getProjectFunctions(project, signal) - .then(response => { - dispatch(projectsAction.fetchProjectFunctionsSuccess(response?.data.funcs)) - - return response?.data.funcs - }) - .catch(error => { - dispatch(projectsAction.fetchProjectFunctionsFailure(error.message)) - - throw error.message - }) - }, - fetchProjectFunctionsBegin: () => ({ type: FETCH_PROJECT_FUNCTIONS_BEGIN }), - fetchProjectFunctionsFailure: error => ({ - type: FETCH_PROJECT_FUNCTIONS_FAILURE, - payload: error - }), - fetchProjectFunctionsSuccess: functions => ({ - type: FETCH_PROJECT_FUNCTIONS_SUCCESS, - payload: functions - }), - fetchProjectJobs: (project, startTimeFrom, signal) => dispatch => { - dispatch(projectsAction.fetchProjectJobsBegin()) - - const params = { - 'partition-by': 'name', - 'partition-sort-by': 'updated', - 'rows-per-partition': '5', - 'max-partitions': '5', - iter: 'false', - start_time_from: startTimeFrom - } - - return projectsApi - .getJobsAndWorkflows(project, params, signal) - .then(response => { - dispatch( - projectsAction.fetchProjectJobsSuccess( - response?.data.runs.filter(job => job.metadata.iteration === 0) - ) - ) - - return response?.data.runs - }) - .catch(error => { - dispatch(projectsAction.fetchProjectJobsFailure(error.message)) - }) - }, - fetchProjectJobsBegin: () => ({ type: FETCH_PROJECT_JOBS_BEGIN }), - fetchProjectJobsFailure: error => ({ - type: FETCH_PROJECT_JOBS_FAILURE, - payload: error - }), - fetchProjectJobsSuccess: jobs => ({ - type: FETCH_PROJECT_JOBS_SUCCESS, - payload: jobs - }), - fetchProjectModels: (project, signal) => dispatch => { - dispatch(projectsAction.fetchProjectModelsBegin()) - - return projectsApi - .getProjectModels(project, signal) - .then(response => { - dispatch(projectsAction.fetchProjectModelsSuccess(response?.data.artifacts)) - - return response?.data.artifacts - }) - .catch(error => { - dispatch(projectsAction.fetchProjectModelsFailure(error.message)) - - throw error.message - }) - }, - fetchProjectModelsBegin: () => ({ type: FETCH_PROJECT_MODELS_BEGIN }), - fetchProjectModelsFailure: error => ({ - type: FETCH_PROJECT_MODELS_FAILURE, - payload: error - }), - fetchProjectModelsSuccess: models => ({ - type: FETCH_PROJECT_MODELS_SUCCESS, - payload: models - }), - fetchProjectRunningJobs: (project, signal) => dispatch => { - dispatch(projectsAction.fetchProjectRunningJobsBegin()) - - return projectsApi - .getProjectRunningJobs(project, signal) - .then(response => { - dispatch(projectsAction.fetchProjectRunningJobsSuccess(response?.data.runs)) - - return response?.data.runs - }) - .catch(error => { - dispatch(projectsAction.fetchProjectRunningJobsFailure(error.message)) - - throw error.message - }) - }, - fetchProjectRunningJobsBegin: () => ({ - type: FETCH_PROJECT_RUNNING_JOBS_BEGIN - }), - fetchProjectRunningJobsFailure: error => ({ - type: FETCH_PROJECT_RUNNING_JOBS_FAILURE, - payload: error - }), - fetchProjectRunningJobsSuccess: jobs => ({ - type: FETCH_PROJECT_RUNNING_JOBS_SUCCESS, - payload: jobs - }), - fetchProjectScheduledJobs: project => dispatch => { - dispatch(projectsAction.fetchProjectScheduledJobsBegin()) - - return projectsApi - .getProjectScheduledJobs(project) - .then(response => { - dispatch(projectsAction.fetchProjectScheduledJobsSuccess(response.data.schedules)) - - return response.data.schedules - }) - .catch(error => { - dispatch(projectsAction.fetchProjectScheduledJobsFailure(error.message)) - - throw error.message - }) - }, - fetchProjectScheduledJobsBegin: () => ({ - type: FETCH_PROJECT_SCHEDULED_JOBS_BEGIN - }), - fetchProjectScheduledJobsFailure: error => ({ - type: FETCH_PROJECT_SCHEDULED_JOBS_FAILURE, - payload: error - }), - fetchProjectScheduledJobsSuccess: jobs => ({ - type: FETCH_PROJECT_SCHEDULED_JOBS_SUCCESS, - payload: jobs - }), - fetchProjectSecrets: project => dispatch => { - dispatch(projectsAction.fetchProjectSecretsBegin()) - - return projectsApi - .getProjectSecrets(project) - .then(response => { - dispatch(projectsAction.fetchProjectSecretsSuccess(response.data)) - }) - .catch(error => { - dispatch(projectsAction.fetchProjectSecretsFailure(error.message)) - - throw error - }) - }, - fetchProjectSecretsBegin: () => ({ - type: FETCH_PROJECT_SECRETS_BEGIN - }), - fetchProjectSecretsFailure: error => ({ - type: FETCH_PROJECT_SECRETS_FAILURE, - payload: error - }), - fetchProjectSecretsSuccess: secrets => ({ - type: FETCH_PROJECT_SECRETS_SUCCESS, - payload: secrets - }), - fetchProjectSummary: (project, signal) => dispatch => { - dispatch(projectsAction.fetchProjectSummaryBegin()) - - return projectsApi - .getProjectSummary(project, signal) - .then(({ data }) => { - return dispatch(projectsAction.fetchProjectSummarySuccess(parseSummaryData(data))) - }) - .catch(error => { - if (![REQUEST_CANCELED, DEFAULT_ABORT_MSG].includes(error.message)) { - dispatch(projectsAction.fetchProjectSummaryFailure(error.message)) - - throw error - } - }) - }, - fetchProjectSummaryBegin: () => ({ - type: FETCH_PROJECT_SUMMARY_BEGIN - }), - fetchProjectSummaryFailure: error => ({ - type: FETCH_PROJECT_SUMMARY_FAILURE, - payload: error - }), - fetchProjectSummarySuccess: summary => ({ - type: FETCH_PROJECT_SUMMARY_SUCCESS, - payload: summary - }), - fetchProjects: - (params, setRequestErrorMessage = () => {}) => - dispatch => { - dispatch(projectsAction.fetchProjectsBegin()) - setRequestErrorMessage('') - - return projectsApi - .getProjects(params) - .then(response => { - const parsedProjects = parseProjects(response.data.projects) - - dispatch(projectsAction.fetchProjectsSuccess(parsedProjects)) - dispatch( - projectsAction.fetchProjectsNamesSuccess( - parsedProjects - .filter(project => project.status.state === PROJECT_ONLINE_STATUS) - .map(project => project.metadata.name) - ) - ) - - return parsedProjects - }) - .catch(error => { - dispatch(projectsAction.fetchProjectsFailure(error), dispatch) - showErrorNotification( - dispatch, - error, - 'Failed to fetch projects', - null, - null, - setRequestErrorMessage - ) - }) - }, - fetchProjectsBegin: () => ({ type: FETCH_PROJECTS_BEGIN }), - fetchProjectsFailure: error => ({ - type: FETCH_PROJECTS_FAILURE, - payload: error - }), - fetchProjectsNames: () => dispatch => { - dispatch(projectsAction.fetchProjectsNamesBegin()) - - return projectsApi - .getProjects({ format: 'name_only', state: PROJECT_ONLINE_STATUS }) - .then(({ data: { projects } }) => { - dispatch(projectsAction.fetchProjectsNamesSuccess(projects)) - - return projects - }) - .catch(error => { - dispatch(projectsAction.fetchProjectsNamesFailure(error)) - showErrorNotification(dispatch, error, '', 'Failed to fetch projects') - }) - }, - fetchProjectsNamesBegin: () => ({ type: FETCH_PROJECTS_NAMES_BEGIN }), - fetchProjectsNamesFailure: error => ({ - type: FETCH_PROJECTS_NAMES_FAILURE, - payload: error - }), - fetchProjectsNamesSuccess: summary => ({ - type: FETCH_PROJECTS_NAMES_SUCCESS, - payload: summary - }), - fetchProjectsSuccess: projectsList => ({ - type: FETCH_PROJECTS_SUCCESS, - payload: projectsList - }), - fetchProjectsSummary: (signal, refresh) => dispatch => { - dispatch(projectsAction.fetchProjectsSummaryBegin()) - - return projectsApi - .getProjectSummaries(signal) - .then(({ data: { project_summaries } }) => { - if (firstServerErrorTimestamp && refresh) { - firstServerErrorTimestamp = null - - refresh() - } - - const summaryData = parseSummaryData(project_summaries) - - dispatch(projectsAction.fetchProjectsSummarySuccess(summaryData)) - dispatch(projectsAction.setMlrunIsUnhealthy(false)) - dispatch(projectsAction.setMlrunUnhealthyRetrying(false)) - - return summaryData - }) - .catch(err => { - if (mlrunUnhealthyErrors.includes(err.response?.status)) { - if (!firstServerErrorTimestamp) { - firstServerErrorTimestamp = new Date() - - dispatch(projectsAction.setMlrunUnhealthyRetrying(true)) - } - - const threeMinutesPassed = (new Date() - firstServerErrorTimestamp) / 1000 > 180 - - if (!threeMinutesPassed) { - setTimeout(() => { - dispatch(projectsAction.fetchProjectsSummary(signal, refresh)) - }, 3000) - } - - if (threeMinutesPassed) { - dispatch(projectsAction.setMlrunIsUnhealthy(true)) - dispatch(projectsAction.setMlrunUnhealthyRetrying(true)) - } - } - - dispatch(projectsAction.fetchProjectsSummaryFailure(err)) - }) - }, - fetchProjectsSummaryBegin: () => ({ type: FETCH_PROJECTS_SUMMARY_BEGIN }), - fetchProjectsSummaryFailure: error => ({ - type: FETCH_PROJECTS_SUMMARY_FAILURE, - payload: error - }), - fetchProjectsSummarySuccess: summary => ({ - type: FETCH_PROJECTS_SUMMARY_SUCCESS, - payload: summary - }), - fetchProjectWorkflows: project => dispatch => { - dispatch(projectsAction.fetchProjectWorkflowsBegin()) - - return workflowsApi - .getWorkflows(project) - .then(response => { - dispatch(projectsAction.fetchProjectWorkflowsSuccess(response.data.runs)) - - return response.data.runs - }) - .catch(error => { - dispatch(projectsAction.fetchProjectWorkflowsFailure(error.message)) - }) - }, - fetchProjectWorkflowsBegin: () => ({ - type: FETCH_PROJECT_WORKFLOWS_BEGIN - }), - fetchProjectWorkflowsFailure: error => ({ - type: FETCH_PROJECT_WORKFLOWS_FAILURE, - payload: error - }), - fetchProjectWorkflowsSuccess: workflows => ({ - type: FETCH_PROJECT_WORKFLOWS_SUCCESS, - payload: workflows - }), - removeNewProjectError: () => ({ type: REMOVE_NEW_PROJECT_ERROR }), - removeProjectData: () => ({ type: REMOVE_PROJECT_DATA }), - removeProjectSummary: () => ({ type: REMOVE_PROJECT_SUMMARY }), - removeProjects: () => ({ type: REMOVE_PROJECTS }), - setDeletingProjects: data => ({ - type: SET_DELETING_PROJECTS, - payload: data - }), - setMlrunIsUnhealthy: isUnhealthy => ({ - type: SET_MLRUN_IS_UNHEALTHY, - payload: isUnhealthy - }), - setMlrunUnhealthyRetrying: isRetrying => ({ - type: SET_MLRUN_UNHEALTHY_RETRYING, - payload: isRetrying - }), - setJobsMonitoringData: data => ({ - type: SET_JOBS_MONITORING_DATA, - payload: data - }) -} - -export default projectsAction diff --git a/src/common/Breadcrumbs/Breadcrumbs.js b/src/common/Breadcrumbs/Breadcrumbs.js index 86933c50d5..eaf36cef36 100755 --- a/src/common/Breadcrumbs/Breadcrumbs.js +++ b/src/common/Breadcrumbs/Breadcrumbs.js @@ -27,8 +27,8 @@ import BreadcrumbsStep from './BreadcrumbsStep/BreadcrumbsStep' import { useMode } from '../../hooks/mode.hook' import { generateMlrunScreens, generateTabsList } from './breadcrumbs.util' import { PROJECTS_PAGE_PATH } from '../../constants' -import projectsAction from '../../actions/projects' import { generateProjectsList } from '../../utils/projects' +import { fetchProjects } from '../../reducers/projectReducer' import './breadcrumbs.scss' @@ -83,12 +83,8 @@ const Breadcrumbs = ({ onClick = () => {} }) => { }, [location.pathname, params.projectName, mlrunScreens, projectTabs]) useEffect(() => { - if ( - projectsList.length === 0 && - location.pathname !== '/projects' && - !location.pathname.startsWith('/projects/*') - ) { - dispatch(projectsAction.fetchProjects({ format: 'minimal' })) + if (projectsList.length === 0 && location.pathname !== '/projects') { + dispatch(fetchProjects({ params: { format: 'minimal' } })) } }, [dispatch, location.pathname, projectsList.length]) diff --git a/src/common/TargetPath/targetPath.util.js b/src/common/TargetPath/targetPath.util.js index 4d0341e8a7..e79fd5a6f1 100644 --- a/src/common/TargetPath/targetPath.util.js +++ b/src/common/TargetPath/targetPath.util.js @@ -34,10 +34,10 @@ import { V3IO_INPUT_PATH_SCHEME } from '../../constants' import { getArtifactReference, getFeatureReference, getParsedResource } from '../../utils/resources' -import projectAction from '../../actions/projects' import { showErrorNotification } from '../../utils/notifications.util' import { fetchArtifact, fetchArtifacts } from '../../reducers/artifactsReducer' import { fetchFeatureVector, fetchFeatureVectors } from '../../reducers/featureStoreReducer' +import { fetchProjectsNames } from '../../reducers/projectReducer' import { isCommunityEdition } from '../../utils/helper' const targetPathRegex = @@ -333,12 +333,15 @@ export const generateArtifactsReferencesList = artifacts => { } export const getProjectsNames = (dispatch, setDataInputState, projectName) => { - dispatch(projectAction.fetchProjectsNames()).then(result => { - setDataInputState(prev => ({ - ...prev, - projects: generateProjectsList(result ?? [], projectName) - })) - }) + dispatch(fetchProjectsNames()) + .unwrap() + .then(result => { + setDataInputState(prev => ({ + ...prev, + projects: generateProjectsList(result ?? [], projectName) + })) + }) + .catch(() => {}) } export const getArtifacts = (dispatch, project, storePathType, setDataInputState) => { diff --git a/src/components/Alerts/Alerts.js b/src/components/Alerts/Alerts.js index 8354262b19..f569b55ce9 100644 --- a/src/components/Alerts/Alerts.js +++ b/src/components/Alerts/Alerts.js @@ -37,13 +37,12 @@ import { checkForSelectedAlert } from './alerts.util' import { getJobLogs } from '../../utils/getJobLogs.util' -import projectsAction from '../../actions/projects' import { useAlertsPageData } from '../../hooks/useAlertsPageData' import { useFiltersFromSearchParams } from '../../hooks/useFiltersFromSearchParams.hook' +import { removeProjects } from '../../reducers/projectReducer' const Alerts = () => { const [selectedAlert, setSelectedAlert] = useState({}) - const [, setProjectsRequestErrorMessage] = useState('') const alertsStore = useSelector(state => state.alertsStore) const filtersStore = useSelector(store => store.filtersStore) const dispatch = useDispatch() @@ -85,14 +84,9 @@ const Alerts = () => { return paginatedAlerts.map(alert => createAlertRowData(alert, isCrossProjects)) }, [isCrossProjects, paginatedAlerts]) - const fetchMinimalProjects = useCallback(() => { - dispatch(projectsAction.fetchProjects({ format: 'minimal' }, setProjectsRequestErrorMessage)) - }, [dispatch]) - useEffect(() => { - dispatch(projectsAction.removeProjects()) - isCrossProjects && fetchMinimalProjects() - }, [dispatch, isCrossProjects, fetchMinimalProjects]) + dispatch(removeProjects()) + }, [dispatch, isCrossProjects]) const handleCancel = () => { setSelectedAlert({}) diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelDataSource/FeatureSetsPanelDataSource.js b/src/components/FeatureSetsPanel/FeatureSetsPanelDataSource/FeatureSetsPanelDataSource.js index b51b9c6ee1..096fb764e4 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelDataSource/FeatureSetsPanelDataSource.js +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelDataSource/FeatureSetsPanelDataSource.js @@ -18,16 +18,14 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import React, { useCallback, useState } from 'react' -import { connect, useDispatch, useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import PropTypes from 'prop-types' import { isEmpty } from 'lodash' import FeatureSetsPanelDataSourceView from './FeatureSetsPanelDataSourceView' -import projectsAction from '../../../actions/projects' import { MLRUN_STORAGE_INPUT_PATH_SCHEME } from '../../../constants' - import { CSV, PARQUET } from './featureSetsPanelDataSource.util' import { isUrlInputValid } from '../UrlPath.utils' import { @@ -175,6 +173,4 @@ FeatureSetsPanelDataSource.propTypes = { validation: PropTypes.shape({}).isRequired } -export default connect(projectStore => ({ ...projectStore }), { - ...projectsAction -})(FeatureSetsPanelDataSource) +export default FeatureSetsPanelDataSource diff --git a/src/components/FeatureSetsPanel/UrlPath.utils.js b/src/components/FeatureSetsPanel/UrlPath.utils.js index f4b00d8f6d..f560e6c2fa 100644 --- a/src/components/FeatureSetsPanel/UrlPath.utils.js +++ b/src/components/FeatureSetsPanel/UrlPath.utils.js @@ -30,7 +30,6 @@ import { S3_INPUT_PATH_SCHEME, V3IO_INPUT_PATH_SCHEME } from '../../constants' -import projectsAction from '../../actions/projects' import { generateArtifactsList, generateArtifactsReferencesList, @@ -38,6 +37,7 @@ import { } from '../../utils/panelPathScheme' import { showErrorNotification } from '../../utils/notifications.util' import { fetchArtifact, fetchArtifacts } from '../../reducers/artifactsReducer' +import { fetchProjectsNames } from '../../reducers/projectReducer' import { isCommunityEdition } from '../../utils/helper' export const CSV = 'csv' @@ -156,9 +156,12 @@ export const isUrlInputValid = (pathInputType, pathInputValue, dataSourceKind) = } export const getProjectsNames = (dispatch, setProjects, project) => { - dispatch(projectsAction.fetchProjectsNames()).then(projects => { - return setProjects(generateProjectsList(projects ?? [], project)) - }) + dispatch(fetchProjectsNames()) + .unwrap() + .then(projects => { + return setProjects(generateProjectsList(projects ?? [], project)) + }) + .catch(() => {}) } export const getArtifacts = (dispatch, project, projectItemType, setArtifacts) => { diff --git a/src/components/JobWizard/JobWizard.js b/src/components/JobWizard/JobWizard.js index 5e682e366c..7726976aca 100644 --- a/src/components/JobWizard/JobWizard.js +++ b/src/components/JobWizard/JobWizard.js @@ -63,7 +63,6 @@ import { getSaveJobErrorMsg } from './JobWizard.util' import functionsActions from '../../actions/functions' -import projectsAction from '../../actions/projects' import { FUNCTIONS_SELECTION_FUNCTIONS_TAB } from './JobWizardSteps/JobWizardFunctionSelection/jobWizardFunctionSelection.util' import { JOB_WIZARD_MODE } from '../../types' import { MODAL_MAX } from 'igz-controls/constants' @@ -73,6 +72,7 @@ import { setNotification } from '../../reducers/notificationReducer' import { showErrorNotification } from '../../utils/notifications.util' import { useModalBlockHistory } from '../../hooks/useModalBlockHistory.hook' import { editJob, removeJobFunction, runNewJob } from '../../reducers/jobReducer' +import { fetchProject } from '../../reducers/projectReducer' import './jobWizard.scss' @@ -137,7 +137,15 @@ const JobWizard = ({ useEffect(() => { if (!isEditMode) { - dispatch(projectsAction.fetchProject(params.projectName, { format: 'minimal' })) + dispatch( + fetchProject({ + project: params.projectName, + params: { + format: 'minimal' + } + }) + ) + .unwrap() .then(response => setCurrentProject(response?.data)) .catch(error => { showErrorNotification(dispatch, error, 'The project failed to load') @@ -565,7 +573,6 @@ export default connect( jobsStore }), { - ...functionsActions, - ...projectsAction + ...functionsActions } )(JobWizard) diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js index a104f1a900..95447c8429 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js +++ b/src/components/JobWizard/JobWizardSteps/JobWizardFunctionSelection/JobWizardFunctionSelection.js @@ -32,7 +32,6 @@ import Search from '../../../../common/Search/Search' import { FormOnChange, FormSelect } from 'igz-controls/components' import functionsActions from '../../../../actions/functions' -import projectsAction from '../../../../actions/projects' import { FILTER_MENU_MODAL, FUNCTION_RUN_KINDS, @@ -54,6 +53,7 @@ import { } from './jobWizardFunctionSelection.util' import './jobWizardFunctionSelection.scss' +import { fetchProjectsNames } from '../../../../reducers/projectReducer' const JobWizardFunctionSelection = ({ activeTab, @@ -95,10 +95,16 @@ const JobWizardFunctionSelection = ({ const functionsContainerRef = useRef(null) const hubFunctionLoadedRef = useRef(false) - const jobWizardFiltersValues = useSelector(store => store.filtersStore[FILTER_MENU_MODAL]?.[JOB_WIZARD_FILTERS]?.values ?? hubFiltersInitialValues) + const jobWizardFiltersValues = useSelector( + store => + store.filtersStore[FILTER_MENU_MODAL]?.[JOB_WIZARD_FILTERS]?.values ?? hubFiltersInitialValues + ) const { loading } = useSelector(store => store.functionsStore) - const filtersStoreHubCategories = useMemo(() => jobWizardFiltersValues[HUB_CATEGORIES_FILTER], [jobWizardFiltersValues]) + const filtersStoreHubCategories = useMemo( + () => jobWizardFiltersValues[HUB_CATEGORIES_FILTER], + [jobWizardFiltersValues] + ) const dispatch = useDispatch() @@ -132,9 +138,12 @@ const JobWizardFunctionSelection = ({ useEffect(() => { if (projects.length === 0) { - dispatch(projectsAction.fetchProjectsNames()).then(projects => { - setProjects(generateProjectsList(projects, params.projectName)) - }) + dispatch(fetchProjectsNames()) + .unwrap() + .then(projects => { + setProjects(generateProjectsList(projects, params.projectName)) + }) + .catch(() => {}) } }, [dispatch, params.projectName, projects.length]) diff --git a/src/components/Project/ProjectMonitor.js b/src/components/Project/ProjectMonitor.js index 2cab07f292..7865a97830 100644 --- a/src/components/Project/ProjectMonitor.js +++ b/src/components/Project/ProjectMonitor.js @@ -28,7 +28,6 @@ import RegisterModelModal from '../../elements/RegisterModelModal/RegisterModelM import functionsActions from '../../actions/functions' import nuclioAction from '../../actions/nuclio' -import projectsAction from '../../actions/projects' import { DATASET_TYPE, DATASETS_TAB, @@ -46,19 +45,20 @@ import { useMode } from '../../hooks/mode.hook' import { showErrorNotification } from '../../utils/notifications.util' import { useNuclioMode } from '../../hooks/nuclioMode.hook' import { removeNewFeatureSet } from '../../reducers/featureStoreReducer' - -const ProjectMonitor = ({ - fetchNuclioV3ioStreams, +import { fetchProject, fetchProjectFunctions, fetchProjectSummary, + removeProjectData, + removeProjectSummary +} from '../../reducers/projectReducer' + +const ProjectMonitor = ({ + fetchNuclioV3ioStreams, functionsStore, nuclioStore, - projectStore, removeFunctionsError, removeNewFunction, - removeProjectData, - removeProjectSummary, removeV3ioStreams }) => { const [createFeatureSetPanelIsOpen, setCreateFeatureSetPanelIsOpen] = useState(false) @@ -74,6 +74,7 @@ const ProjectMonitor = ({ const projectSummariesAbortControllerRef = useRef(new AbortController()) const v3ioStreamsAbortControllerRef = useRef(new AbortController()) const frontendSpec = useSelector(state => state.appStore.frontendSpec) + const projectStore = useSelector(store => store.projectStore) const registerArtifactLink = useCallback( artifactKind => @@ -132,16 +133,27 @@ const ProjectMonitor = ({ projectSummariesAbortControllerRef.current = new AbortController() Promise.all([ - fetchProject(params.projectName, {}, projectAbortControllerRef.current.signal), - fetchProjectSummary(params.projectName, projectSummariesAbortControllerRef.current.signal) + dispatch( + fetchProject({ + project: params.projectName, + params: {}, + signal: projectAbortControllerRef.current.signal + }) + ).unwrap(), + dispatch( + fetchProjectSummary({ + project: params.projectName, + signal: projectSummariesAbortControllerRef.current.signal + }) + ).unwrap() ]).catch(error => { handleFetchProjectError(error, navigate, setConfirmData, dispatch) }) - }, [dispatch, fetchProject, fetchProjectSummary, navigate, params.projectName]) + }, [dispatch, navigate, params.projectName]) const resetProjectData = useCallback(() => { - removeProjectData() - }, [removeProjectData]) + dispatch(removeProjectData()) + }, [dispatch]) useEffect(() => { return () => { @@ -156,9 +168,9 @@ const ProjectMonitor = ({ return () => { resetProjectData() - removeProjectSummary() + dispatch(removeProjectSummary()) } - }, [fetchProjectDataAndSummary, removeProjectSummary, resetProjectData]) + }, [dispatch, fetchProjectDataAndSummary, resetProjectData]) useEffect(() => { if (nuclioStreamsAreEnabled && !isNuclioModeDisabled) { @@ -215,17 +227,19 @@ const ProjectMonitor = ({ setShowFunctionsPanel(false) removeNewFunction() - const funcs = await fetchProjectFunctions(params.projectName).catch(error => { - dispatch( - setNotification({ - status: 200, - id: Math.random(), - message: 'Function was deployed' - }) - ) - - showErrorNotification(dispatch, error, '', 'Failed to fetch functions') - }) + const funcs = await dispatch(fetchProjectFunctions({ project: params.projectName })) + .unwrap() + .catch(error => { + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: 'Function was deployed' + }) + ) + + showErrorNotification(dispatch, error, '', 'Failed to fetch functions') + }) if (!isEmpty(funcs)) { const currentItem = funcs.find(func => { @@ -252,10 +266,12 @@ const ProjectMonitor = ({ setShowFunctionsPanel(false) removeNewFunction() - const funcs = await fetchProjectFunctions(params.projectName).catch(error => { - showErrorNotification(dispatch, deployError, '', 'Failed to deploy the function') - showErrorNotification(dispatch, error, '', 'Failed to fetch functions') - }) + const funcs = await dispatch(fetchProjectFunctions({ project: params.projectName })) + .unwrap() + .catch(error => { + showErrorNotification(dispatch, deployError, '', 'Failed to deploy the function') + showErrorNotification(dispatch, error, '', 'Failed to fetch functions') + }) if (!isEmpty(funcs)) { const currentItem = funcs.find(func => { @@ -273,8 +289,8 @@ const ProjectMonitor = ({ const handleLaunchIDE = useCallback(() => {}, []) const handleRefresh = () => { - removeProjectData() - removeProjectSummary() + dispatch(removeProjectData()) + dispatch(removeProjectSummary()) fetchProjectDataAndSummary() if (nuclioStreamsAreEnabled && !isNuclioModeDisabled) { @@ -315,14 +331,12 @@ const ProjectMonitor = ({ } export default connect( - ({ functionsStore, nuclioStore, projectStore }) => ({ + ({ functionsStore, nuclioStore }) => ({ functionsStore, - nuclioStore, - projectStore + nuclioStore }), { ...functionsActions, - ...projectsAction, ...nuclioAction } )(ProjectMonitor) diff --git a/src/components/Project/ProjectOverview/ProjectOverview.js b/src/components/Project/ProjectOverview/ProjectOverview.js index 05717a021d..71caf3490e 100644 --- a/src/components/Project/ProjectOverview/ProjectOverview.js +++ b/src/components/Project/ProjectOverview/ProjectOverview.js @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import React, { useEffect, useMemo, useState } from 'react' -import { connect, useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { isEmpty } from 'lodash' import { useNavigate, useParams } from 'react-router-dom' @@ -30,21 +30,21 @@ import ProjectDetailsHeader from '../../../common/ProjectDetailsHeader/ProjectDe import ProjectOverviewTableRow from '../ProjectOverviewTableRow/ProjectOverviewTableRow' import { ConfirmDialog } from 'igz-controls/components' -import projectActions from '../../../actions/projects' - import { handleClick, getInitialCards } from './ProjectOverview.util' import { handleFetchProjectError } from '../project.utils' import { openPopUp } from 'igz-controls/utils/common.util' import { useMode } from '../../../hooks/mode.hook' +import { fetchProject } from '../../../reducers/projectReducer' import './ProjectOverview.scss' -const ProjectOverview = ({ fetchProject, project }) => { +const ProjectOverview = () => { const [confirmData, setConfirmData] = useState(null) const params = useParams() const navigate = useNavigate() const dispatch = useDispatch() const { isDemoMode } = useMode() + const project = useSelector(store => store.projectStore.project) const cards = useMemo(() => { return params.projectName ? getInitialCards(params, navigate, isDemoMode) : {} @@ -53,10 +53,10 @@ const ProjectOverview = ({ fetchProject, project }) => { const handlePathExecution = handleClick(navigate, openPopUp) useEffect(() => { - fetchProject(params.projectName).catch(error => - handleFetchProjectError(error, navigate, setConfirmData, dispatch) - ) - }, [dispatch, fetchProject, navigate, params.projectName]) + dispatch(fetchProject({ project: params.projectName })) + .unwrap() + .catch(error => handleFetchProjectError(error, navigate, setConfirmData, dispatch)) + }, [dispatch, navigate, params.projectName]) if (project.error) { return ( @@ -135,13 +135,4 @@ const ProjectOverview = ({ fetchProject, project }) => { ) } -const actionCreators = { - fetchProject: projectActions.fetchProject -} - -export default connect( - ({ projectStore }) => ({ - project: projectStore.project - }), - { ...actionCreators } -)(ProjectOverview) +export default ProjectOverview diff --git a/src/components/ProjectSettings/ProjectSettings.js b/src/components/ProjectSettings/ProjectSettings.js index 798e0f8dea..1e3202b083 100644 --- a/src/components/ProjectSettings/ProjectSettings.js +++ b/src/components/ProjectSettings/ProjectSettings.js @@ -40,7 +40,6 @@ import { validTabs } from './projectSettings.util' import { onDeleteProject } from '../ProjectsPage/projects.util' -import projectsAction from '../../actions/projects' import { initialMembersState, membersActions, @@ -50,6 +49,7 @@ import projectsIguazioApi from '../../api/projects-iguazio-api' 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 './projectSettings.scss' @@ -244,7 +244,7 @@ const ProjectSettings = () => { }, []) const fetchMinimalProjects = useCallback(() => { - dispatch(projectsAction.fetchProjects({ format: 'minimal' })) + dispatch(fetchProjects({ params: { format: 'minimal' } })) }, [dispatch]) useEffect(() => { diff --git a/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.js b/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.js index eed002487a..69631a47c2 100644 --- a/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.js +++ b/src/components/ProjectsJobsMonitoring/ProjectsJobsMonitoring.js @@ -50,7 +50,7 @@ import { parseWorkflowsQueryParamsCallback } from '../../utils/jobs.util' import { useJobsPageData } from '../../hooks/useJobsPageData' -import projectsAction from '../../actions/projects' +import { fetchProjects } from '../../reducers/projectReducer' import './projectsJobsMonitoring.scss' @@ -144,7 +144,12 @@ const ProjectsJobsMonitoring = () => { } const fetchMinimalProjects = useCallback(() => { - dispatch(projectsAction.fetchProjects({ format: 'minimal' }, setProjectsRequestErrorMessage)) + dispatch( + fetchProjects({ + params: { format: 'minimal' }, + setRequestErrorMessage: setProjectsRequestErrorMessage + }) + ) }, [dispatch]) useEffect(() => { diff --git a/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.js b/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.js index ab7a56e0c9..c63aaaca8c 100644 --- a/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.js +++ b/src/components/ProjectsPage/CreateProjectDialog/CreateProjectDialog.js @@ -21,7 +21,7 @@ import React from 'react' import PropTypes from 'prop-types' import arrayMutators from 'final-form-arrays' import { Form } from 'react-final-form' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { createForm } from 'final-form' import ErrorMessage from '../../../common/ErrorMessage/ErrorMessage' @@ -35,14 +35,11 @@ import { getInternalLabelsValidationRule } from 'igz-controls/utils/validation.util' import { setFieldState, isSubmitDisabled } from 'igz-controls/utils/form.util' +import { removeNewProjectError } from '../../../reducers/projectReducer' import './createProjectDialog.scss' -const CreateProjectDialog = ({ - closeNewProjectPopUp, - handleCreateProject, - removeNewProjectError -}) => { +const CreateProjectDialog = ({ closeNewProjectPopUp, handleCreateProject }) => { const projectStore = useSelector(store => store.projectStore) const frontendSpec = useSelector(store => store.appStore.frontendSpec) const initialValues = { @@ -57,6 +54,7 @@ const CreateProjectDialog = ({ onSubmit: handleCreateProject }) ) + const dispatch = useDispatch() return ( { if (projectStore.newProject.error) { - removeNewProjectError() + dispatch(removeNewProjectError()) } }} message={projectStore.newProject.error} @@ -138,8 +136,7 @@ const CreateProjectDialog = ({ CreateProjectDialog.propTypes = { closeNewProjectPopUp: PropTypes.func.isRequired, - handleCreateProject: PropTypes.func.isRequired, - removeNewProjectError: PropTypes.func.isRequired + handleCreateProject: PropTypes.func.isRequired } export default CreateProjectDialog diff --git a/src/components/ProjectsPage/Projects.js b/src/components/ProjectsPage/Projects.js index 049f83e0d9..69c50828ae 100644 --- a/src/components/ProjectsPage/Projects.js +++ b/src/components/ProjectsPage/Projects.js @@ -35,7 +35,6 @@ import { projectsSortOptions } from './projects.util' import nuclioActions from '../../actions/nuclio' -import projectsAction from '../../actions/projects' import { BG_TASK_RUNNING } from '../../utils/poll.util' import { onDeleteProject } from './projects.util' import { PROJECT_ONLINE_STATUS } from '../../constants' @@ -47,6 +46,17 @@ import { setNotification } from '../../reducers/notificationReducer' import { showErrorNotification } from '../../utils/notifications.util' import { useMode } from '../../hooks/mode.hook' import { useNuclioMode } from '../../hooks/nuclioMode.hook' +import { + changeProjectState, + createNewProject, + fetchProject, + fetchProjects, + fetchProjectsNames, + fetchProjectsSummary, + removeNewProjectError, + removeProjects, + setDeletingProjects +} from '../../reducers/projectReducer' const Projects = () => { const [actionsMenu, setActionsMenu] = useState({}) @@ -78,7 +88,12 @@ const Projects = () => { }, [projectStore.deletingProjects]) const fetchMinimalProjects = useCallback(() => { - dispatch(projectsAction.fetchProjects({ format: 'minimal' }, setProjectsRequestErrorMessage)) + dispatch( + fetchProjects({ + params: { format: 'minimal' }, + setRequestErrorMessage: setProjectsRequestErrorMessage + }) + ) }, [dispatch]) const isValidProjectState = useCallback( @@ -117,16 +132,19 @@ const Projects = () => { dispatch(nuclioActions.fetchNuclioFunctions()) } - dispatch(projectsAction.removeProjects()) + dispatch(removeProjects()) fetchMinimalProjects() dispatch( - projectsAction.fetchProjectsSummary(abortControllerRef.current.signal, refreshProjects) - ).then(result => { - if (result) { - generateMonitoringCounters(result, dispatch) - generateAlerts(result, dispatch) - } - }) + fetchProjectsSummary({ signal: abortControllerRef.current.signal, refresh: refreshProjects }) + ) + .unwrap() + .then(result => { + if (result) { + generateMonitoringCounters(result, dispatch) + generateAlerts(result, dispatch) + } + }) + .catch(() => {}) if (!isEmpty(deletingProjectsRef.current)) { dispatch(fetchBackgroundTasks({})) @@ -154,7 +172,7 @@ const Projects = () => { if (!isEmpty(newDeletingProjects)) { pollDeletingProjects(terminatePollRef, newDeletingProjects, refreshProjects, dispatch) } else { - dispatch(projectsAction.setDeletingProjects({})) + dispatch(setDeletingProjects({})) } }) .catch(error => { @@ -185,7 +203,8 @@ const Projects = () => { const handleArchiveProject = useCallback( project => { - dispatch(projectsAction.changeProjectState(project.metadata.name, 'archived')) + dispatch(changeProjectState({ project: project.metadata.name, status: 'archived' })) + .unwrap() .then(() => { fetchMinimalProjects() }) @@ -207,10 +226,12 @@ const Projects = () => { const handleUnarchiveProject = useCallback( project => { dispatch( - projectsAction.changeProjectState(project.metadata.name, PROJECT_ONLINE_STATUS) - ).then(() => { - fetchMinimalProjects() - }) + changeProjectState({ project: project.metadata.name, status: PROJECT_ONLINE_STATUS }) + ) + .unwrap() + .then(() => { + fetchMinimalProjects() + }) }, [dispatch, fetchMinimalProjects] ) @@ -248,7 +269,8 @@ const Projects = () => { const exportYaml = useCallback( projectMinimal => { if (projectMinimal?.metadata?.name) { - dispatch(projectsAction.fetchProject(projectMinimal.metadata.name)) + dispatch(fetchProject({ project: projectMinimal.metadata.name })) + .unwrap() .then(response => { var blob = new Blob([yaml.dump(response?.data, { lineWidth: -1 })]) @@ -268,7 +290,8 @@ const Projects = () => { projectMinimal => { const yamlByteSizeLimit = 2000000 if (projectMinimal?.metadata?.name) { - dispatch(projectsAction.fetchProject(projectMinimal.metadata.name)) + dispatch(fetchProject({ project: projectMinimal.metadata.name })) + .unwrap() .then(response => { if (response.headers.get('content-length') > yamlByteSizeLimit) { openPopUp(ConfirmDialog, { @@ -297,11 +320,6 @@ const Projects = () => { [convertToYaml, dispatch, exportYaml] ) - const removeNewProjectError = useCallback( - () => dispatch(projectsAction.removeNewProjectError()), - [dispatch] - ) - const handleOnDeleteProject = useCallback( project => onDeleteProject( @@ -366,41 +384,46 @@ const Projects = () => { const closeNewProjectPopUp = useCallback(() => { if (projectStore.newProject.error) { - removeNewProjectError() + dispatch(removeNewProjectError()) } setCreateProject(false) - }, [projectStore.newProject.error, removeNewProjectError]) + }, [dispatch, projectStore.newProject.error]) const handleCreateProject = values => { dispatch( - projectsAction.createNewProject({ - metadata: { - name: values.name, - labels: - values.labels?.reduce((acc, labelData) => { - acc[labelData.key] = labelData.value - return acc - }, {}) ?? {} - }, - spec: { - description: values.description + createNewProject({ + postData: { + metadata: { + name: values.name, + labels: + values.labels?.reduce((acc, labelData) => { + acc[labelData.key] = labelData.value + return acc + }, {}) ?? {} + }, + spec: { + description: values.description + } } }) - ).then(result => { - if (result) { - setCreateProject(false) - refreshProjects() - dispatch(projectsAction.fetchProjectsNames()) - dispatch( - setNotification({ - status: 200, - id: Math.random(), - message: `Project "${result.metadata?.name}" was created successfully` - }) - ) - } - }) + ) + .unwrap() + .then(result => { + if (result) { + setCreateProject(false) + refreshProjects() + dispatch(fetchProjectsNames()) + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: `Project "${result.metadata?.name}" was created successfully` + }) + ) + } + }) + .catch(() => {}) } return ( @@ -422,7 +445,6 @@ const Projects = () => { projectsRequestErrorMessage={projectsRequestErrorMessage} projectStore={projectStore} refreshProjects={refreshProjects} - removeNewProjectError={removeNewProjectError} selectedProjectsState={selectedProjectsState} setCreateProject={setCreateProject} setFilterMatches={setFilterMatches} diff --git a/src/components/ProjectsPage/ProjectsView.js b/src/components/ProjectsPage/ProjectsView.js index 09417a1b01..acc153a8bf 100644 --- a/src/components/ProjectsPage/ProjectsView.js +++ b/src/components/ProjectsPage/ProjectsView.js @@ -59,7 +59,6 @@ const ProjectsView = ({ projectsRequestErrorMessage, projectStore, refreshProjects, - removeNewProjectError, selectedProjectsState, setCreateProject, setFilterMatches, @@ -85,7 +84,6 @@ const ProjectsView = ({ )} {confirmData && ( @@ -217,7 +215,6 @@ ProjectsView.propTypes = { handleSelectSortOption: PropTypes.func.isRequired, projectsRequestErrorMessage: PropTypes.string.isRequired, refreshProjects: PropTypes.func.isRequired, - removeNewProjectError: PropTypes.func.isRequired, selectedProjectsState: PropTypes.string.isRequired, setCreateProject: PropTypes.func.isRequired, setFilterMatches: PropTypes.func.isRequired, diff --git a/src/components/ProjectsPage/projects.util.js b/src/components/ProjectsPage/projects.util.js index ad937aa954..199df0fd1a 100644 --- a/src/components/ProjectsPage/projects.util.js +++ b/src/components/ProjectsPage/projects.util.js @@ -32,17 +32,22 @@ import { isBackgroundTaskRunning, pollTask } from '../../utils/poll.util' -import { PROJECT_ONLINE_STATUS, SET_PROJECT_TOTAL_ALERTS } from '../../constants' +import { PROJECT_ONLINE_STATUS } from '../../constants' import { DANGER_BUTTON, FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' import { setNotification } from '../../reducers/notificationReducer' import { showErrorNotification } from '../../utils/notifications.util' -import projectsAction from '../../actions/projects' import { ReactComponent as ArchiveIcon } from 'igz-controls/images/archive-icon.svg' import { ReactComponent as Delete } from 'igz-controls/images/delete.svg' import { ReactComponent as DownloadIcon } from 'igz-controls/images/ml-download.svg' import { ReactComponent as UnarchiveIcon } from 'igz-controls/images/unarchive-icon.svg' import { ReactComponent as Yaml } from 'igz-controls/images/yaml.svg' +import { + deleteProject, + setDeletingProjects, + setJobsMonitoringData, + setProjectTotalAlerts +} from '../../reducers/projectReducer' export const mlrunUnhealthyErrors = [ BAD_GATEWAY_ERROR_STATUS_CODE, @@ -235,7 +240,7 @@ export const pollDeletingProjects = (terminatePollRef, deletingProjects, refresh } }) - dispatch(projectsAction.setDeletingProjects(omit(deletingProjects, tasksToExclude))) + dispatch(setDeletingProjects(omit(deletingProjects, tasksToExclude))) refresh() } @@ -260,10 +265,7 @@ export const generateAlerts = (data, dispatch) => { (project.other_alerts_count || 0) }) - dispatch({ - type: SET_PROJECT_TOTAL_ALERTS, - payload: projectAlerts - }) + dispatch(setProjectTotalAlerts(projectAlerts)) } export const generateMonitoringCounters = (data, dispatch) => { @@ -325,7 +327,7 @@ export const generateMonitoringCounters = (data, dispatch) => { monitoringCounters.alerts.application }) - dispatch(projectsAction.setJobsMonitoringData(monitoringCounters)) + dispatch(setJobsMonitoringData(monitoringCounters)) } export const onDeleteProject = (project, setConfirmData, ...args) => { @@ -355,8 +357,9 @@ export const handleDeleteProject = ( ) => { setConfirmData && setConfirmData(null) - dispatch(projectsAction.deleteProject(project.metadata.name, deleteNonEmpty)) - .then(response => { + dispatch(deleteProject({ projectName: project.metadata.name, deleteNonEmpty })) + .unwrap() + .then(({ response }) => { if (isBackgroundTaskRunning(response)) { dispatch( setNotification({ @@ -371,7 +374,8 @@ export const handleDeleteProject = ( [response.data.metadata.name]: last(response.data.metadata.kind.split('.')) } - dispatch(projectsAction.setDeletingProjects(newDeletingProjects)) + dispatch(setDeletingProjects(newDeletingProjects)) + if (refreshProjects) { pollDeletingProjects(terminatePollRef, newDeletingProjects, refreshProjects, dispatch) } @@ -393,7 +397,7 @@ export const handleDeleteProject = ( } } }) - .catch(error => { + .catch(({ error }) => { handleDeleteProjectError( error, handleDeleteProject, diff --git a/src/constants.js b/src/constants.js index e194e06b2f..fa630fd755 100644 --- a/src/constants.js +++ b/src/constants.js @@ -155,12 +155,6 @@ export const FETCH_JOB_PODS_FAILURE = 'FETCH_JOB_PODS_FAILURE' export const FETCH_JOB_PODS_SUCCESS = 'FETCH_JOB_PODS_SUCCESS' export const JOB_DEFAULT_OUTPUT_PATH = 'v3io:///projects/{{run.project}}/artifacts/{{run.uid}}' export const REMOVE_JOB_PODS = 'REMOVE_JOB_PODS' -export const SET_DELETING_PROJECTS = 'SET_DELETING_PROJECTS' -export const SET_PROJECT_TOTAL_ALERTS = 'SET_PROJECT_TOTAL_ALERTS' -export const SET_JOBS_DATA = 'SET_JOBS_DATA' -export const SET_JOBS_MONITORING_DATA = 'SET_JOBS_MONITORING_DATA' -export const SET_MLRUN_IS_UNHEALTHY = 'SET_MLRUN_IS_UNHEALTHY' -export const SET_MLRUN_UNHEALTHY_RETRYING = 'SET_MLRUN_UNHEALTHY_RETRYING' export const FUNCTION_SELECTION_STEP = 'functionSelection' export const RUN_DETAILS_STEP = 'runDetails' @@ -298,70 +292,6 @@ export const FUNCTION_FILTERS = 'FUNCTION_FILTERS' export const ARTIFACTS_TAB = 'artifacts' export const ARTIFACT_PREVIEW_TABLE_ROW_LIMIT = 100 -/*=========== PROJECTS =============*/ - -export const CHANGE_PROJECT_STATE_BEGIN = 'CHANGE_PROJECT_STATE_BEGIN' -export const CHANGE_PROJECT_STATE_FAILURE = 'CHANGE_PROJECT_STATE_FAILURE' -export const CHANGE_PROJECT_STATE_SUCCESS = 'CHANGE_PROJECT_STATE_SUCCESS' -export const CREATE_PROJECT_BEGIN = 'CREATE_PROJECT_BEGIN' -export const CREATE_PROJECT_FAILURE = 'CREATE_PROJECT_FAILURE' -export const CREATE_PROJECT_SUCCESS = 'CREATE_PROJECT_SUCCESS' -export const DELETE_PROJECT_BEGIN = 'DELETE_PROJECT_BEGIN' -export const DELETE_PROJECT_FAILURE = 'DELETE_PROJECT_FAILURE' -export const DELETE_PROJECT_SUCCESS = 'DELETE_PROJECT_SUCCESS' -export const FETCH_PROJECT_BEGIN = 'FETCH_PROJECT_BEGIN' -export const FETCH_PROJECT_DATASETS_BEGIN = 'FETCH_PROJECT_DATASETS_BEGIN' -export const FETCH_PROJECT_DATASETS_FAILURE = 'FETCH_PROJECT_DATASETS_FAILURE' -export const FETCH_PROJECT_SUMMARY_BEGIN = 'FETCH_PROJECT_SUMMARY_BEGIN' -export const FETCH_PROJECT_SUMMARY_FAILURE = 'FETCH_PROJECT_SUMMARY_FAILURE' -export const FETCH_PROJECT_SUMMARY_SUCCESS = 'FETCH_PROJECT_SUMMARY_SUCCESS' -export const FETCH_PROJECT_DATASETS_SUCCESS = 'FETCH_PROJECT_DATASETS_SUCCESS' -export const FETCH_PROJECT_FAILED_JOBS_BEGIN = 'FETCH_PROJECT_FAILED_JOBS_BEGIN' -export const FETCH_PROJECT_FAILED_JOBS_FAILURE = 'FETCH_PROJECT_FAILED_JOBS_FAILURE' -export const FETCH_PROJECT_FAILED_JOBS_SUCCESS = 'FETCH_PROJECT_FAILED_JOBS_SUCCESS' -export const FETCH_PROJECT_FAILURE = 'FETCH_PROJECT_FAILURE' -export const FETCH_PROJECT_FEATURE_SETS_BEGIN = 'FETCH_PROJECT_FEATURE_SETS_BEGIN' -export const FETCH_PROJECT_FEATURE_SETS_FAILURE = 'FETCH_PROJECT_FEATURE_SETS_FAILURE' -export const FETCH_PROJECT_FEATURE_SETS_SUCCESS = 'FETCH_PROJECT_FEATURE_SETS_SUCCESS' -export const FETCH_PROJECT_FILES_BEGIN = 'FETCH_PROJECT_FILES_BEGIN' -export const FETCH_PROJECT_FILES_FAILURE = 'FETCH_PROJECT_FILES_FAILURE' -export const FETCH_PROJECT_FILES_SUCCESS = 'FETCH_PROJECT_FILES_SUCCESS' -export const FETCH_PROJECT_FUNCTIONS_BEGIN = 'FETCH_PROJECT_FUNCTIONS_BEGIN' -export const FETCH_PROJECT_FUNCTIONS_FAILURE = 'FETCH_PROJECT_FUNCTIONS_FAILURE' -export const FETCH_PROJECT_FUNCTIONS_SUCCESS = 'FETCH_PROJECT_FUNCTIONS_SUCCESS' -export const FETCH_PROJECT_JOBS_BEGIN = 'FETCH_PROJECT_JOBS_BEGIN' -export const FETCH_PROJECT_JOBS_FAILURE = 'FETCH_PROJECT_JOBS_FAILURE' -export const FETCH_PROJECT_JOBS_SUCCESS = 'FETCH_PROJECT_JOBS_SUCCESS' -export const FETCH_PROJECT_MODELS_BEGIN = 'FETCH_PROJECT_MODELS_BEGIN' -export const FETCH_PROJECT_MODELS_FAILURE = 'FETCH_PROJECT_MODELS_FAILURE' -export const FETCH_PROJECT_MODELS_SUCCESS = 'FETCH_PROJECT_MODELS_SUCCESS' -export const FETCH_PROJECT_RUNNING_JOBS_BEGIN = 'FETCH_PROJECT_RUNNING_JOBS_BEGIN' -export const FETCH_PROJECT_RUNNING_JOBS_FAILURE = 'FETCH_PROJECT_RUNNING_JOBS_FAILURE' -export const FETCH_PROJECT_RUNNING_JOBS_SUCCESS = 'FETCH_PROJECT_RUNNING_JOBS_SUCCESS' -export const FETCH_PROJECT_SCHEDULED_JOBS_BEGIN = 'FETCH_PROJECT_SCHEDULED_JOBS_BEGIN' -export const FETCH_PROJECT_SCHEDULED_JOBS_FAILURE = 'FETCH_PROJECT_SCHEDULED_JOBS_FAILURE' -export const FETCH_PROJECT_SCHEDULED_JOBS_SUCCESS = 'FETCH_PROJECT_SCHEDULED_JOBS_SUCCESS' -export const FETCH_PROJECT_SECRETS_BEGIN = 'FETCH_PROJECT_SECRETS_BEGIN' -export const FETCH_PROJECT_SECRETS_FAILURE = 'FETCH_PROJECT_SECRETS_FAILURE' -export const FETCH_PROJECT_SECRETS_SUCCESS = 'FETCH_PROJECT_SECRETS_SUCCESS' -export const FETCH_PROJECT_SUCCESS = 'FETCH_PROJECT_SUCCESS' -export const FETCH_PROJECTS_BEGIN = 'FETCH_PROJECTS_BEGIN' -export const FETCH_PROJECTS_FAILURE = 'FETCH_PROJECTS_FAILURE' -export const FETCH_PROJECTS_NAMES_BEGIN = 'FETCH_PROJECTS_NAMES_BEGIN' -export const FETCH_PROJECTS_NAMES_FAILURE = 'FETCH_PROJECTS_NAMES_FAILURE' -export const FETCH_PROJECTS_NAMES_SUCCESS = 'FETCH_PROJECTS_NAMES_SUCCESS' -export const FETCH_PROJECTS_SUCCESS = 'FETCH_PROJECTS_SUCCESS' -export const FETCH_PROJECTS_SUMMARY_BEGIN = 'FETCH_PROJECTS_SUMMARY_BEGIN' -export const FETCH_PROJECTS_SUMMARY_FAILURE = 'FETCH_PROJECTS_SUMMARY_FAILURE' -export const FETCH_PROJECTS_SUMMARY_SUCCESS = 'FETCH_PROJECTS_SUMMARY_SUCCESS' -export const FETCH_PROJECT_WORKFLOWS_BEGIN = 'FETCH_PROJECT_WORKFLOWS_BEGIN' -export const FETCH_PROJECT_WORKFLOWS_FAILURE = 'FETCH_PROJECT_WORKFLOWS_FAILURE' -export const FETCH_PROJECT_WORKFLOWS_SUCCESS = 'FETCH_PROJECT_WORKFLOWS_SUCCESS' -export const REMOVE_NEW_PROJECT_ERROR = 'REMOVE_NEW_PROJECT_ERROR' -export const REMOVE_PROJECTS = 'REMOVE_PROJECTS' -export const REMOVE_PROJECT_SUMMARY = 'REMOVE_PROJECT_SUMMARY' -export const REMOVE_PROJECT_DATA = 'REMOVE_PROJECT_DATA' - /*=========== DETAILS =============*/ export const DETAILS_ANALYSIS_TAB = 'analysis' diff --git a/src/elements/ProjectCard/ProjectCard.js b/src/elements/ProjectCard/ProjectCard.js index 2ee1dc0f2b..f31f19bfb5 100644 --- a/src/elements/ProjectCard/ProjectCard.js +++ b/src/elements/ProjectCard/ProjectCard.js @@ -19,23 +19,16 @@ such restriction. */ import React, { useEffect, useState, useMemo, useRef } from 'react' import PropTypes from 'prop-types' -import { connect } from 'react-redux' +import { useSelector } from 'react-redux' import ProjectCardView from './ProjectCardView' import { generateProjectStatistic } from './projectCard.util' -import projectsAction from '../../actions/projects' -const ProjectCard = ({ - actionsMenu, - alert, - nuclioStore, - project, - projectStore, - projectSummary -}) => { +const ProjectCard = ({ actionsMenu, alert, project, projectSummary }) => { const [fetchNuclioFunctionsFailure, setFetchNuclioFunctionsFailure] = useState(false) - + const projectStore = useSelector(store => store.projectStore) + const nuclioStore = useSelector(store => store.nuclioStore) const actionsMenuRef = useRef() useEffect(() => { @@ -80,12 +73,4 @@ ProjectCard.propTypes = { alert: PropTypes.number.isRequired } -export default connect( - (projectStore, nuclioStore) => ({ - ...projectStore, - ...nuclioStore - }), - { - ...projectsAction - } -)(ProjectCard) +export default ProjectCard diff --git a/src/elements/ProjectJobs/ProjectJobs.js b/src/elements/ProjectJobs/ProjectJobs.js index 19b0d7d846..ead06082ce 100644 --- a/src/elements/ProjectJobs/ProjectJobs.js +++ b/src/elements/ProjectJobs/ProjectJobs.js @@ -18,7 +18,7 @@ under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ import React, { useEffect, useMemo, useState } from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import moment from 'moment' @@ -26,28 +26,36 @@ import ProjectDataCard from '../ProjectDataCard/ProjectDataCard' import { MONITOR_JOBS_TAB, REQUEST_CANCELED } from '../../constants' import { getJobsStatistics, getJobsTableData, groupByName, sortByDate } from './projectJobs.utils' -import projectsAction from '../../actions/projects' +import { fetchProjectJobs } from '../../reducers/projectReducer' -const ProjectJobs = ({ fetchProjectJobs, projectStore }) => { +const ProjectJobs = () => { const [groupedLatestItem, setGroupedLatestItem] = useState([]) const params = useParams() + const dispatch = useDispatch() + const projectStore = useSelector(store => store.projectStore) useEffect(() => { - if (projectStore.project.jobs.data) { + if (projectStore.project?.jobs?.data) { setGroupedLatestItem(sortByDate(groupByName(projectStore.project.jobs.data))) } - }, [projectStore.project.jobs.data]) + }, [projectStore.project?.jobs?.data]) useEffect(() => { const abortController = new AbortController() const startTimeFrom = moment().add(-7, 'days').toISOString() - fetchProjectJobs(params.projectName, startTimeFrom, abortController.signal) + dispatch( + fetchProjectJobs({ + project: params.projectName, + startTimeFrom, + signal: abortController.signal + }) + ) return () => { abortController.abort(REQUEST_CANCELED) } - }, [fetchProjectJobs, params.projectName]) + }, [dispatch, params.projectName]) const jobsData = useMemo(() => { const statistics = getJobsStatistics(projectStore.projectSummary, params.projectName) @@ -74,11 +82,4 @@ const ProjectJobs = ({ fetchProjectJobs, projectStore }) => { ) } -export default connect( - projectStore => ({ - ...projectStore - }), - { - ...projectsAction - } -)(React.memo(ProjectJobs)) +export default React.memo(ProjectJobs) diff --git a/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.js b/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.js index da8af60fb4..962c124632 100644 --- a/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.js +++ b/src/elements/ProjectSettingsGeneral/ProjectSettingsGeneral.js @@ -21,7 +21,7 @@ import React, { useCallback, useEffect, useState, useRef } from 'react' import PropTypes from 'prop-types' import arrayMutators from 'final-form-arrays' import { Form } from 'react-final-form' -import { connect, useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { createForm } from 'final-form' import { cloneDeep, isEmpty } from 'lodash' import { useParams } from 'react-router-dom' @@ -38,7 +38,6 @@ import { import ChangeOwnerPopUp from '../ChangeOwnerPopUp/ChangeOwnerPopUp' import Loader from '../../common/Loader/Loader' -import projectsAction from '../../actions/projects' import projectsApi from '../../api/projects-api' import { ARTIFACT_PATH, @@ -69,22 +68,21 @@ import { parseChipsData, convertChipsData } from '../../utils/convertChipsData' import { setNotification } from '../../reducers/notificationReducer' import { showErrorNotification } from '../../utils/notifications.util' import { areNodeSelectorsSupported } from './projectSettingsGeneral.utils' +import { fetchProject, removeProjectData } from '../../reducers/projectReducer' import './projectSettingsGeneral.scss' const ProjectSettingsGeneral = ({ changeOwnerCallback, - fetchProject, - frontendSpec, membersState, - projectStore, projectMembershipIsEnabled, - projectOwnerIsShown, - removeProjectData + projectOwnerIsShown }) => { const [projectIsInitialized, setProjectIsInitialized] = useState(false) const [lastEditedProjectValues, setLastEditedProjectValues] = useState({}) const internalLabelsValidatedRef = useRef(true) + const projectStore = useSelector(store => store.projectStore) + const frontendSpec = useSelector(store => store.appStore.frontendSpec) const formRef = useRef( createForm({ @@ -101,7 +99,8 @@ const ProjectSettingsGeneral = ({ if (!projectIsInitialized) { setProjectIsInitialized(true) - fetchProject(params.projectName) + dispatch(fetchProject({ project: params.projectName })) + .unwrap() .then(response => { const newInitial = { [SOURCE_URL]: response?.data?.spec?.[SOURCE_URL], @@ -136,14 +135,7 @@ const ProjectSettingsGeneral = ({ showErrorNotification(dispatch, error, '', customErrorMsg) }) } - }, [ - params.pageTab, - params.projectName, - fetchProject, - dispatch, - frontendSpec, - projectIsInitialized - ]) + }, [params.pageTab, params.projectName, dispatch, frontendSpec, projectIsInitialized]) useEffect(() => { if ( @@ -167,10 +159,10 @@ const ProjectSettingsGeneral = ({ useEffect(() => { return () => { - removeProjectData() + dispatch(removeProjectData()) setProjectIsInitialized(false) } - }, [removeProjectData]) + }, [dispatch]) const sendProjectSettingsData = useCallback( projectData => { @@ -427,10 +419,4 @@ ProjectSettingsGeneral.propTypes = { changeOwnerCallback: PropTypes.func.isRequired } -export default connect( - ({ appStore, projectStore }) => ({ - projectStore, - frontendSpec: appStore.frontendSpec - }), - { ...projectsAction } -)(ProjectSettingsGeneral) +export default ProjectSettingsGeneral diff --git a/src/elements/ProjectSettingsSecrets/ProjectSettingsSecrets.js b/src/elements/ProjectSettingsSecrets/ProjectSettingsSecrets.js index 64fa693c43..08fc37756d 100644 --- a/src/elements/ProjectSettingsSecrets/ProjectSettingsSecrets.js +++ b/src/elements/ProjectSettingsSecrets/ProjectSettingsSecrets.js @@ -19,7 +19,7 @@ such restriction. */ import React, { useCallback, useEffect, useRef, useState } from 'react' import { Form } from 'react-final-form' -import { connect, useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { createForm } from 'final-form' import { differenceWith, isEmpty, isEqual } from 'lodash' import { useParams } from 'react-router-dom' @@ -35,23 +35,19 @@ import { } from './ProjectSettingsSecrets.utils' import { areFormValuesChanged, setFieldState } from 'igz-controls/utils/form.util' import projectApi from '../../api/projects-api' -import projectsAction from '../../actions/projects' import { FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' import { getErrorMsg } from 'igz-controls/utils/common.util' import { getValidationRules } from 'igz-controls/utils/validation.util' import { showErrorNotification } from '../../utils/notifications.util' +import { fetchProjectSecrets, removeProjectData } from '../../reducers/projectReducer' -const ProjectSettingsSecrets = ({ - fetchProjectSecrets, - projectStore, - removeProjectData, - setNotification -}) => { +const ProjectSettingsSecrets = ({ setNotification }) => { const [modifyingIsInProgress, setModifyingIsInProgress] = useState(false) const [lastEditedFormValues, setLastEditedFormValues] = useState({}) const [isUserAllowed, setIsUserAllowed] = useState(true) const params = useParams() const dispatch = useDispatch() + const projectStore = useSelector(store => store.projectStore) const formRef = React.useRef( createForm({ initialValues: {}, @@ -63,34 +59,36 @@ const ProjectSettingsSecrets = ({ const fetchSecrets = useCallback(() => { setIsUserAllowed(true) - fetchProjectSecrets(params.projectName).catch(error => { - const customErrorMsg = - error.response?.status === FORBIDDEN_ERROR_STATUS_CODE - ? 'Permission denied' - : getErrorMsg(error, 'Failed to fetch project data') - - showErrorNotification(dispatch, error, '', customErrorMsg, () => { - fetchSecrets() + dispatch(fetchProjectSecrets({ project: params.projectName })) + .unwrap() + .catch(error => { + const customErrorMsg = + error.response?.status === FORBIDDEN_ERROR_STATUS_CODE + ? 'Permission denied' + : getErrorMsg(error, 'Failed to fetch project data') + + showErrorNotification(dispatch, error, '', customErrorMsg, () => { + fetchSecrets() + }) }) - }) - }, [dispatch, fetchProjectSecrets, params.projectName]) + }, [dispatch, params.projectName]) useEffect(() => { fetchSecrets() return () => { - removeProjectData() + dispatch(removeProjectData()) } - }, [fetchSecrets, removeProjectData, params.projectName]) + }, [dispatch, fetchSecrets, params.projectName]) useEffect(() => { const formSecrets = projectStore.project.secrets?.data['secret_keys'] ? projectStore.project.secrets.data['secret_keys'].map(secret => ({ - data: { - key: secret, - value: '' - } - })) + data: { + key: secret, + value: '' + } + })) : [] const newInitial = { secrets: formSecrets @@ -141,18 +139,18 @@ const ProjectSettingsSecrets = ({ areFormValuesChanged(lastEditedFormValues, formStateLocal.values) && formStateLocal.valid ) { - const modificationType = + const modificationType = formStateLocal.values.secrets.length > lastEditedFormValues.secrets.length ? ADD_PROJECT_SECRET : formStateLocal.values.secrets.length === lastEditedFormValues.secrets.length ? EDIT_PROJECT_SECRET : DELETE_PROJECT_SECRET const primarySecretsArray = - modificationType === DELETE_PROJECT_SECRET + modificationType === DELETE_PROJECT_SECRET ? lastEditedFormValues.secrets : formStateLocal.values.secrets const secondarySecretsArray = - modificationType === DELETE_PROJECT_SECRET + modificationType === DELETE_PROJECT_SECRET ? formStateLocal.values.secrets : lastEditedFormValues.secrets const differences = differenceWith(primarySecretsArray, secondarySecretsArray, isEqual) @@ -164,13 +162,13 @@ const ProjectSettingsSecrets = ({ })) const newFormValues = { secrets: newSecrets } const requestData = - modificationType === DELETE_PROJECT_SECRET + modificationType === DELETE_PROJECT_SECRET ? changedData.key : { provider: 'kubernetes', secrets: { [changedData.key]: changedData.value } } setLastEditedFormValues(newFormValues) formStateRef.current.form.restart(newFormValues) - modifyProjectSecret(modificationType , requestData) + modifyProjectSecret(modificationType, requestData) } } }) @@ -225,9 +223,4 @@ const ProjectSettingsSecrets = ({ ) } -export default connect( - ({ projectStore }) => ({ - projectStore - }), - { ...projectsAction } -)(ProjectSettingsSecrets) +export default ProjectSettingsSecrets diff --git a/src/reducers/featureStoreReducer.js b/src/reducers/featureStoreReducer.js index 6e714aff92..38ee8e3237 100644 --- a/src/reducers/featureStoreReducer.js +++ b/src/reducers/featureStoreReducer.js @@ -540,18 +540,5 @@ export const { setNewFeatureSetTarget, setNewFeatureSetVersion } = featureStoreSlice.actions -export default featureStoreSlice.reducer -// const featureStoreReducer = (state = initialState, { type, payload }) => { -// case START_FEATURE_SET_INGEST_SUCCESS: -// return { -// ...state, -// loading: false, -// error: null -// } -// default: -// return state -// } -// } -// -// export default featureStoreReducer +export default featureStoreSlice.reducer diff --git a/src/reducers/projectReducer.js b/src/reducers/projectReducer.js index 3ad1289865..696783a503 100644 --- a/src/reducers/projectReducer.js +++ b/src/reducers/projectReducer.js @@ -17,74 +17,20 @@ 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 { createAsyncThunk, createSlice } from '@reduxjs/toolkit' + +import projectsApi from '../api/projects-api' +import { hideLoading, showLoading } from './redux.util' import { - CHANGE_PROJECT_STATE_BEGIN, - CHANGE_PROJECT_STATE_FAILURE, - CHANGE_PROJECT_STATE_SUCCESS, - CREATE_PROJECT_BEGIN, - CREATE_PROJECT_FAILURE, - CREATE_PROJECT_SUCCESS, - DELETE_PROJECT_BEGIN, - DELETE_PROJECT_FAILURE, - DELETE_PROJECT_SUCCESS, - FETCH_PROJECT_BEGIN, - FETCH_PROJECT_DATASETS_BEGIN, - FETCH_PROJECT_SUMMARY_BEGIN, - FETCH_PROJECT_SUMMARY_FAILURE, - FETCH_PROJECT_SUMMARY_SUCCESS, - FETCH_PROJECT_DATASETS_FAILURE, - FETCH_PROJECT_DATASETS_SUCCESS, - FETCH_PROJECT_FAILED_JOBS_BEGIN, - FETCH_PROJECT_FAILED_JOBS_FAILURE, - FETCH_PROJECT_FAILED_JOBS_SUCCESS, - FETCH_PROJECT_FAILURE, - FETCH_PROJECT_FILES_BEGIN, - FETCH_PROJECT_FILES_FAILURE, - FETCH_PROJECT_FILES_SUCCESS, - FETCH_PROJECT_FUNCTIONS_BEGIN, - FETCH_PROJECT_FUNCTIONS_FAILURE, - FETCH_PROJECT_FUNCTIONS_SUCCESS, - FETCH_PROJECT_JOBS_BEGIN, - FETCH_PROJECT_JOBS_FAILURE, - FETCH_PROJECT_JOBS_SUCCESS, - FETCH_PROJECT_MODELS_BEGIN, - FETCH_PROJECT_MODELS_FAILURE, - FETCH_PROJECT_MODELS_SUCCESS, - FETCH_PROJECT_RUNNING_JOBS_BEGIN, - FETCH_PROJECT_RUNNING_JOBS_FAILURE, - FETCH_PROJECT_RUNNING_JOBS_SUCCESS, - FETCH_PROJECT_SCHEDULED_JOBS_BEGIN, - FETCH_PROJECT_SCHEDULED_JOBS_FAILURE, - FETCH_PROJECT_SCHEDULED_JOBS_SUCCESS, - FETCH_PROJECT_SUCCESS, - FETCH_PROJECT_WORKFLOWS_BEGIN, - FETCH_PROJECT_WORKFLOWS_FAILURE, - FETCH_PROJECT_WORKFLOWS_SUCCESS, - FETCH_PROJECTS_BEGIN, - FETCH_PROJECTS_FAILURE, - FETCH_PROJECTS_SUCCESS, - REMOVE_NEW_PROJECT_ERROR, - REMOVE_PROJECT_SUMMARY, - REMOVE_PROJECT_DATA, - REMOVE_PROJECTS, - FETCH_PROJECT_FEATURE_SETS_BEGIN, - FETCH_PROJECT_FEATURE_SETS_SUCCESS, - FETCH_PROJECT_FEATURE_SETS_FAILURE, - FETCH_PROJECTS_SUMMARY_BEGIN, - FETCH_PROJECTS_SUMMARY_FAILURE, - FETCH_PROJECTS_SUMMARY_SUCCESS, - FETCH_PROJECTS_NAMES_BEGIN, - FETCH_PROJECTS_NAMES_FAILURE, - FETCH_PROJECTS_NAMES_SUCCESS, - FETCH_PROJECT_SECRETS_BEGIN, - FETCH_PROJECT_SECRETS_FAILURE, - FETCH_PROJECT_SECRETS_SUCCESS, - SET_PROJECT_TOTAL_ALERTS, - SET_JOBS_MONITORING_DATA, - SET_MLRUN_IS_UNHEALTHY, - SET_MLRUN_UNHEALTHY_RETRYING, - SET_DELETING_PROJECTS -} from '../constants' + CONFLICT_ERROR_STATUS_CODE, + FORBIDDEN_ERROR_STATUS_CODE, + INTERNAL_SERVER_ERROR_STATUS_CODE +} 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 { parseSummaryData } from '../utils/parseSummaryData' +import { mlrunUnhealthyErrors } from '../components/ProjectsPage/projects.util' const initialState = { deletingProjects: {}, @@ -129,12 +75,12 @@ const initialState = { error: null }, functions: { - data: null, + data: [], loading: false, error: null }, jobs: { - data: null, + data: [], error: null, loading: false }, @@ -184,648 +130,453 @@ const initialState = { } } -const projectReducer = (state = initialState, { type, payload }) => { - switch (type) { - case CHANGE_PROJECT_STATE_BEGIN: - return { - ...state, - loading: true - } - case CHANGE_PROJECT_STATE_FAILURE: - return { - ...state, - loading: false - } - case CHANGE_PROJECT_STATE_SUCCESS: - return { - ...state, - loading: false - } - case CREATE_PROJECT_BEGIN: - return { - ...state, - loading: true - } - case CREATE_PROJECT_FAILURE: - return { - ...state, - loading: false, - newProject: { - error: payload - } - } - case CREATE_PROJECT_SUCCESS: - return { - ...state, - loading: false, - newProject: { - error: null - } - } - case DELETE_PROJECT_BEGIN: - return { - ...state, - projectsToDelete: [...state.projectsToDelete, payload] - } - case DELETE_PROJECT_FAILURE: - return { - ...state, - projectsToDelete: state.projectsToDelete.filter(projectName => projectName !== payload) - } - case DELETE_PROJECT_SUCCESS: - return { - ...state, - projectsToDelete: state.projectsToDelete.filter(projectName => projectName !== payload) - } - case FETCH_PROJECT_BEGIN: - return { - ...state, - project: { - ...state.project, - loading: true - } - } - case FETCH_PROJECT_DATASETS_BEGIN: - return { - ...state, - project: { - ...state.project, - dataSets: { - ...state.project.dataSets, - loading: true - } - } - } - case FETCH_PROJECT_DATASETS_FAILURE: - return { - ...state, - project: { - ...state.project, - dataSets: { - data: [], - error: payload, - loading: false - } - } - } - case FETCH_PROJECT_DATASETS_SUCCESS: - return { - ...state, - project: { - ...state.project, - dataSets: { - data: payload, - loading: false, - error: null - } - } - } - case FETCH_PROJECT_FEATURE_SETS_BEGIN: - return { - ...state, - project: { - ...state.project, - featureSets: { - ...state.project.featureSets, - loading: true - } - } - } - case FETCH_PROJECT_FEATURE_SETS_FAILURE: - return { - ...state, - project: { - ...state.project, - featureSets: { - data: [], - error: payload, - loading: false - } - } - } - case FETCH_PROJECT_FEATURE_SETS_SUCCESS: - return { - ...state, - project: { - ...state.project, - featureSets: { - data: payload, - loading: false, - error: null - } - } - } - case FETCH_PROJECT_FAILED_JOBS_BEGIN: - return { - ...state, - project: { - ...state.project, - failedJobs: { - ...state.project.failedJobs, - loading: true - } - } - } - case FETCH_PROJECT_FAILED_JOBS_FAILURE: - return { - ...state, - project: { - ...state.project, - failedJobs: { - ...state.project.failedJobs, - data: [], - error: payload, - loading: false - } - } - } - case FETCH_PROJECT_FAILED_JOBS_SUCCESS: - return { - ...state, - project: { - ...state.project, - failedJobs: { - ...state.project.failedJobs, - data: payload, - error: null, - loading: false - } - } - } - case FETCH_PROJECT_FAILURE: - return { - ...state, - project: { - ...state.project, - loading: false, - error: payload - } - } - case FETCH_PROJECT_FILES_BEGIN: - return { - ...state, - project: { - ...state.project, - files: { - ...state.project.files, - loading: true - } - } - } - case FETCH_PROJECT_FILES_FAILURE: - return { - ...state, - project: { - ...state.project, - files: { - data: [], - error: payload, - loading: false - } - } - } - case FETCH_PROJECT_FILES_SUCCESS: - return { - ...state, - project: { - ...state.project, - files: { - data: payload, - loading: true, - error: null - } - } - } - case FETCH_PROJECT_FUNCTIONS_BEGIN: - return { - ...state, - project: { - ...state.project, - functions: { - ...state.project.functions, - loading: true - } - } - } - case FETCH_PROJECT_FUNCTIONS_FAILURE: - return { - ...state, - project: { - ...state.project, - functions: { - ...state.project.functions, - error: payload - } - } - } - case FETCH_PROJECT_FUNCTIONS_SUCCESS: - return { - ...state, - project: { - ...state.project, - functions: { - data: payload, - loading: false, - error: null - } - } - } - case FETCH_PROJECT_JOBS_BEGIN: - return { - ...state, - project: { - ...state.project, - jobs: { - ...state.project.jobs, - loading: true - } - } - } - case FETCH_PROJECT_JOBS_FAILURE: - return { - ...state, - project: { - ...state.project, - jobs: { - ...state.project.jobs, - error: payload, - loading: false - } - } - } - case FETCH_PROJECT_JOBS_SUCCESS: - return { - ...state, - project: { - ...state.project, - jobs: { - data: payload, - loading: false, - error: null - } - } - } - case FETCH_PROJECT_MODELS_BEGIN: - return { - ...state, - project: { - ...state.project, - models: { - ...state.project.models, - loading: true - } - } - } - case FETCH_PROJECT_MODELS_FAILURE: - return { - ...state, - project: { - ...state.project, - models: { - data: [], - error: payload, - loading: false - } - } - } - case FETCH_PROJECT_MODELS_SUCCESS: - return { - ...state, - project: { - ...state.project, - models: { - data: payload, - error: null, - loading: false - } - } - } - case FETCH_PROJECT_RUNNING_JOBS_BEGIN: - return { - ...state, - project: { - ...state.project, - runningJobs: { - ...state.project.runningJobs, - error: null, - loading: true - } - } - } - case FETCH_PROJECT_RUNNING_JOBS_FAILURE: - return { - ...state, - project: { - ...state.project, - runningJobs: { - ...state.project.runningJobs, - data: [], - error: payload, - loading: false - } - } - } - case FETCH_PROJECT_RUNNING_JOBS_SUCCESS: - return { - ...state, - project: { - ...state.project, - runningJobs: { - ...state.project.runningJobs, - data: payload, - error: null, - loading: false - } - } - } - case FETCH_PROJECT_SUCCESS: - return { - ...state, - project: { - ...state.project, - data: payload, - loading: false, - error: null - } - } - case FETCH_PROJECT_SCHEDULED_JOBS_BEGIN: - return { - ...state, - project: { - ...state.project, - scheduledJobs: { - ...state.project.scheduledJobs, - loading: true - } - } - } - case FETCH_PROJECT_SCHEDULED_JOBS_FAILURE: - return { - ...state, - project: { - ...state.project, - scheduledJobs: { - ...state.project.scheduledJobs, - data: [], - error: payload, - loading: false - } - } - } - case FETCH_PROJECT_SCHEDULED_JOBS_SUCCESS: - return { - ...state, - project: { - ...state.project, - scheduledJobs: { - ...state.project.scheduledJobs, - data: payload, - error: null, - loading: false - } +export const changeProjectState = createAsyncThunk( + 'changeProjectState', + ({ project, status }, thunkAPI) => { + return projectsApi + .changeProjectState(project, status) + .catch(error => thunkAPI.rejectWithValue(error)) + } +) +export const createNewProject = createAsyncThunk('createNewProject', ({ postData }, thunkAPI) => { + return projectsApi + .createProject(postData) + .then(result => { + return result.data + }) + .catch(error => { + const message = + error.response?.status === CONFLICT_ERROR_STATUS_CODE + ? `A project named "${postData.metadata.name}" already exists.` + : error.response?.status === FORBIDDEN_ERROR_STATUS_CODE + ? 'You don’t have permission to create a project.' + : error.response?.status === INTERNAL_SERVER_ERROR_STATUS_CODE + ? error.response.data?.detail || + 'The system already has the maximum number of projects. An existing project must be deleted before you can create another.' + : error.message + + return thunkAPI.rejectWithValue(message) + }) +}) +export const deleteProject = createAsyncThunk( + 'deleteProject', + ({ projectName, deleteNonEmpty }, thunkAPI) => { + return projectsApi + .deleteProject(projectName, deleteNonEmpty) + .then(response => { + return { response, projectName } + }) + .catch(error => thunkAPI.rejectWithValue({ error, projectName })) + } +) + +export const fetchProject = createAsyncThunk( + 'fetchProject', + ({ project, params, signal }, thunkAPI) => { + return projectsApi + .getProject(project, params, signal) + .then(response => { + return response + }) + .catch(error => { + if (![REQUEST_CANCELED, DEFAULT_ABORT_MSG].includes(error.message)) { + return thunkAPI.rejectWithValue(error) + } + }) + } +) +export const fetchProjectDataSets = createAsyncThunk( + 'fetchProjectDataSets', + ({ project, params, signal }, thunkAPI) => { + return projectsApi + .getProjectDataSets(project) + .then(response => { + return response?.data.artifacts + }) + .catch(error => thunkAPI.rejectWithValue(error.message)) + } +) +export const fetchProjectFailedJobs = createAsyncThunk( + 'fetchProjectFailedJobs', + ({ project, signal }, thunkAPI) => { + return projectsApi + .getProjectFailedJobs(project, signal) + .then(response => { + return response?.data.runs + }) + .catch(error => thunkAPI.rejectWithValue(error.message)) + } +) +export const fetchProjectFunctions = createAsyncThunk( + 'fetchProjectFunctions', + ({ project, signal }, thunkAPI) => { + return projectsApi + .getProjectFunctions(project, signal) + .then(response => { + return response?.data.funcs + }) + .catch(error => thunkAPI.rejectWithValue(error.message)) + } +) +export const fetchProjectJobs = createAsyncThunk( + 'fetchProjectJobs', + ({ project, startTimeFrom, signal }, thunkAPI) => { + const params = { + 'partition-by': 'name', + 'partition-sort-by': 'updated', + 'rows-per-partition': '5', + 'max-partitions': '5', + iter: 'false', + start_time_from: startTimeFrom + } + + return projectsApi + .getJobsAndWorkflows(project, params, signal) + .then(response => { + return response?.data.runs + }) + .catch(error => thunkAPI.rejectWithValue(error.message)) + } +) +export const fetchProjectSecrets = createAsyncThunk( + 'fetchProjectSecrets', + ({ project }, thunkAPI) => { + return projectsApi.getProjectSecrets(project).catch(error => thunkAPI.rejectWithValue(error)) + } +) +export const fetchProjectSummary = createAsyncThunk( + 'fetchProjectSummary', + ({ project, signal }, thunkAPI) => { + return projectsApi + .getProjectSummary(project, signal) + .then(({ data }) => { + return parseSummaryData(data) + }) + .catch(error => { + if (![REQUEST_CANCELED, DEFAULT_ABORT_MSG].includes(error.message)) { + return thunkAPI.rejectWithValue(error) + } + }) + } +) +export const fetchProjects = createAsyncThunk( + 'fetchProjects', + ({ params, setRequestErrorMessage = () => {} }, thunkAPI) => { + setRequestErrorMessage('') + + return projectsApi + .getProjects(params) + .then(response => { + return parseProjects(response.data.projects) + }) + .catch(error => { + showErrorNotification( + thunkAPI.dispatch, + error, + 'Failed to fetch projects', + null, + null, + setRequestErrorMessage + ) + return thunkAPI.rejectWithValue(error) + }) + } +) +export const fetchProjectsNames = createAsyncThunk('fetchProjectsNames', (_, thunkAPI) => { + return projectsApi + .getProjects({ format: 'name_only', state: PROJECT_ONLINE_STATUS }) + .then(({ data: { projects } }) => { + return projects + }) + .catch(error => { + showErrorNotification(thunkAPI.dispatch, error, '', 'Failed to fetch projects') + return thunkAPI.rejectWithValue(error) + }) +}) + +let firstServerErrorTimestamp = null + +export const fetchProjectsSummary = createAsyncThunk( + 'fetchProjectsSummary', + ({ signal, refresh }, thunkAPI) => { + return projectsApi + .getProjectSummaries(signal) + .then(({ data: { project_summaries } }) => { + if (firstServerErrorTimestamp && refresh) { + firstServerErrorTimestamp = null + + refresh() } - } - case FETCH_PROJECT_SECRETS_BEGIN: - return { - ...state, - project: { - ...state.project, - secrets: { - ...state.project.secrets, - loading: true + + thunkAPI.dispatch(setMlrunIsUnhealthy(false)) + thunkAPI.dispatch(setMlrunUnhealthyRetrying(false)) + + return parseSummaryData(project_summaries) + }) + .catch(err => { + if (mlrunUnhealthyErrors.includes(err.response?.status)) { + if (!firstServerErrorTimestamp) { + firstServerErrorTimestamp = new Date() + + thunkAPI.dispatch(setMlrunUnhealthyRetrying(true)) } - } - } - case FETCH_PROJECT_SECRETS_FAILURE: - return { - ...state, - project: { - ...state.project, - secrets: { - ...state.project.secrets, - error: payload, - loading: false + + const threeMinutesPassed = (new Date() - firstServerErrorTimestamp) / 1000 > 180 + + if (!threeMinutesPassed) { + setTimeout(() => { + thunkAPI.dispatch(fetchProjectsSummary({ signal, refresh })) + }, 3000) } - } - } - case FETCH_PROJECT_SECRETS_SUCCESS: - return { - ...state, - project: { - ...state.project, - secrets: { - ...state.project.secrets, - data: payload, - error: null, - loading: false + + if (threeMinutesPassed) { + thunkAPI.dispatch(setMlrunIsUnhealthy(true)) + thunkAPI.dispatch(setMlrunUnhealthyRetrying(true)) } } - } - case FETCH_PROJECTS_BEGIN: - return { - ...state, - loading: true - } - case FETCH_PROJECTS_FAILURE: - return { - ...state, - projects: [], + + return thunkAPI.rejectWithValue(err) + }) + } +) + +const projectStoreSlice = createSlice({ + name: 'projectStore', + initialState, + reducers: { + removeNewProjectError(state) { + state.newProject.error = null + }, + removeProjectData(state) { + state.project = initialState.project + }, + removeProjectSummary(state) { + state.projectSummary = { + error: null, loading: false, - error: payload - } - case FETCH_PROJECTS_NAMES_BEGIN: - return { - ...state, - projectsNames: { - ...state.projectsNames, - loading: true - } - } - case FETCH_PROJECTS_NAMES_FAILURE: - return { - ...state, - projectsNames: { - data: [], - loading: false, - error: payload - } - } - case FETCH_PROJECTS_NAMES_SUCCESS: - return { - ...state, - projectsNames: { - ...state.projectsNames, - data: payload, - loading: false - } + data: [] } - case FETCH_PROJECTS_SUCCESS: - return { - ...state, - projects: payload, + }, + removeProjects(state) { + state.projects = [] + }, + setDeletingProjects(state, action) { + state.deletingProjects = { ...action.payload } + }, + setMlrunIsUnhealthy(state, action) { + state.mlrunUnhealthy.isUnhealthy = action.payload + }, + setMlrunUnhealthyRetrying(state, action) { + state.mlrunUnhealthy.retrying = action.payload + }, + setJobsMonitoringData(state, action) { + state.jobsMonitoringData = action.payload + }, + setProjectTotalAlerts(state, action) { + state.projectTotalAlerts = { ...action.payload } + } + }, + extraReducers: builder => { + builder.addCase(changeProjectState.pending, showLoading) + builder.addCase(changeProjectState.fulfilled, hideLoading) + builder.addCase(changeProjectState.rejected, hideLoading) + builder.addCase(createNewProject.pending, showLoading) + builder.addCase(createNewProject.fulfilled, state => { + state.newProject.error = null + state.loading = false + }) + builder.addCase(createNewProject.rejected, (state, action) => { + state.newProject.error = action.payload + state.loading = false + }) + builder.addCase(deleteProject.fulfilled, (state, action) => { + state.projectsToDelete = state.projectsToDelete.filter( + projectName => projectName !== action.payload.projectName + ) + }) + builder.addCase(deleteProject.rejected, (state, action) => { + state.projectsToDelete = state.projectsToDelete.filter( + projectName => projectName !== action.payload.projectName + ) + }) + builder.addCase(fetchProject.pending, state => { + state.project.loading = true + }) + builder.addCase(fetchProject.fulfilled, (state, action) => { + state.project = { + ...state.project, + error: null, + loading: false, + data: action.payload?.data + } + }) + builder.addCase(fetchProject.rejected, (state, action) => { + state.project.error = action.payload + state.project.loading = false + }) + builder.addCase(fetchProjectDataSets.pending, state => { + state.project.dataSets.loading = true + }) + builder.addCase(fetchProjectDataSets.fulfilled, (state, action) => { + state.project.dataSets = { + data: action.payload, loading: false, error: null } - case FETCH_PROJECTS_SUMMARY_BEGIN: - return { - ...state, - projectsSummary: { - ...state.projectsSummary, - loading: true - } - } - case FETCH_PROJECTS_SUMMARY_FAILURE: - return { - ...state, - projectsSummary: { - data: [], - loading: false, - error: payload - } - } - case FETCH_PROJECTS_SUMMARY_SUCCESS: - return { - ...state, - projectsSummary: { - ...state.projectsSummary, - data: payload, - loading: false, - error: null - } - } - case FETCH_PROJECT_SUMMARY_BEGIN: - return { - ...state, - projectSummary: { - ...state.projectSummary, - loading: true - } + }) + builder.addCase(fetchProjectDataSets.rejected, (state, action) => { + state.project.dataSets = { + data: [], + error: action.payload, + loading: false } - case FETCH_PROJECT_SUMMARY_FAILURE: - return { - ...state, - projectSummary: { - data: [], - loading: false, - error: payload - } + }) + builder.addCase(fetchProjectFailedJobs.pending, state => { + state.project.failedJobs.loading = true + }) + builder.addCase(fetchProjectFailedJobs.fulfilled, (state, action) => { + state.project.failedJobs = { + data: action.payload, + error: null, + loading: false } - case FETCH_PROJECT_SUMMARY_SUCCESS: - return { - ...state, - projectSummary: { - data: payload, - loading: false, - error: null - } + }) + builder.addCase(fetchProjectFailedJobs.rejected, (state, action) => { + state.project.failedJobs = { + data: [], + error: action.payload, + loading: false } - case FETCH_PROJECT_WORKFLOWS_BEGIN: - return { - ...state, - project: { - ...state.project, - workflows: { - ...state.project.workflows, - loading: true - } - } + }) + builder.addCase(fetchProjectFunctions.pending, state => { + state.project.functions.loading = true + }) + builder.addCase(fetchProjectFunctions.fulfilled, (state, action) => { + state.project.functions = { + data: action.payload, + error: null, + loading: false } - case FETCH_PROJECT_WORKFLOWS_FAILURE: - return { - ...state, - project: { - ...state.project, - workflows: { - ...state.project.workflows, - data: [], - error: payload, - loading: false - } - } + }) + builder.addCase(fetchProjectFunctions.rejected, (state, action) => { + state.project.functions = { + data: [], + error: action.payload, + loading: false } - case FETCH_PROJECT_WORKFLOWS_SUCCESS: - return { - ...state, - project: { - ...state.project, - workflows: { - ...state.project.workflows, - data: payload, - error: null, - loading: false - } - } + }) + builder.addCase(fetchProjectJobs.pending, state => { + state.project.jobs.loading = true + }) + builder.addCase(fetchProjectJobs.fulfilled, (state, action) => { + state.project.jobs = { + data: action.payload.filter(job => job.metadata.iteration === 0), + error: null, + loading: false } - case REMOVE_PROJECT_SUMMARY: - return { - ...state, - projectSummary: { - error: null, - loading: false, - data: [] - } + }) + builder.addCase(fetchProjectJobs.rejected, (state, action) => { + state.project.jobs = { + data: [], + error: action.payload, + loading: false } - case REMOVE_PROJECT_DATA: - return { - ...state, - project: { - ...initialState.project - } + }) + builder.addCase(fetchProjectSecrets.pending, state => { + state.project.secrets.loading = true + }) + builder.addCase(fetchProjectSecrets.fulfilled, (state, action) => { + state.project.secrets = { + data: action.payload, + error: null, + loading: false } - case REMOVE_PROJECTS: - return { - ...state, - projects: [] + }) + builder.addCase(fetchProjectSecrets.rejected, (state, action) => { + state.project.secrets = { + data: [], + error: action.payload.message, + loading: false } - case REMOVE_NEW_PROJECT_ERROR: - return { - ...state, - newProject: { - error: null - } + }) + builder.addCase(fetchProjectSummary.pending, state => { + state.projectSummary.loading = true + }) + builder.addCase(fetchProjectSummary.fulfilled, (state, action) => { + state.projectSummary = { + data: action.payload, + error: null, + loading: false } - case SET_PROJECT_TOTAL_ALERTS: - return { - ...state, - projectTotalAlerts: { - ...state.projectTotalAlerts, - ...payload - } + }) + builder.addCase(fetchProjectSummary.rejected, (state, action) => { + state.projectSummary = { + data: [], + error: action.payload.message, + loading: false } - case SET_DELETING_PROJECTS: - return { - ...state, - deletingProjects: { - ...payload - } + }) + builder.addCase(fetchProjects.pending, showLoading) + builder.addCase(fetchProjects.fulfilled, (state, action) => { + state.projects = action.payload + state.loading = false + state.error = null + state.projectsNames.data = action.payload + .filter(project => project.status.state === PROJECT_ONLINE_STATUS) + .map(project => project.metadata.name) + }) + builder.addCase(fetchProjects.rejected, (state, action) => { + state.projects = [] + state.loading = false + state.error = action.payload + }) + builder.addCase(fetchProjectsNames.pending, state => { + state.projectsNames.loading = true + }) + builder.addCase(fetchProjectsNames.fulfilled, (state, action) => { + state.projectsNames = { + data: action.payload, + error: null, + loading: false } - case SET_JOBS_MONITORING_DATA: - return { - ...state, - jobsMonitoringData: { - ...state.jobsMonitoringData, - ...payload - } + }) + builder.addCase(fetchProjectsNames.rejected, (state, action) => { + state.projectsNames = { + data: [], + error: action.payload, + loading: false } - case SET_MLRUN_IS_UNHEALTHY: - return { - ...state, - mlrunUnhealthy: { - ...state.mlrunUnhealthy, - isUnhealthy: payload - } + }) + builder.addCase(fetchProjectsSummary.pending, state => { + state.projectsSummary.loading = true + }) + builder.addCase(fetchProjectsSummary.fulfilled, (state, action) => { + state.projectsSummary = { + data: action.payload, + error: null, + loading: false } - case SET_MLRUN_UNHEALTHY_RETRYING: - return { - ...state, - mlrunUnhealthy: { - ...state.mlrunUnhealthy, - retrying: payload - } + }) + builder.addCase(fetchProjectsSummary.rejected, (state, action) => { + state.projectsSummary = { + data: [], + error: action.payload, + loading: false } - default: - return state + }) } -} +}) + +export const { + removeNewProjectError, + removeProjectData, + removeProjectSummary, + removeProjects, + setDeletingProjects, + setMlrunIsUnhealthy, + setMlrunUnhealthyRetrying, + setJobsMonitoringData, + setProjectTotalAlerts +} = projectStoreSlice.actions -export default projectReducer +export default projectStoreSlice.reducer From 81bf1bf8201cc95d035f477ed72e26421357d71a Mon Sep 17 00:00:00 2001 From: adi-gini Date: Fri, 4 Apr 2025 14:20:14 +0300 Subject: [PATCH 05/30] Fix [Functions] Missing "Version tag" in the function popup screen (#3189) --- src/components/Details/details.util.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Details/details.util.js b/src/components/Details/details.util.js index f2984c0066..7d821c7e62 100644 --- a/src/components/Details/details.util.js +++ b/src/components/Details/details.util.js @@ -320,7 +320,8 @@ export const generateJobsContent = selectedItem => { shouldPopUp: !isEmpty(selectedItem.function), handleClick: () => openPopUp(FunctionPopUp, { - funcUri: selectedItem.function + funcUri: selectedItem.function, + funcTag: selectedItem.ui?.functionTag ?? '' }) }, functionTag: { From b1cd1df1a7f4feccbd07469eb560bd4ed41d977e Mon Sep 17 00:00:00 2001 From: mariana-furyk <58301139+mariana-furyk@users.noreply.github.com> Date: Mon, 7 Apr 2025 08:04:33 +0300 Subject: [PATCH 06/30] Impl [Details] Move Redux to RTK (#3157) --- package.json | 2 +- src/actions/details.js | 161 ------ src/actions/modelEndpoints.js | 122 ----- .../AddToFeatureVectorPage.js | 5 - .../AddToFeatureVectorView.js | 3 - src/components/Alerts/Alerts.js | 27 +- src/components/Datasets/Datasets.js | 5 - src/components/Datasets/DatasetsView.js | 10 +- src/components/Details/Details.js | 121 ++--- .../Details/DetailsHeader/DetailsHeader.js | 8 +- .../DetailsTabsContent/DetailsTabsContent.js | 23 +- src/components/Details/details.util.js | 18 +- .../DetailsArtifacts/DetailsArtifacts.js | 44 +- .../DetailsAlertsMetrics.js | 14 +- .../DetailsDrillDownAlert.js | 19 +- src/components/DetailsInfo/DetailsInfo.js | 40 +- src/components/DetailsInfo/DetailsInfoView.js | 4 +- .../DetailsMetrics/DetailsMetrics.js | 52 +- .../DetailsRequestedFeatures.js | 40 +- src/components/Documents/Documents.js | 5 - src/components/Documents/DocumentsView.js | 7 +- .../FeatureStore/FeatureSets/FeatureSets.js | 5 - .../FeatureSets/FeatureSetsView.js | 3 - .../FeatureVectors/FeatureVectors.js | 5 - .../FeatureVectors/FeatureVectorsView.js | 3 - .../FeatureStore/Features/Features.js | 5 - .../FeatureStore/Features/FeaturesView.js | 3 - src/components/Files/Files.js | 5 - src/components/Files/FilesView.js | 7 +- src/components/FilterMenu/FilterMenu.js | 30 +- src/components/FunctionsPage/Functions.js | 5 - src/components/FunctionsPage/FunctionsView.js | 3 - .../FunctionsPageOld/FunctionsOld.js | 7 +- .../FunctionsPageOld/FunctionsViewOld.js | 3 - .../Jobs/MonitorWorkflows/MonitorWorkflows.js | 7 +- .../ModelEndpoints/ModelEndpoints.js | 5 - src/components/ModelsPage/Models/Models.js | 19 +- .../ModelsPage/Models/ModelsView.js | 7 +- .../RealTimePipelines/RealTimePipelines.js | 5 - .../WorkflowsMonitoring.js | 3 +- src/components/Table/Table.js | 3 - src/components/Table/TableView.js | 3 - src/components/Workflow/Workflow.js | 6 - .../DetailsInfoItem/DetailsInfoItem.js | 3 - .../DetailsInfoItemChip.js | 15 +- .../DetailsPopUp/JobPopUp/JobPopUp.js | 3 +- src/elements/JobsTable/JobsTable.js | 8 +- .../ScheduledJobsTable/ScheduledJobsTable.js | 5 - src/elements/WorkflowsTable/WorkflowsTable.js | 3 - src/hooks/usePods.hook.js | 25 +- src/reducers/detailsReducer.js | 458 +++++++++--------- 51 files changed, 448 insertions(+), 944 deletions(-) delete mode 100644 src/actions/details.js delete mode 100644 src/actions/modelEndpoints.js diff --git a/package.json b/package.json index cb48596973..2f1845112a 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "final-form-arrays": "^3.1.0", "fs-extra": "^10.0.0", "identity-obj-proxy": "^3.0.0", - "iguazio.dashboard-react-controls": "2.2.22", + "iguazio.dashboard-react-controls": "2.2.23", "is-wsl": "^1.1.0", "js-base64": "^2.5.2", "js-yaml": "^4.1.0", diff --git a/src/actions/details.js b/src/actions/details.js deleted file mode 100644 index c1910faece..0000000000 --- a/src/actions/details.js +++ /dev/null @@ -1,161 +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 detailsApi from '../api/details-api' -import { - FETCH_JOB_PODS_BEGIN, - FETCH_JOB_PODS_FAILURE, - FETCH_JOB_PODS_SUCCESS, - FETCH_MODEL_FEATURE_VECTOR_BEGIN, - FETCH_MODEL_FEATURE_VECTOR_FAILURE, - FETCH_MODEL_FEATURE_VECTOR_SUCCESS, - REMOVE_DETAILS_POPUP_INFO_CONTENT, - REMOVE_INFO_CONTENT, - REMOVE_JOB_PODS, - REMOVE_MODEL_FEATURE_VECTOR, - RESET_CHANGES, - SET_CHANGES, - SET_CHANGES_COUNTER, - SET_CHANGES_DATA, - SET_DETAILS_DATES, - SET_DETAILS_POPUP_INFO_CONTENT, - SET_EDIT_MODE, - SET_FILTERS_WAS_HANDLED, - SET_INFO_CONTENT, - SET_ITERATION, - SET_ITERATION_OPTIONS, - SHOW_WARNING -} from '../constants' -import { generatePods } from '../utils/generatePods' - -const detailsActions = { - fetchModelFeatureVector: (project, name, reference) => dispatch => { - dispatch(detailsActions.fetchModelFeatureVectorBegin()) - - return detailsApi - .getModelFeatureVector(project, name, reference) - .then(response => { - dispatch(detailsActions.fetchModelFeatureVectorSuccess(response.data.status)) - - return response.data.status - }) - .catch(err => { - dispatch(detailsActions.fetchModelFeatureVectorFailure(err)) - }) - }, - fetchModelFeatureVectorBegin: () => ({ - type: FETCH_MODEL_FEATURE_VECTOR_BEGIN - }), - fetchModelFeatureVectorFailure: error => ({ - type: FETCH_MODEL_FEATURE_VECTOR_FAILURE, - payload: error - }), - fetchModelFeatureVectorSuccess: featureSets => ({ - type: FETCH_MODEL_FEATURE_VECTOR_SUCCESS, - payload: featureSets - }), - fetchJobPods: (project, uid, kind) => dispatch => { - dispatch(detailsActions.fetchPodsBegin()) - - return detailsApi - .getJobPods(project, uid, kind) - .then(({ data }) => { - let podsData = generatePods(project, uid, data) - - dispatch(detailsActions.fetchPodsSuccess(podsData)) - - return podsData - }) - .catch(err => { - dispatch(detailsActions.fetchPodsFailure(err)) - }) - }, - fetchPodsBegin: () => ({ - type: FETCH_JOB_PODS_BEGIN - }), - fetchPodsFailure: error => ({ - type: FETCH_JOB_PODS_FAILURE, - payload: error - }), - fetchPodsSuccess: pods => ({ - type: FETCH_JOB_PODS_SUCCESS, - payload: pods - }), - removeDetailsPopUpInfoContent: () => ({ - type: REMOVE_DETAILS_POPUP_INFO_CONTENT - }), - removeInfoContent: () => ({ - type: REMOVE_INFO_CONTENT - }), - removeModelFeatureVector: () => ({ - type: REMOVE_MODEL_FEATURE_VECTOR - }), - removePods: () => ({ - type: REMOVE_JOB_PODS - }), - resetChanges: () => ({ - type: RESET_CHANGES - }), - setChanges: data => ({ - type: SET_CHANGES, - payload: data - }), - setChangesCounter: counter => ({ - type: SET_CHANGES_COUNTER, - payload: counter - }), - setChangesData: data => ({ - type: SET_CHANGES_DATA, - payload: data - }), - setDetailsDates: data => ({ - type: SET_DETAILS_DATES, - payload: data - }), - setDetailsPopUpInfoContent: content => ({ - type: SET_DETAILS_POPUP_INFO_CONTENT, - payload: content - }), - setEditMode: value => ({ - type: SET_EDIT_MODE, - payload: value - }), - setFiltersWasHandled: isHandled => ({ - type: SET_FILTERS_WAS_HANDLED, - payload: isHandled - }), - setInfoContent: content => ({ - type: SET_INFO_CONTENT, - payload: content - }), - setIteration: iteration => ({ - type: SET_ITERATION, - payload: iteration - }), - setIterationOption: option => ({ - type: SET_ITERATION_OPTIONS, - payload: option - }), - showWarning: show => ({ - type: SHOW_WARNING, - payload: show - }) -} - -export default detailsActions diff --git a/src/actions/modelEndpoints.js b/src/actions/modelEndpoints.js deleted file mode 100644 index 9427f2e6b9..0000000000 --- a/src/actions/modelEndpoints.js +++ /dev/null @@ -1,122 +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 modelEndpointsApi from '../api/modelEndpoints-api' -import { - DEFAULT_ABORT_MSG, - FETCH_ENDPOINT_METRICS_BEGIN, - FETCH_ENDPOINT_METRICS_SUCCESS, - FETCH_ENDPOINT_METRICS_FAILURE, - FETCH_ENDPOINT_METRICS_VALUES_BEGIN, - FETCH_ENDPOINT_METRICS_VALUES_SUCCESS, - FETCH_ENDPOINT_METRICS_VALUES_FAILURE, - SET_SELECTED_METRICS_OPTIONS -} from '../constants' - -import { - generateMetricsItems, - parseMetrics -} from '../components/DetailsMetrics/detailsMetrics.util' -import { TIME_FRAME_LIMITS } from '../utils/datePicker.util' -import { largeResponseCatchHandler } from '../utils/largeResponseCatchHandler' - -const modelEndpointsActions = { - fetchModelEndpointMetrics: (project, uid) => dispatch => { - dispatch(modelEndpointsActions.fetchEndpointMetricsBegin()) - - return modelEndpointsApi - .getModelEndpointMetrics(project, uid) - .then(({ data = [] }) => { - const metrics = generateMetricsItems(data) - - dispatch(modelEndpointsActions.fetchEndpointMetricsSuccess({ endpointUid: uid, metrics })) - - return metrics - }) - .catch(error => { - dispatch(modelEndpointsActions.fetchEndpointMetricsFailure(error)) - }) - }, - fetchEndpointMetricsBegin: () => ({ - type: FETCH_ENDPOINT_METRICS_BEGIN - }), - fetchEndpointMetricsFailure: error => ({ - type: FETCH_ENDPOINT_METRICS_FAILURE, - payload: error - }), - fetchEndpointMetricsSuccess: payload => ({ - type: FETCH_ENDPOINT_METRICS_SUCCESS, - payload - }), - fetchModelEndpointMetricsValues: ( - project, - uid, - params, - abortController, - setRequestErrorMessage = () => {} - ) => dispatch => { - const config = { - params, - ui: { - controller: abortController, - setRequestErrorMessage, - customErrorMessage: 'The query result is too large to display. Reduce either the number of metrics or the time period.' - } - } - - setRequestErrorMessage('') - dispatch(modelEndpointsActions.fetchEndpointMetricsValuesBegin()) - - return modelEndpointsApi - .getModelEndpointMetricsValues(project, uid, config) - .then(({ data = [] }) => { - const differenceInDays = params.end - params.start - const timeUnit = differenceInDays > TIME_FRAME_LIMITS['24_HOURS'] ? 'days' : 'hours' - const metrics = parseMetrics(data, timeUnit) - - dispatch(modelEndpointsActions.fetchEndpointMetricsValuesSuccess()) - - return metrics - }) - .catch(error => { - dispatch( - modelEndpointsActions.fetchEndpointMetricsValuesFailure( - error?.message === DEFAULT_ABORT_MSG ? null : error - ) - ) - largeResponseCatchHandler(error, 'Failed to fetch metrics', dispatch, setRequestErrorMessage) - }) - }, - fetchEndpointMetricsValuesBegin: () => ({ - type: FETCH_ENDPOINT_METRICS_VALUES_BEGIN - }), - fetchEndpointMetricsValuesFailure: error => ({ - type: FETCH_ENDPOINT_METRICS_VALUES_FAILURE, - payload: error - }), - fetchEndpointMetricsValuesSuccess: () => ({ - type: FETCH_ENDPOINT_METRICS_VALUES_SUCCESS - }), - setSelectedMetricsOptions: payload => ({ - type: SET_SELECTED_METRICS_OPTIONS, - payload - }) -} - -export default modelEndpointsActions diff --git a/src/components/AddToFeatureVectorPage/AddToFeatureVectorPage.js b/src/components/AddToFeatureVectorPage/AddToFeatureVectorPage.js index 9776d95d80..bbc2cd0ef6 100644 --- a/src/components/AddToFeatureVectorPage/AddToFeatureVectorPage.js +++ b/src/components/AddToFeatureVectorPage/AddToFeatureVectorPage.js @@ -224,10 +224,6 @@ const AddToFeatureVectorPage = () => { [fetchData, fetchTags] ) - const handleRefreshWithFilters = useCallback(() => { - handleRefresh(addToFeatureVectorFilters) - }, [addToFeatureVectorFilters, handleRefresh]) - const collapseRowCallback = useCallback( feature => { const newStoreSelectedRowData = { @@ -378,7 +374,6 @@ const AddToFeatureVectorPage = () => { filtersConfig={filtersConfig} filtersStore={filtersStore} handleRefresh={handleRefresh} - handleRefreshWithFilters={handleRefreshWithFilters} pageData={pageData} ref={addToFeatureVectorPageRef} requestErrorMessage={requestErrorMessage} diff --git a/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.js b/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.js index a40254c465..6632a35ffd 100644 --- a/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.js +++ b/src/components/AddToFeatureVectorPage/AddToFeatureVectorView.js @@ -47,7 +47,6 @@ const AddToFeatureVectorView = React.forwardRef( filtersConfig, filtersStore, handleRefresh, - handleRefreshWithFilters, pageData, requestErrorMessage, selectedRowData, @@ -98,7 +97,6 @@ const AddToFeatureVectorView = React.forwardRef( actionsMenu={actionsMenu} hideActionsMenu={tableStore.isTablePanelOpen} pageData={pageData} - retryRequest={handleRefreshWithFilters} tab={ADD_TO_FEATURE_VECTOR_TAB} tableClassName="features-table" tableHeaders={tableContent[0]?.content ?? []} @@ -139,7 +137,6 @@ AddToFeatureVectorView.propTypes = { filtersConfig: PropTypes.object.isRequired, filtersStore: PropTypes.object.isRequired, handleRefresh: PropTypes.func.isRequired, - handleRefreshWithFilters: PropTypes.func.isRequired, pageData: PropTypes.object.isRequired, requestErrorMessage: PropTypes.string.isRequired, selectedRowData: PropTypes.object.isRequired, diff --git a/src/components/Alerts/Alerts.js b/src/components/Alerts/Alerts.js index f569b55ce9..d44a1b5f60 100644 --- a/src/components/Alerts/Alerts.js +++ b/src/components/Alerts/Alerts.js @@ -64,22 +64,11 @@ const Alerts = () => { lastCheckedAlertIdRef, paginatedAlerts, paginationConfigAlertsRef, - refreshAlerts, requestErrorMessage, searchParams, - setAlerts, setSearchParams } = useAlertsPageData(alertsFilters, true) - const handleRefreshWithFilters = useCallback( - filters => { - setAlerts(null) - - return refreshAlerts(filters) - }, - [refreshAlerts, setAlerts] - ) - const tableContent = useMemo(() => { return paginatedAlerts.map(alert => createAlertRowData(alert, isCrossProjects)) }, [isCrossProjects, paginatedAlerts]) @@ -169,16 +158,14 @@ const Alerts = () => { filtersStore={filtersStore} handleCancel={handleCancel} handleRefreshAlerts={handleRefreshAlerts} - handleRefreshWithFilters={handleRefreshWithFilters} isCrossProjects={isCrossProjects} - pageData={pageData} - paginationConfigAlertsRef={paginationConfigAlertsRef} - requestErrorMessage={requestErrorMessage} - selectedAlert={selectedAlert} - setSearchParams={setSearchParams} - tableContent={tableContent} - /> - { [fetchData, fetchTags] ) - const handleRefreshWithFilters = useCallback(() => { - refreshDatasets(datasetsFilters) - }, [datasetsFilters, refreshDatasets]) - const handleAddTag = useCallback( artifact => { openPopUp(AddArtifactTagPopUp, { @@ -447,7 +443,6 @@ const Datasets = ({ isAllVersions = false }) => { filtersStore={filtersStore} getAndSetSelectedArtifact={getAndSetSelectedArtifact} handleRefreshDatasets={isAllVersions ? handleRefreshDatasetVersions : handleRefreshDatasets} - handleRefreshWithFilters={handleRefreshWithFilters} handleRegisterDataset={handleRegisterDataset} historyBackLink={historyBackLink} isAllVersions={isAllVersions} diff --git a/src/components/Datasets/DatasetsView.js b/src/components/Datasets/DatasetsView.js index 003607ac63..2af7439fe5 100644 --- a/src/components/Datasets/DatasetsView.js +++ b/src/components/Datasets/DatasetsView.js @@ -56,7 +56,6 @@ const DatasetsView = React.forwardRef( filtersStore, getAndSetSelectedArtifact, handleRefreshDatasets, - handleRefreshWithFilters, handleRegisterDataset, historyBackLink, isAllVersions, @@ -104,7 +103,8 @@ const DatasetsView = React.forwardRef( - {artifactsStore.loading ? null : tableContent.length === 0 && isEmpty(selectedDataset) ? ( + {artifactsStore.loading ? null : tableContent.length === 0 && + isEmpty(selectedDataset) ? ( setSelectedDataset({})} pageData={pageData} - retryRequest={handleRefreshWithFilters} selectedItem={selectedDataset} tableClassName="datasets-table" - tableHeaders={!isEmpty(tableHeaders) ? tableHeaders : getDefaultFirstHeader(isAllVersions)} + tableHeaders={ + !isEmpty(tableHeaders) ? tableHeaders : getDefaultFirstHeader(isAllVersions) + } viewMode={viewMode} > {tableContent.map((tableItem, index) => ( @@ -187,7 +188,6 @@ DatasetsView.propTypes = { filtersStore: PropTypes.object.isRequired, getAndSetSelectedArtifact: PropTypes.func.isRequired, handleRefreshDatasets: PropTypes.func.isRequired, - handleRefreshWithFilters: PropTypes.func.isRequired, handleRegisterDataset: PropTypes.func.isRequired, historyBackLink: PropTypes.string.isRequired, isAllVersions: PropTypes.bool.isRequired, diff --git a/src/components/Details/Details.js b/src/components/Details/Details.js index 7fcc4efad5..69aa19ff94 100644 --- a/src/components/Details/Details.js +++ b/src/components/Details/Details.js @@ -20,7 +20,7 @@ such restriction. import React, { useEffect, useCallback, useRef, useMemo, useState } from 'react' import PropTypes from 'prop-types' import { useLocation, useParams } from 'react-router-dom' -import { connect, useDispatch, useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { createForm } from 'final-form' import arrayMutators from 'final-form-arrays' import { Form } from 'react-final-form' @@ -30,14 +30,12 @@ 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 { TERTIARY_BUTTON, PRIMARY_BUTTON } from 'igz-controls/constants' -import detailsActions from '../../actions/details' import { ALERTS_PAGE, ARTIFACTS_PAGE, @@ -63,6 +61,17 @@ import { import { isEveryObjectValueEmpty } from '../../utils/isEveryObjectValueEmpty' import { showArtifactsPreview } from '../../reducers/artifactsReducer' import { setFieldState } from 'igz-controls/utils/form.util' +import { + removeDetailsPopUpInfoContent, + removeInfoContent, + removeModelFeatureVector, + resetChanges, + setDetailsPopUpInfoContent, + setEditMode, + setFiltersWasHandled, + setInfoContent, + showWarning +} from '../../reducers/detailsReducer' import './details.scss' @@ -79,22 +88,8 @@ const Details = ({ isDetailsPopUp = false, isDetailsScreen = false, pageData, - removeDetailsPopUpInfoContent, - removeInfoContent, - removeModelFeatureVector = () => {}, - resetChanges, - retryRequest = () => {}, selectedItem, - setChanges, - setChangesCounter, - setChangesData, - setDetailsPopUpInfoContent, setDetailsPopUpSelectedTab, - setFiltersWasHandled, - setInfoContent, - setIteration, - setIterationOption, - showWarning, tab = '', withActionMenu = true }) => { @@ -110,13 +105,7 @@ const Details = ({ return isDetailsPopUp ? [setDetailsPopUpInfoContent, removeDetailsPopUpInfoContent] : [setInfoContent, removeInfoContent] - }, [ - isDetailsPopUp, - removeDetailsPopUpInfoContent, - removeInfoContent, - setDetailsPopUpInfoContent, - setInfoContent - ]) + }, [isDetailsPopUp]) const previousPathnameRef = useRef( location.pathname.substring(0, location.pathname.lastIndexOf(params.tab)) ) @@ -148,17 +137,17 @@ const Details = ({ useEffect(() => { return () => { if (!isDetailsPopUp) { - resetChanges() + dispatch(resetChanges()) } } - }, [isDetailsPopUp, resetChanges]) + }, [dispatch, isDetailsPopUp]) useEffect(() => { if (!isEveryObjectValueEmpty(selectedItem)) { if (pageData.details.type === JOBS_PAGE) { - setDetailsInfo(generateJobsContent(selectedItem)) + dispatch(setDetailsInfo(generateJobsContent(selectedItem))) } else if (pageData.details.type === ALERTS_PAGE) { - setDetailsInfo(generateAlertsContent(selectedItem)) + dispatch(setDetailsInfo(generateAlertsContent(selectedItem))) } else if ( pageData.details.type === ARTIFACTS_PAGE || pageData.details.type === FILES_TAB || @@ -167,20 +156,24 @@ const Details = ({ pageData.details.type === DATASETS_TAB || pageData.details.type === DOCUMENTS_TAB ) { - setDetailsInfo( - generateArtifactsContent( - pageData.details.type, - selectedItem, - params.projectName, - isDetailsPopUp, - frontendSpec.internal_labels + dispatch( + setDetailsInfo( + generateArtifactsContent( + pageData.details.type, + selectedItem, + params.projectName, + isDetailsPopUp, + frontendSpec.internal_labels + ) ) ) } else if (pageData.details.type === FUNCTIONS_PAGE) { - setDetailsInfo(generateFunctionsContent(selectedItem)) + dispatch(setDetailsInfo(generateFunctionsContent(selectedItem))) } else { - setDetailsInfo( - generateFeatureStoreContent(pageData.details.type, selectedItem, isDetailsPopUp) + dispatch( + setDetailsInfo( + generateFeatureStoreContent(pageData.details.type, selectedItem, isDetailsPopUp) + ) ) } } @@ -191,24 +184,25 @@ const Details = ({ pageData.details.type, params.projectName, setDetailsInfo, - selectedItem + selectedItem, + dispatch ]) useEffect(() => { return () => { if (pageData.details.type === MODELS_TAB) { - removeModelFeatureVector() + dispatch(removeModelFeatureVector()) } - removeDetailsInfo() + dispatch(removeDetailsInfo()) } - }, [pageData.details.type, removeDetailsInfo, removeModelFeatureVector, selectedItem]) + }, [dispatch, pageData.details.type, removeDetailsInfo, selectedItem]) const handleShowWarning = useCallback( show => { - showWarning(show) + dispatch(showWarning(show)) }, - [showWarning] + [dispatch] ) const handleRefreshClick = useCallback( @@ -218,10 +212,10 @@ const Details = ({ document.getElementById('refresh')?.contains(event.target) ) { handleShowWarning(true) - setFiltersWasHandled(true) + dispatch(setFiltersWasHandled(true)) } }, - [detailsStore.changes.counter, handleShowWarning, setFiltersWasHandled] + [detailsStore.changes.counter, dispatch, handleShowWarning] ) useEffect(() => { @@ -269,17 +263,17 @@ const Details = ({ if (previousPathnameRef.current !== currentPathname && !isDetailsPopUp) { formRef.current.restart(formInitialValues) - dispatch(detailsActions.setEditMode(false)) + dispatch(setEditMode(false)) previousPathnameRef.current = currentPathname } }, [dispatch, formInitialValues, isDetailsPopUp, location.pathname, params.tab]) const applyChanges = useCallback(() => { applyDetailsChanges(detailsStore.changes).then(() => { - resetChanges() + 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) @@ -289,40 +283,33 @@ const Details = ({ applyDetailsChanges, applyDetailsChangesCallback, detailsStore.changes, - resetChanges, + dispatch, selectedItem ]) const cancelChanges = useCallback(() => { if (detailsStore.changes.counter > 0) { - resetChanges() - + dispatch(resetChanges()) formRef.current.reset(formInitialValues) } - }, [detailsStore.changes.counter, formInitialValues, resetChanges]) + }, [detailsStore.changes.counter, dispatch, formInitialValues]) const leavePage = useCallback(() => { cancelChanges() handleShowWarning(false) if (detailsStore.filtersWasHandled) { - setFiltersWasHandled(false) + dispatch(setFiltersWasHandled(false)) } else { blocker.proceed?.() } window.dispatchEvent(new CustomEvent('discardChanges')) - }, [ - blocker, - cancelChanges, - detailsStore.filtersWasHandled, - handleShowWarning, - setFiltersWasHandled - ]) + }, [blocker, cancelChanges, detailsStore.filtersWasHandled, dispatch, handleShowWarning]) const doNotLeavePage = useCallback(() => { blocker.reset?.() - dispatch(detailsActions.showWarning(false)) + dispatch(showWarning(false)) window.dispatchEvent(new CustomEvent('cancelLeave')) }, [blocker, dispatch]) @@ -346,7 +333,6 @@ const Details = ({ handleShowWarning={handleShowWarning} pageData={pageData} selectedItem={selectedItem} - setIteration={setIteration} tab={tab} withActionMenu={withActionMenu} /> @@ -369,11 +355,6 @@ const Details = ({ isDetailsPopUp={isDetailsPopUp} pageData={pageData} selectedItem={selectedItem} - setChanges={setChanges} - setChangesCounter={setChangesCounter} - setChangesData={setChangesData} - setIteration={setIteration} - setIterationOption={setIterationOption} /> {(blocker.state === 'blocked' || detailsStore.showWarning) && ( @@ -420,10 +401,8 @@ Details.propTypes = { handleRefresh: PropTypes.func, isDetailsScreen: PropTypes.bool, pageData: PropTypes.shape({}).isRequired, - removeModelFeatureVector: PropTypes.func, - retryRequest: PropTypes.func, selectedItem: PropTypes.shape({}).isRequired, tab: PropTypes.string } -export default connect(null, { ...detailsActions })(Details) +export default Details diff --git a/src/components/Details/DetailsHeader/DetailsHeader.js b/src/components/Details/DetailsHeader/DetailsHeader.js index 85e7a68963..f3211b8995 100644 --- a/src/components/Details/DetailsHeader/DetailsHeader.js +++ b/src/components/Details/DetailsHeader/DetailsHeader.js @@ -21,7 +21,7 @@ import React, { useCallback, useRef, useEffect, useState, useMemo } from 'react' import PropTypes from 'prop-types' import { Link, useLocation, useNavigate, useParams } from 'react-router-dom' import { isEmpty } from 'lodash' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import classNames from 'classnames' import { Button, Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' @@ -44,6 +44,7 @@ import { getDefaultCloseDetailsLink } from '../../../utils/link-helper.util' import { getFilteredSearchParams } from '../../../utils/filter.util' +import { setIteration } from '../../../reducers/detailsReducer' import { ReactComponent as Close } from 'igz-controls/images/close.svg' import { ReactComponent as Back } from 'igz-controls/images/back-arrow.svg' @@ -66,7 +67,6 @@ const DetailsHeader = ({ isDetailsPopUp, pageData, selectedItem, - setIteration, tab, withActionMenu = true }) => { @@ -78,6 +78,7 @@ const DetailsHeader = ({ const { actionButton, withToggleViewBtn, showAllVersions } = pageData.details const headerRef = useRef() const location = useLocation() + const dispatch = useDispatch() const errorMessage = useMemo( () => @@ -236,7 +237,7 @@ const DetailsHeader = ({ key="Iteration" label="Iteration:" onClick={option => { - setIteration(option) + dispatch(setIteration(option)) }} options={detailsStore.iterationOptions} selectedId={detailsStore.iteration} @@ -374,7 +375,6 @@ DetailsHeader.propTypes = { isDetailsScreen: PropTypes.bool.isRequired, pageData: PropTypes.shape({}).isRequired, selectedItem: PropTypes.shape({}).isRequired, - setIteration: PropTypes.func.isRequired, tab: PropTypes.string } diff --git a/src/components/Details/DetailsTabsContent/DetailsTabsContent.js b/src/components/Details/DetailsTabsContent/DetailsTabsContent.js index efeeca38cd..27f2541eac 100644 --- a/src/components/Details/DetailsTabsContent/DetailsTabsContent.js +++ b/src/components/Details/DetailsTabsContent/DetailsTabsContent.js @@ -77,12 +77,7 @@ const DetailsTabsContent = ({ handlePreview, isDetailsPopUp = false, pageData, - selectedItem, - setChanges, - setChangesCounter, - setChangesData, - setIteration, - setIterationOption + selectedItem }) => { const detailsStore = useSelector(store => store.detailsStore) const params = useParams() @@ -97,8 +92,6 @@ const DetailsTabsContent = ({ pageData={pageData} ref={applyChangesRef} selectedItem={selectedItem} - setChangesCounter={setChangesCounter} - setChangesData={setChangesData} /> ) case DETAILS_DRIFT_ANALYSIS_TAB: @@ -138,8 +131,6 @@ const DetailsTabsContent = ({ isDetailsPopUp={isDetailsPopUp} iteration={detailsStore.iteration} selectedItem={selectedItem} - setIteration={setIteration} - setIterationOption={setIterationOption} /> ) case DETAILS_RESULTS_TAB: @@ -229,9 +220,6 @@ const DetailsTabsContent = ({ formState={formState} isDetailsPopUp={isDetailsPopUp} selectedItem={selectedItem} - setChanges={setChanges} - setChangesData={setChangesData} - setChangesCounter={setChangesCounter} /> ) case DETAILS_ALERT_APPLICATION: @@ -243,8 +231,6 @@ const DetailsTabsContent = ({ pageData={pageData} ref={applyChangesRef} selectedItem={selectedItem} - setChangesCounter={setChangesCounter} - setChangesData={setChangesData} /> ) case DETAILS_COLLECTIONS_TAB: @@ -257,12 +243,7 @@ const DetailsTabsContent = ({ DetailsTabsContent.propTypes = { handlePreview: PropTypes.func.isRequired, pageData: PropTypes.shape({}).isRequired, - selectedItem: PropTypes.shape({}).isRequired, - setChanges: PropTypes.func.isRequired, - setChangesCounter: PropTypes.func.isRequired, - setChangesData: PropTypes.func.isRequired, - setIteration: PropTypes.func.isRequired, - setIterationOption: PropTypes.func.isRequired + selectedItem: PropTypes.shape({}).isRequired } export default React.memo(DetailsTabsContent) diff --git a/src/components/Details/details.util.js b/src/components/Details/details.util.js index 7d821c7e62..0294287cf5 100644 --- a/src/components/Details/details.util.js +++ b/src/components/Details/details.util.js @@ -46,7 +46,12 @@ import { formatDatetime, 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 detailsActions from '../../actions/details' +import { + setChangesCounter, + setChangesData, + setFiltersWasHandled, + showWarning +} from '../../reducers/detailsReducer' export const generateArtifactsContent = ( detailsType, @@ -498,10 +503,9 @@ export const handleFinishEdit = ( changes, detailsTabActions, detailsTabDispatch, - setChangesData, - setChangesCounter, currentField, formState, + dispatch, fields ) => { detailsTabDispatch({ @@ -541,8 +545,8 @@ export const handleFinishEdit = ( }) } - setChangesCounter(countChanges(changesData)) - setChangesData({ ...changesData }) + dispatch(setChangesCounter(countChanges(changesData))) + dispatch(setChangesData({ ...changesData })) } export const countChanges = changesData => { @@ -596,8 +600,8 @@ export const performDetailsActionHelper = async (changes, dispatch, filtersWasHa window.addEventListener('discardChanges', () => resolver(true)) window.addEventListener('cancelLeave', () => resolver(false)) - dispatch(detailsActions.setFiltersWasHandled(filtersWasHandled)) - dispatch(detailsActions.showWarning(true)) + dispatch(setFiltersWasHandled(filtersWasHandled)) + dispatch(showWarning(true)) }) } diff --git a/src/components/DetailsArtifacts/DetailsArtifacts.js b/src/components/DetailsArtifacts/DetailsArtifacts.js index a967f0300e..fdd0f03268 100644 --- a/src/components/DetailsArtifacts/DetailsArtifacts.js +++ b/src/components/DetailsArtifacts/DetailsArtifacts.js @@ -39,6 +39,7 @@ import { ALLOW_SORT_BY, DEFAULT_SORT_BY, EXCLUDE_SORT_BY } from 'igz-controls/ty import { fetchArtifacts } from '../../reducers/artifactsReducer' import { getChipLabelAndValue } from '../../utils/getChipLabelAndValue' import { fetchJob } from '../../reducers/jobReducer' +import { setIteration, setIterationOption } from '../../reducers/detailsReducer' import './detailsArtifacts.scss' @@ -49,9 +50,7 @@ const DetailsArtifacts = ({ excludeSortBy = null, isDetailsPopUp = false, iteration, - selectedItem, - setIteration, - setIterationOption + selectedItem }) => { const [artifactsPreviewContent, setArtifactsPreviewContent] = useState([]) const [artifactsIds, setArtifactsIds] = useState([]) @@ -114,29 +113,31 @@ const DetailsArtifacts = ({ } }) - setIterationOption( - iterationsList - .sort((a, b) => a - b) - .map(iteration => ({ - label: - iteration === bestIteration ? `${bestIteration} (Best iteration)` : `${iteration}`, - id: `${iteration}` - })) + dispatch( + setIterationOption( + iterationsList + .sort((a, b) => a - b) + .map(iteration => ({ + label: + iteration === bestIteration ? `${bestIteration} (Best iteration)` : `${iteration}`, + id: `${iteration}` + })) + ) ) } - }, [bestIteration, selectedItem.iterationStats, setIterationOption]) + }, [bestIteration, dispatch, selectedItem.iterationStats]) useEffect(() => { if (!isNaN(parseInt(bestIteration))) { - setIteration(`${bestIteration}`) + dispatch(setIteration(`${bestIteration}`)) } else if (selectedItem.iterationStats?.length > 0 && iterationOptions?.length > 0) { - setIteration(iterationOptions[0].id) + dispatch(setIteration(iterationOptions[0].id)) } return () => { - setIteration('') + dispatch(setIteration('')) } - }, [bestIteration, setIteration, selectedItem.iterationStats, iterationOptions]) + }, [bestIteration, selectedItem.iterationStats, iterationOptions, dispatch]) const getJobArtifacts = useCallback( (job, iteration) => { @@ -150,13 +151,12 @@ const DetailsArtifacts = ({ return dispatch( fetchJob({ project: job.project || params.projectName, - jobId: job.uid || params.jobId, + jobId: job.uid || params.jobId, iter: iteration }) ) .unwrap() - .then( - responseJob => { + .then(responseJob => { if (responseJob) { const selectedJob = getJobAccordingIteration(responseJob) @@ -164,8 +164,7 @@ const DetailsArtifacts = ({ generateArtifactsPreviewContent(selectedJob, selectedJob.artifacts) ) } - } - ) + }) } else { if (iteration) { config.params.iter = iteration @@ -280,8 +279,7 @@ DetailsArtifacts.propTypes = { defaultDirection: PropTypes.string, excludeSortBy: EXCLUDE_SORT_BY, iteration: PropTypes.string.isRequired, - selectedItem: PropTypes.shape({}).isRequired, - setIterationOption: PropTypes.func.isRequired + selectedItem: PropTypes.shape({}).isRequired } export default DetailsArtifacts diff --git a/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.js b/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.js index 29b2e42a6f..48a3efddb8 100644 --- a/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.js +++ b/src/components/DetailsDrillDownAlert/DetailsAlertsMetrics.js @@ -29,16 +29,14 @@ import NoMetricData from '../DetailsMetrics/MetricsCards/NoMetricData' import StatsCard from '../../common/StatsCard/StatsCard' import { REQUEST_CANCELED } from '../../constants' -import detailsActions from '../../actions/details' -import modelEndpointsActions from '../../actions/modelEndpoints' import { groupMetricByApplication } from '../../elements/MetricsSelector/metricsSelector.util' - import { CUSTOM_RANGE_DATE_OPTION, datePickerPastOptions, PAST_24_HOUR_DATE_OPTION, TIME_FRAME_LIMITS } from '../../utils/datePicker.util' +import { fetchModelEndpointMetricsValues, setDetailsDates } from '../../reducers/detailsReducer' import { ReactComponent as MetricsIcon } from 'igz-controls/images/metrics-icon.svg' @@ -65,7 +63,7 @@ const DetailsAlertsMetrics = ({ selectedItem, filters, isAlertsPage = true }) => } dispatch( - detailsActions.setDetailsDates({ + setDetailsDates({ value: generatedDates, selectedOptionId, isPredefined @@ -88,13 +86,13 @@ const DetailsAlertsMetrics = ({ selectedItem, filters, isAlertsPage = true }) => metricsValuesAbortController.current = new AbortController() return dispatch( - modelEndpointsActions.fetchModelEndpointMetricsValues( - projectName, + fetchModelEndpointMetricsValues({ + project: projectName, uid, params, - metricsValuesAbortController.current, + abortController: metricsValuesAbortController.current, setRequestErrorMessage - ) + }) ) }, [dispatch, metricsValuesAbortController] diff --git a/src/components/DetailsDrillDownAlert/DetailsDrillDownAlert.js b/src/components/DetailsDrillDownAlert/DetailsDrillDownAlert.js index 6e23d34f43..d9a89bb4ad 100644 --- a/src/components/DetailsDrillDownAlert/DetailsDrillDownAlert.js +++ b/src/components/DetailsDrillDownAlert/DetailsDrillDownAlert.js @@ -34,18 +34,7 @@ import { ReactComponent as EnlargeIcon } from 'igz-controls/images/ml-enlarge.sv import '../DetailsInfo/detailsInfo.scss' const DetailsDrillDownAlert = React.forwardRef( - ( - { - detailsStore, - formState, - isDetailsPopUp, - pageData, - selectedItem, - setChangesCounter, - setChangesData - }, - applyChangesRef - ) => { + ({ detailsStore, formState, isDetailsPopUp, pageData, selectedItem }, applyChangesRef) => { const openAlertsLogsModal = useCallback(() => { openPopUp(AlertLogsModal, { selectedItem, pageData }) }, [pageData, selectedItem]) @@ -59,8 +48,6 @@ const DetailsDrillDownAlert = React.forwardRef( pageData={pageData} ref={applyChangesRef} selectedItem={selectedItem} - setChangesCounter={setChangesCounter} - setChangesData={setChangesData} /> {pageData.details.entityType === JOB && ( <> @@ -97,9 +84,7 @@ DetailsDrillDownAlert.propTypes = { detailsStore: PropTypes.shape({}).isRequired, isDetailsPopUp: PropTypes.bool.isRequired, pageData: PropTypes.shape({}).isRequired, - selectedItem: PropTypes.shape({}).isRequired, - setChangesData: PropTypes.func.isRequired, - setChangesCounter: PropTypes.func.isRequired + selectedItem: PropTypes.shape({}).isRequired } DetailsInfo.displayName = 'DetailsDrillDownAlert' diff --git a/src/components/DetailsInfo/DetailsInfo.js b/src/components/DetailsInfo/DetailsInfo.js index f60c0945a3..62a8afaa9f 100644 --- a/src/components/DetailsInfo/DetailsInfo.js +++ b/src/components/DetailsInfo/DetailsInfo.js @@ -24,7 +24,6 @@ import { useDispatch } from 'react-redux' import DetailsInfoView from './DetailsInfoView' -import detailsActions from '../../actions/details' import { detailsInfoActions, detailsInfoReducer, initialState } from './detailsInfoReducer' import { handleFinishEdit } from '../Details/details.util' import { isEveryObjectValueEmpty } from '../../utils/isEveryObjectValueEmpty' @@ -36,20 +35,10 @@ import { generateSourcesDetailsInfo, generateAlertsDetailsInfo } from './detailsInfo.util' +import { setEditMode } from '../../reducers/detailsReducer' const DetailsInfo = React.forwardRef( - ( - { - detailsStore, - formState, - isDetailsPopUp, - pageData, - selectedItem, - setChangesCounter, - setChangesData - }, - applyChangesRef - ) => { + ({ detailsStore, formState, isDetailsPopUp, pageData, selectedItem }, applyChangesRef) => { const location = useLocation() const [detailsInfoState, detailsInfoDispatch] = useReducer(detailsInfoReducer, initialState) const params = useParams() @@ -66,7 +55,7 @@ const DetailsInfo = React.forwardRef( detailsInfoDispatch({ type: detailsInfoActions.RESET_EDIT_MODE }) - dispatch(detailsActions.setEditMode(false)) + dispatch(setEditMode(false)) } }, [applyChangesRef, dispatch] @@ -94,7 +83,7 @@ const DetailsInfo = React.forwardRef( detailsInfoDispatch({ type: detailsInfoActions.RESET_EDIT_MODE }) - dispatch(detailsActions.setEditMode(false)) + dispatch(setEditMode(false)) }, [dispatch]) const handleInfoItemClick = useCallback( @@ -107,16 +96,13 @@ const DetailsInfo = React.forwardRef( fieldType } }) - dispatch(detailsActions.setEditMode(true)) + dispatch(setEditMode(true)) } }, [detailsInfoState.editMode, dispatch] ) - const sources = useMemo( - () => generateSourcesDetailsInfo(selectedItem), - [selectedItem] - ) + const sources = useMemo(() => generateSourcesDetailsInfo(selectedItem), [selectedItem]) const producer = useMemo( () => generateProducerDetailsInfo(selectedItem, isDetailsPopUp), @@ -139,19 +125,18 @@ const DetailsInfo = React.forwardRef( const finishEdit = useCallback( currentField => { - dispatch(detailsActions.setEditMode(false)) + dispatch(setEditMode(false)) return handleFinishEdit( detailsStore.changes, detailsInfoActions, detailsInfoDispatch, - setChangesData, - setChangesCounter, currentField, - formState + formState, + dispatch ) }, - [detailsStore.changes, dispatch, formState, setChangesCounter, setChangesData] + [detailsStore.changes, dispatch, formState] ) return ( @@ -169,7 +154,6 @@ const DetailsInfo = React.forwardRef( params={params} ref={editItemRef} selectedItem={selectedItem} - setChangesData={setChangesData} /> ) } @@ -179,9 +163,7 @@ DetailsInfo.propTypes = { detailsStore: PropTypes.shape({}).isRequired, formState: PropTypes.shape({}), pageData: PropTypes.shape({}).isRequired, - selectedItem: PropTypes.shape({}).isRequired, - setChangesData: PropTypes.func.isRequired, - setChangesCounter: PropTypes.func.isRequired + selectedItem: PropTypes.shape({}).isRequired } DetailsInfo.displayName = 'DetailsInfo' diff --git a/src/components/DetailsInfo/DetailsInfoView.js b/src/components/DetailsInfo/DetailsInfoView.js index 49d8bb92ac..f4933418e3 100644 --- a/src/components/DetailsInfo/DetailsInfoView.js +++ b/src/components/DetailsInfo/DetailsInfoView.js @@ -65,8 +65,7 @@ const DetailsInfoView = React.forwardRef( isDetailsPopUp, pageData, params, - selectedItem, - setChangesData + selectedItem }, ref ) => { @@ -194,7 +193,6 @@ const DetailsInfoView = React.forwardRef( onClick={handleInfoItemClick} params={params} ref={ref} - setChangesData={setChangesData} state={state} /> diff --git a/src/components/DetailsMetrics/DetailsMetrics.js b/src/components/DetailsMetrics/DetailsMetrics.js index a8abf8640f..728b4e83b4 100644 --- a/src/components/DetailsMetrics/DetailsMetrics.js +++ b/src/components/DetailsMetrics/DetailsMetrics.js @@ -30,8 +30,6 @@ import ApplicationMetricCard from './MetricsCards/ApplicationMetricCard' import NoData from '../../common/NoData/NoData' import { REQUEST_CANCELED } from '../../constants' -import detailsActions from '../../actions/details' -import modelEndpointsActions from '../../actions/modelEndpoints' import { groupMetricByApplication } from '../../elements/MetricsSelector/metricsSelector.util' import { @@ -50,6 +48,12 @@ import { import { ReactComponent as MetricsIcon } from 'igz-controls/images/metrics-icon.svg' import './DetailsMetrics.scss' +import { + fetchModelEndpointMetrics, + fetchModelEndpointMetricsValues, + setDetailsDates, + setSelectedMetricsOptions +} from '../../reducers/detailsReducer' const DetailsMetrics = ({ selectedItem }) => { const [metrics, setMetrics] = useState([]) @@ -93,7 +97,7 @@ const DetailsMetrics = ({ selectedItem }) => { } dispatch( - detailsActions.setDetailsDates({ + setDetailsDates({ value: generatedDates, selectedOptionId, isPredefined @@ -113,11 +117,13 @@ const DetailsMetrics = ({ selectedItem }) => { useEffect(() => { dispatch( - modelEndpointsActions.fetchModelEndpointMetrics( - selectedItem.metadata.project, - selectedItem.metadata.uid - ) - ).then(() => setMetricOptionsAreLoaded(true)) + fetchModelEndpointMetrics({ + project: selectedItem.metadata.project, + uid: selectedItem.metadata.uid + }) + ) + .unwrap() + .then(() => setMetricOptionsAreLoaded(true)) }, [dispatch, selectedItem.metadata.project, selectedItem.metadata.uid]) useEffect(() => { @@ -133,23 +139,23 @@ const DetailsMetrics = ({ selectedItem }) => { return Promise.all([ dispatch( - modelEndpointsActions.fetchModelEndpointMetricsValues( - selectedItemProject, - selectedItemUid, - selectedMetricsParams, - metricsValuesAbortController.current, + fetchModelEndpointMetricsValues({ + project: selectedItemProject, + uid: selectedItemUid, + params: selectedMetricsParams, + abortController: metricsValuesAbortController.current, setRequestErrorMessage - ) - ), + }) + ).unwrap(), dispatch( - modelEndpointsActions.fetchModelEndpointMetricsValues( - selectedItemProject, - selectedItemUid, - preInvocationMetricParams, - metricsValuesAbortController.current, + fetchModelEndpointMetricsValues({ + project: selectedItemProject, + uid: selectedItemUid, + params: preInvocationMetricParams, + abortController: metricsValuesAbortController.current, setRequestErrorMessage - ) - ) + }) + ).unwrap() ]).then(([metrics, previousInvocation]) => { if (metrics) setMetrics(metrics) @@ -236,7 +242,7 @@ const DetailsMetrics = ({ selectedItem }) => { metrics={detailsStore.metricsOptions.all} onSelect={metrics => dispatch( - modelEndpointsActions.setSelectedMetricsOptions({ + setSelectedMetricsOptions({ endpointUid: selectedItem.metadata.uid, metrics }) diff --git a/src/components/DetailsRequestedFeatures/DetailsRequestedFeatures.js b/src/components/DetailsRequestedFeatures/DetailsRequestedFeatures.js index 3a671eb232..05b6599845 100644 --- a/src/components/DetailsRequestedFeatures/DetailsRequestedFeatures.js +++ b/src/components/DetailsRequestedFeatures/DetailsRequestedFeatures.js @@ -20,26 +20,21 @@ such restriction. import React, { useCallback, useEffect, useState } from 'react' import PropTypes from 'prop-types' import { cloneDeep, isEqual, isNil } from 'lodash' +import { useDispatch } from 'react-redux' import DetailsRequestedFeaturesView from './DetailsRequestedFeaturesView' import { countChanges } from '../Details/details.util.js' +import { setChanges, setChangesCounter, setChangesData } from '../../reducers/detailsReducer' -const DetailsRequestedFeatures = ({ - changes, - formState, - isDetailsPopUp = false, - selectedItem, - setChanges, - setChangesData, - setChangesCounter -}) => { +const DetailsRequestedFeatures = ({ changes, formState, isDetailsPopUp = false, selectedItem }) => { const [confirmDialogData, setConfirmDialogData] = useState({ index: null, feature: null }) const [editableItemIndex, setEditableItemIndex] = useState(null) const [labelFeatureIsEditable, setLabelFeatureIsEditable] = useState(false) + const dispatch = useDispatch() useEffect(() => { return () => { @@ -90,15 +85,15 @@ const DetailsRequestedFeatures = ({ } } - setChangesCounter(countChanges(changesData)) - setChangesData({ ...changesData }) + dispatch(setChangesCounter(countChanges(changesData))) + dispatch(setChangesData({ ...changesData })) }, [ changes.data, + dispatch, editableItemIndex, - formState, - labelFeatureIsEditable, - setChangesCounter, - setChangesData + formState.initialValues.features, + formState.values.features, + labelFeatureIsEditable ]) const handleDelete = index => { @@ -131,10 +126,12 @@ const DetailsRequestedFeatures = ({ } formState.form.change('features', updatedFeatures) - setChanges({ - data: changesData, - counter: countChanges(changesData) - }) + dispatch( + setChanges({ + data: changesData, + counter: countChanges(changesData) + }) + ) setConfirmDialogData({ index: null, feature: null }) } @@ -170,10 +167,7 @@ const DetailsRequestedFeatures = ({ DetailsRequestedFeatures.propTypes = { changes: PropTypes.object.isRequired, formState: PropTypes.object.isRequired, - selectedItem: PropTypes.shape({}).isRequired, - setChanges: PropTypes.func.isRequired, - setChangesData: PropTypes.func.isRequired, - setChangesCounter: PropTypes.func.isRequired + selectedItem: PropTypes.shape({}).isRequired } export default DetailsRequestedFeatures diff --git a/src/components/Documents/Documents.js b/src/components/Documents/Documents.js index 2bb0eb47ff..e859c5bcf3 100644 --- a/src/components/Documents/Documents.js +++ b/src/components/Documents/Documents.js @@ -217,10 +217,6 @@ const Documents = ({ isAllVersions = false }) => { [fetchData, fetchTags] ) - const handleRefreshWithFilters = useCallback(() => { - refreshDocuments(documentsFilters) - }, [documentsFilters, refreshDocuments]) - const handleAddTag = useCallback( artifact => { openPopUp(AddArtifactTagPopUp, { @@ -440,7 +436,6 @@ const Documents = ({ isAllVersions = false }) => { handleRefreshDocuments={ isAllVersions ? handleRefreshDocumentVersions : handleRefreshDocuments } - handleRefreshWithFilters={handleRefreshWithFilters} historyBackLink={historyBackLink} isAllVersions={isAllVersions} isSelectedArtifactBeyondTheList={isSelectedArtifactBeyondTheList} diff --git a/src/components/Documents/DocumentsView.js b/src/components/Documents/DocumentsView.js index 6848d06b93..1b09eba713 100644 --- a/src/components/Documents/DocumentsView.js +++ b/src/components/Documents/DocumentsView.js @@ -53,7 +53,6 @@ const DocumentsView = React.forwardRef( filtersStore, getAndSetSelectedArtifact, handleRefreshDocuments, - handleRefreshWithFilters, historyBackLink, isAllVersions, pageData, @@ -119,10 +118,11 @@ const DocumentsView = React.forwardRef( } handleCancel={() => setSelectedDocument({})} pageData={pageData} - retryRequest={handleRefreshWithFilters} selectedItem={selectedDocument} tableClassName="documents-table" - tableHeaders={!isEmpty(tableHeaders) ? tableHeaders : getDefaultFirstHeader(isAllVersions)} + tableHeaders={ + !isEmpty(tableHeaders) ? tableHeaders : getDefaultFirstHeader(isAllVersions) + } viewMode={viewMode} > {tableContent.map((tableItem, index) => ( @@ -175,7 +175,6 @@ DocumentsView.propTypes = { filtersStore: PropTypes.object.isRequired, getAndSetSelectedArtifact: PropTypes.func.isRequired, handleRefreshDocuments: PropTypes.func.isRequired, - handleRefreshWithFilters: PropTypes.func.isRequired, historyBackLink: PropTypes.string.isRequired, isAllVersions: PropTypes.bool.isRequired, pageData: PropTypes.object.isRequired, diff --git a/src/components/FeatureStore/FeatureSets/FeatureSets.js b/src/components/FeatureStore/FeatureSets/FeatureSets.js index 3ae2d960aa..46cd6c051c 100644 --- a/src/components/FeatureStore/FeatureSets/FeatureSets.js +++ b/src/components/FeatureStore/FeatureSets/FeatureSets.js @@ -166,10 +166,6 @@ const FeatureSets = () => { [fetchData, fetchTags] ) - const handleRefreshWithFilters = useCallback(() => { - handleRefresh(featureSetsFilters) - }, [featureSetsFilters, handleRefresh]) - const collapseRowCallback = useCallback( featureSet => { const newStoreSelectedRowData = { @@ -445,7 +441,6 @@ const FeatureSets = () => { featureStore={featureStore} filtersStore={filtersStore} filters={featureSetsFilters} - handleRefreshWithFilters={handleRefreshWithFilters} handleRefresh={handleRefresh} pageData={pageData} ref={{ featureStoreRef }} diff --git a/src/components/FeatureStore/FeatureSets/FeatureSetsView.js b/src/components/FeatureStore/FeatureSets/FeatureSetsView.js index b91eb17651..7a366fce0b 100644 --- a/src/components/FeatureStore/FeatureSets/FeatureSetsView.js +++ b/src/components/FeatureStore/FeatureSets/FeatureSetsView.js @@ -53,7 +53,6 @@ const FeatureSetsView = React.forwardRef( filtersStore, filters, handleRefresh, - handleRefreshWithFilters, pageData, requestErrorMessage, selectedFeatureSet, @@ -115,7 +114,6 @@ const FeatureSetsView = React.forwardRef( detailsFormInitialValues={detailsFormInitialValues} handleCancel={() => setSelectedFeatureSetMin({})} pageData={pageData} - retryRequest={handleRefreshWithFilters} selectedItem={selectedFeatureSet} tab={FEATURE_SETS_TAB} tableClassName="feature-sets-table" @@ -164,7 +162,6 @@ FeatureSetsView.propTypes = { featureStore: PropTypes.object.isRequired, filtersStore: PropTypes.object.isRequired, handleRefresh: PropTypes.func.isRequired, - handleRefreshWithFilters: PropTypes.func.isRequired, pageData: PropTypes.object.isRequired, requestErrorMessage: PropTypes.string.isRequired, selectedFeatureSet: PropTypes.object.isRequired, diff --git a/src/components/FeatureStore/FeatureVectors/FeatureVectors.js b/src/components/FeatureStore/FeatureVectors/FeatureVectors.js index 8570748d75..ac157b663f 100644 --- a/src/components/FeatureStore/FeatureVectors/FeatureVectors.js +++ b/src/components/FeatureStore/FeatureVectors/FeatureVectors.js @@ -250,10 +250,6 @@ const FeatureVectors = () => { [fetchData, fetchTags] ) - const handleRefreshWithFilters = useCallback(() => { - handleRefresh(featureVectorsFilters) - }, [featureVectorsFilters, handleRefresh]) - const collapseRowCallback = useCallback( featureVector => { const newStoreSelectedRowData = { @@ -504,7 +500,6 @@ const FeatureVectors = () => { filters={featureVectorsFilters} filtersStore={filtersStore} handleRefresh={handleRefresh} - handleRefreshWithFilters={handleRefreshWithFilters} pageData={pageData} ref={{ featureStoreRef }} requestErrorMessage={requestErrorMessage} diff --git a/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.js b/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.js index 2f159806e9..ceeb685979 100644 --- a/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.js +++ b/src/components/FeatureStore/FeatureVectors/FeatureVectorsView.js @@ -49,7 +49,6 @@ const FeatureVectorsView = React.forwardRef( filters, filtersStore, handleRefresh, - handleRefreshWithFilters, pageData, requestErrorMessage, selectedFeatureVector, @@ -107,7 +106,6 @@ const FeatureVectorsView = React.forwardRef( detailsFormInitialValues={detailsFormInitialValues} handleCancel={() => setSelectedFeatureVector({})} pageData={pageData} - retryRequest={handleRefreshWithFilters} selectedItem={selectedFeatureVector} tab={FEATURE_VECTORS_TAB} tableClassName="feature-vectors-table" @@ -155,7 +153,6 @@ FeatureVectorsView.propTypes = { filters: PropTypes.object.isRequired, filtersStore: PropTypes.object.isRequired, handleRefresh: PropTypes.func.isRequired, - handleRefreshWithFilters: PropTypes.func.isRequired, pageData: PropTypes.object.isRequired, requestErrorMessage: PropTypes.string.isRequired, selectedFeatureVector: PropTypes.object.isRequired, diff --git a/src/components/FeatureStore/Features/Features.js b/src/components/FeatureStore/Features/Features.js index 2f8cc18f0e..267ba0f781 100644 --- a/src/components/FeatureStore/Features/Features.js +++ b/src/components/FeatureStore/Features/Features.js @@ -180,10 +180,6 @@ const Features = () => { [dispatch, fetchData, fetchTags] ) - const handleRefreshWithFilters = useCallback(() => { - handleRefresh(featuresFilters) - }, [featuresFilters, handleRefresh]) - const collapseRowCallback = useCallback( feature => { const newStoreSelectedRowData = @@ -342,7 +338,6 @@ const Features = () => { filters={featuresFilters} getPopUpTemplate={getPopUpTemplate} handleRefresh={handleRefresh} - handleRefreshWithFilters={handleRefreshWithFilters} pageData={pageData} ref={{ featureStoreRef }} requestErrorMessage={requestErrorMessage} diff --git a/src/components/FeatureStore/Features/FeaturesView.js b/src/components/FeatureStore/Features/FeaturesView.js index ac2b4276b9..fabedb09d7 100644 --- a/src/components/FeatureStore/Features/FeaturesView.js +++ b/src/components/FeatureStore/Features/FeaturesView.js @@ -45,7 +45,6 @@ const FeaturesView = React.forwardRef( filtersStore, getPopUpTemplate, handleRefresh, - handleRefreshWithFilters, pageData, requestErrorMessage, selectedRowData, @@ -101,7 +100,6 @@ const FeaturesView = React.forwardRef( actionsMenu={actionsMenu} hideActionsMenu={tableStore.isTablePanelOpen} pageData={pageData} - retryRequest={handleRefreshWithFilters} tab={FEATURES_TAB} tableClassName="features-table" tableHeaders={tableContent[0]?.content ?? []} @@ -141,7 +139,6 @@ FeaturesView.propTypes = { filtersStore: PropTypes.object.isRequired, getPopUpTemplate: PropTypes.func.isRequired, handleRefresh: PropTypes.func.isRequired, - handleRefreshWithFilters: PropTypes.func.isRequired, pageData: PropTypes.object.isRequired, requestErrorMessage: PropTypes.string.isRequired, selectedRowData: PropTypes.object.isRequired, diff --git a/src/components/Files/Files.js b/src/components/Files/Files.js index 0dc4ea38ef..32402349cd 100644 --- a/src/components/Files/Files.js +++ b/src/components/Files/Files.js @@ -220,10 +220,6 @@ const Files = ({ isAllVersions = false }) => { [fetchData, fetchTags] ) - const handleRefreshWithFilters = useCallback(() => { - refreshFiles(filesFilters) - }, [filesFilters, refreshFiles]) - const handleAddTag = useCallback( artifact => { openPopUp(AddArtifactTagPopUp, { @@ -445,7 +441,6 @@ const Files = ({ isAllVersions = false }) => { filtersStore={filtersStore} getAndSetSelectedArtifact={getAndSetSelectedArtifact} handleRefreshFiles={isAllVersions ? handleRefreshFileVersions : handleRefreshFiles} - handleRefreshWithFilters={handleRefreshWithFilters} handleRegisterArtifact={handleRegisterArtifact} historyBackLink={historyBackLink} isAllVersions={isAllVersions} diff --git a/src/components/Files/FilesView.js b/src/components/Files/FilesView.js index 0422045869..4bc9729c8b 100644 --- a/src/components/Files/FilesView.js +++ b/src/components/Files/FilesView.js @@ -56,7 +56,6 @@ const FilesView = React.forwardRef( filtersStore, getAndSetSelectedArtifact, handleRefreshFiles, - handleRefreshWithFilters, handleRegisterArtifact, historyBackLink, isAllVersions, @@ -129,10 +128,11 @@ const FilesView = React.forwardRef( } handleCancel={() => setSelectedFile({})} pageData={pageData} - retryRequest={handleRefreshWithFilters} selectedItem={selectedFile} tableClassName="files-table" - tableHeaders={!isEmpty(tableHeaders) ? tableHeaders : getDefaultFirstHeader(isAllVersions)} + tableHeaders={ + !isEmpty(tableHeaders) ? tableHeaders : getDefaultFirstHeader(isAllVersions) + } viewMode={viewMode} > {tableContent.map((tableItem, index) => ( @@ -188,7 +188,6 @@ FilesView.propTypes = { filtersStore: PropTypes.object.isRequired, getAndSetSelectedArtifact: PropTypes.func.isRequired, handleRefreshFiles: PropTypes.func.isRequired, - handleRefreshWithFilters: PropTypes.func.isRequired, handleRegisterArtifact: PropTypes.func.isRequired, historyBackLink: PropTypes.string.isRequired, isAllVersions: PropTypes.bool.isRequired, diff --git a/src/components/FilterMenu/FilterMenu.js b/src/components/FilterMenu/FilterMenu.js index bf7ddb6fd8..4ddf636128 100644 --- a/src/components/FilterMenu/FilterMenu.js +++ b/src/components/FilterMenu/FilterMenu.js @@ -52,11 +52,11 @@ import { STATUS_FILTER, TAG_FILTER } from '../../constants' -import detailsActions from '../../actions/details' 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 './filterMenu.scss' @@ -170,8 +170,8 @@ const FilterMenu = ({ } window.addEventListener('discardChanges', handleDiscardChanges) - dispatch(detailsActions.setFiltersWasHandled(true)) - dispatch(detailsActions.showWarning(true)) + dispatch(setFiltersWasHandled(true)) + dispatch(showWarning(true)) }) } @@ -450,18 +450,18 @@ const FilterMenu = ({ })} {actionButton && - !actionButton.hidden && - (actionButton.getCustomTemplate ? ( - actionButton.getCustomTemplate(actionButton) - ) : ( -