From 6205558012bc11a269d6ea6495ad472e32c1d428 Mon Sep 17 00:00:00 2001 From: Andrew Mavdryk Date: Thu, 1 Aug 2024 21:03:50 +0300 Subject: [PATCH] Fix [Functions] Apply name filter on loading the function (#2637) --- src/common/NameFilter/NameFilter.js | 8 ++-- src/components/FunctionsPage/Functions.js | 37 ++++++++++++++++++- .../DetailsInfoItem/DetailsInfoItem.js | 9 +++-- src/utils/createFunctionsContent.js | 2 +- src/utils/createJobsContent.js | 35 +++++++++--------- src/utils/createRealTimePipelinesContent.js | 9 ++++- src/utils/generateFunctionDetailsLink.js | 24 ++++++++++-- src/utils/parseUri.js | 4 +- 8 files changed, 92 insertions(+), 36 deletions(-) diff --git a/src/common/NameFilter/NameFilter.js b/src/common/NameFilter/NameFilter.js index cb2f32678..cd7b6a975 100644 --- a/src/common/NameFilter/NameFilter.js +++ b/src/common/NameFilter/NameFilter.js @@ -36,9 +36,9 @@ const NameFilter = ({ applyChanges, filterMenuName= '' }) => { if (event.keyCode === KEY_CODES.ENTER) { applyChanges(event.target.value) if (filterMenuName) { - dispatch(setFiltersValues({ name: filterMenuName, value: { name: event.target.value } })) + dispatch(setFiltersValues({ name: filterMenuName, value: { [NAME_FILTER]: event.target.value } })) } else { - dispatch(setFilters({ name: event.target.value })) + dispatch(setFilters({ [NAME_FILTER]: event.target.value })) } } } @@ -46,9 +46,9 @@ const NameFilter = ({ applyChanges, filterMenuName= '' }) => { if (input.value.length > 0) { applyChanges(input.value) if (filterMenuName) { - dispatch(setFiltersValues({ name: filterMenuName, value: { name: input.value } })) + dispatch(setFiltersValues({ name: filterMenuName, value: { [NAME_FILTER]: input.value } })) } else { - dispatch(setFilters({ name: input.value })) + dispatch(setFilters({ [NAME_FILTER]: input.value })) } } } diff --git a/src/components/FunctionsPage/Functions.js b/src/components/FunctionsPage/Functions.js index ec0037cb7..11e0acc61 100644 --- a/src/components/FunctionsPage/Functions.js +++ b/src/components/FunctionsPage/Functions.js @@ -35,7 +35,8 @@ import { JOB_DEFAULT_OUTPUT_PATH, DATES_FILTER, NAME_FILTER, - SHOW_UNTAGGED_FILTER + SHOW_UNTAGGED_FILTER, + FUNCTION_FILTERS } from '../../constants' import { fetchInitialFunctions, @@ -44,6 +45,11 @@ import { pollDeletingFunctions, setFullSelectedFunction } from './functions.util' +import { + ANY_TIME_DATE_OPTION, + datePickerPastOptions, + getDatePickerFilterValue +} from '../../utils/datePicker.util' import createFunctionsContent from '../../utils/createFunctionsContent' import functionsActions from '../../actions/functions' import jobsActions from '../../actions/jobs' @@ -54,7 +60,7 @@ import { isBackgroundTaskRunning } from '../../utils/poll.util' import { isDetailsTabExists } from '../../utils/isDetailsTabExists' import { openPopUp } from 'igz-controls/utils/common.util' import { parseFunctions } from '../../utils/parseFunctions' -import { setFilters } from '../../reducers/filtersReducer' +import { setFilters, setFiltersValues, setModalFiltersValues } from '../../reducers/filtersReducer' import { setNotification } from '../../reducers/notificationReducer' import { showErrorNotification } from '../../utils/notifications.util' import { useGroupContent } from '../../hooks/groupContent.hook' @@ -497,6 +503,33 @@ const Functions = ({ ) }, [dispatch, fetchFunction, navigate, params.projectName, selectedFunctionMin]) + useLayoutEffect(() => { + if ( + !functionsAreInitializedRef.current && + (params.funcName || (params.hash && params.hash.includes('@'))) + ) { + const funcName = params.funcName || params.hash.split('@')[0] + + dispatch( + setFiltersValues({ + name: FUNCTION_FILTERS, + value: { + [NAME_FILTER]: funcName, + [DATES_FILTER]: getDatePickerFilterValue(datePickerPastOptions, ANY_TIME_DATE_OPTION) + } + }) + ) + dispatch( + setModalFiltersValues({ + name: FUNCTION_FILTERS, + value: { + [SHOW_UNTAGGED_FILTER]: true + } + }) + ) + } + }, [dispatch, params]) + useEffect(() => { fetchInitialFunctions(filtersStore, fetchData, functionsAreInitializedRef) }, [filtersStore, fetchData]) diff --git a/src/elements/DetailsInfoItem/DetailsInfoItem.js b/src/elements/DetailsInfoItem/DetailsInfoItem.js index 2d48ae611..8a04c6ea1 100644 --- a/src/elements/DetailsInfoItem/DetailsInfoItem.js +++ b/src/elements/DetailsInfoItem/DetailsInfoItem.js @@ -26,12 +26,13 @@ import { useSelector } from 'react-redux' import ChipCell from '../../common/ChipCell/ChipCell' import CopyToClipboard from '../../common/CopyToClipboard/CopyToClipboard' +import DetailsInfoItemChip from '../DetailsInfoItemChip/DetailsInfoItemChip' import Input from '../../common/Input/Input' -import { Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' import { FormInput, FormOnChange, FormTextarea } from 'igz-controls/components' -import DetailsInfoItemChip from '../DetailsInfoItemChip/DetailsInfoItemChip' +import { Tooltip, TextTooltipTemplate, RoundedIcon } from 'igz-controls/components' import { CHIP_OPTIONS } from '../../types' +import { generateFunctionDetailsLink } from '../../utils/generateFunctionDetailsLink' import { getValidationRules } from 'igz-controls/utils/validation.util' import { ReactComponent as Checkmark } from 'igz-controls/images/checkmark2.svg' @@ -206,7 +207,7 @@ const DetailsInfoItem = React.forwardRef( ) } else if (!isEmpty(func)) { - const [functionProject, functionNameWithHash] = func.split('/') + const funcLink = generateFunctionDetailsLink(func) return ( {func} diff --git a/src/utils/createFunctionsContent.js b/src/utils/createFunctionsContent.js index 0ef11b404..577183f6a 100644 --- a/src/utils/createFunctionsContent.js +++ b/src/utils/createFunctionsContent.js @@ -34,7 +34,7 @@ const createFunctionsContent = (functions, projectName, showExpandButton) => value: func.name, className: 'table-cell-name', getLink: (hash, tab) => { - return `/projects/${projectName}/functions/${hash}${`/${tab}`}` + return `/projects/${projectName}/functions/${func.name}@${hash}${`/${tab}`}` }, expandedCellContent: { value: formatDatetime(func.updated, 'N/A'), diff --git a/src/utils/createJobsContent.js b/src/utils/createJobsContent.js index 53adfffb8..9fcb64fe3 100644 --- a/src/utils/createJobsContent.js +++ b/src/utils/createJobsContent.js @@ -156,7 +156,8 @@ export const createJobsMonitorTabContent = (jobs, jobName, isStagingMode) => { export const createJobsScheduleTabContent = jobs => { return jobs.map(job => { const identifierUnique = getJobIdentifier(job, true) - const [, , scheduleJobFunctionUid] = job.func?.match(/\w[\w'-]*/g, '') || [] + const [, scheduledJobFunctionName, scheduledJobFunctionHash] = + job.func?.match(/\w[\w'-]*/g, '') || [] const [, projectName, jobUid] = job.lastRunUri?.match(/(.+)@(.+)#([^:]+)(?::(.+))?/) || [] const jobName = job.name const lastRunLink = () => @@ -183,12 +184,12 @@ export const createJobsScheduleTabContent = jobs => { className: 'table-cell-name', showStatus: true, getLink: tab => - validateArguments(scheduleJobFunctionUid, tab) + validateArguments(scheduledJobFunctionHash, tab) ? generateLinkToDetailsPanel( job.project, FUNCTIONS_PAGE, null, - scheduleJobFunctionUid, + `${scheduledJobFunctionName}@${scheduledJobFunctionHash}`, null, tab ) @@ -363,18 +364,15 @@ export const createJobsWorkflowContent = ( className: 'table-cell-name', type: 'link', getLink: tab => { - return workflowProjectName ? - getWorkflowMonitoringDetailsLink( - workflowProjectName, - workflowId, - job.customData - ) : getWorkflowDetailsLink( - projectName, - workflowId, - job.customData, - tab, - MONITOR_WORKFLOWS_TAB - ) + return workflowProjectName + ? getWorkflowMonitoringDetailsLink(workflowProjectName, workflowId, job.customData) + : getWorkflowDetailsLink( + projectName, + workflowId, + job.customData, + tab, + MONITOR_WORKFLOWS_TAB + ) }, showStatus: true, showUidRow: true @@ -545,7 +543,8 @@ export const createJobsMonitoringContent = (jobs, jobName, isStagingMode) => { export const createScheduleJobsMonitoringContent = jobs => { return jobs.map(job => { const identifierUnique = getJobIdentifier(job, true) - const [, , scheduleJobFunctionUid] = job.func?.match(/\w[\w'-]*/g, '') || [] + const [, scheduledJobFunctionName, scheduledJobFunctionHash] = + job.func?.match(/\w[\w'-]*/g, '') || [] const [, projectName, jobUid] = job.lastRunUri?.match(/(.+)@(.+)#([^:]+)(?::(.+))?/) || [] const jobName = job.name const lastRunLink = () => @@ -572,12 +571,12 @@ export const createScheduleJobsMonitoringContent = jobs => { className: 'table-cell-name', showStatus: true, getLink: tab => - validateArguments(scheduleJobFunctionUid, tab) + validateArguments(scheduledJobFunctionHash, tab) ? generateLinkToDetailsPanel( job.project, FUNCTIONS_PAGE, null, - scheduleJobFunctionUid, + `${scheduledJobFunctionName}@${scheduledJobFunctionHash}`, null, tab ) diff --git a/src/utils/createRealTimePipelinesContent.js b/src/utils/createRealTimePipelinesContent.js index 21adc7676..f42005342 100644 --- a/src/utils/createRealTimePipelinesContent.js +++ b/src/utils/createRealTimePipelinesContent.js @@ -64,7 +64,14 @@ const createRealTimePipelinesContent = (pipelines, projectName) => className: 'table-cell-2', getLink: tab => validateArguments(pipeline.hash, tab) - ? generateLinkToDetailsPanel(pipeline.project, FUNCTIONS_PAGE, null, pipeline.hash, null, tab) + ? generateLinkToDetailsPanel( + pipeline.project, + FUNCTIONS_PAGE, + null, + `${pipeline.name}@${pipeline.hash}`, + null, + tab + ) : '' }, { diff --git a/src/utils/generateFunctionDetailsLink.js b/src/utils/generateFunctionDetailsLink.js index 4e7c13395..826fe3f2c 100644 --- a/src/utils/generateFunctionDetailsLink.js +++ b/src/utils/generateFunctionDetailsLink.js @@ -17,7 +17,23 @@ 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 { generateLinkPath } from './parseUri' + +export const parseFunctionUri = functionUri => { + let [project, rest] = functionUri.split('/') + let name = rest + let hash = null + let tag = null + let nameWithHash = null + + if (rest.includes('@')) { + ;[name, hash] = rest.split('@') + nameWithHash = `${name}@${hash}` + } else if (rest.includes(':')) { + ;[name, tag] = rest.split(':') + } + + return { project, name, hash, tag, nameWithHash } +} export const generateFunctionDetailsLink = (uri = '') => { // remove 'latest' when function_uri will contain hash or tag @@ -25,9 +41,9 @@ export const generateFunctionDetailsLink = (uri = '') => { // 'my_proj/func_name@func_hash' -> projects/my_proj/functions/func_hash/overview // 'my_proj/func_name' -> projects/my_proj/functions/func_name/latest/overview // 'my_proj/func_name:custom_tag' -> projects/my_proj/functions/func_name/custom_tag/overview + const { project, name, nameWithHash, tag } = parseFunctionUri(uri) + return uri - ? `${generateLinkPath(`store://functions/${uri}`, uri.includes('@'))}${ - uri.includes(':') || uri.includes('@') ? '' : '/latest' - }/overview` + ? `/projects/${project}/functions/${nameWithHash ? nameWithHash : name}${nameWithHash ? '' : '/' + (tag ?? 'latest')}/overview` : '' } diff --git a/src/utils/parseUri.js b/src/utils/parseUri.js index c52016812..4b6f276b4 100644 --- a/src/utils/parseUri.js +++ b/src/utils/parseUri.js @@ -92,11 +92,11 @@ const kindToScreen = { models: `models/${MODELS_TAB}` } -const generateLinkPath = (uri = '', ignoreKey = false) => { +const generateLinkPath = (uri = '') => { const { kind, project, key, tag, uid } = parseUri(uri) const screen = kindToScreen[kind] ?? FILES_TAB const reference = tag ?? uid - return `/projects/${project}/${screen}${ignoreKey ? '' : `/${key}`}${reference ? `/${reference}` : ''}` + return `/projects/${project}/${screen}${key}${reference ? `/${reference}` : ''}` } const generateNuclioLink = pathname => {