From 5579a53e7812d68b962459b9878733b01cb09fc5 Mon Sep 17 00:00:00 2001 From: Samir Jha Date: Mon, 14 Aug 2023 16:21:43 +0000 Subject: [PATCH] Fixes #36679 - Sort CV versions when adding component views --- app/models/katello/content_view.rb | 4 + app/models/katello/content_view_component.rb | 2 +- .../api/v2/content_views/base.json.rabl | 2 +- .../ComponentContentViewAddModal.js | 37 ++- .../ComponentContentViewBulkAddModal.js | 49 ++-- .../ContentViewComponents.js | 7 + .../contentViewComponents.fixtures.json | 16 +- .../__tests__/contentViewComponents.test.js | 2 +- .../publishedContentViewDetails.fixtures.json | 240 ++++-------------- 9 files changed, 103 insertions(+), 256 deletions(-) diff --git a/app/models/katello/content_view.rb b/app/models/katello/content_view.rb index ef33a7860b0..316d2d452fa 100644 --- a/app/models/katello/content_view.rb +++ b/app/models/katello/content_view.rb @@ -178,6 +178,10 @@ def components content_view_components.map(&:latest_version).compact.freeze end + def sorted_versions + versions.order('created_at DESC') + end + # Adds content view components based on the input # [{:content_view_version_id=>1, :latest=> false}, {:content_view_id=>1, :latest=> true} ..] def add_components(components_to_add) diff --git a/app/models/katello/content_view_component.rb b/app/models/katello/content_view_component.rb index 8dcdb99aee1..61379aed36c 100644 --- a/app/models/katello/content_view_component.rb +++ b/app/models/katello/content_view_component.rb @@ -32,7 +32,7 @@ def latest_version end def component_content_view_versions - self.content_view&.versions + self.content_view&.versions&.order(created_at: :desc) end private diff --git a/app/views/katello/api/v2/content_views/base.json.rabl b/app/views/katello/api/v2/content_views/base.json.rabl index dd55f24fad9..696ba7ad75a 100644 --- a/app/views/katello/api/v2/content_views/base.json.rabl +++ b/app/views/katello/api/v2/content_views/base.json.rabl @@ -64,7 +64,7 @@ else attributes :repository_ids end -child :versions => :versions do +child :sorted_versions => :versions do attributes :id, :version attributes :created_at => :published attributes :description diff --git a/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js b/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js index 78b63a1c4c2..0774e9f896e 100644 --- a/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js +++ b/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useMemo } from 'react'; import PropTypes from 'prop-types'; import { Flex, Modal, ModalVariant, Select, SelectVariant, @@ -12,13 +12,12 @@ import { STATUS } from 'foremanReact/constants'; import { selectCVDetails, selectCVDetailStatus, - selectCVDetailError, } from '../../Details/ContentViewDetailSelectors'; import { addComponent } from '../ContentViewDetailActions'; import { CONTENT_VIEW_NEEDS_PUBLISH } from '../../ContentViewsConstants'; const ComponentContentViewAddModal = ({ - cvId, componentCvId, componentId, latest, show, setIsOpen, + cvId, componentCvId, componentId, latest, componentVersionId, show, setIsOpen, }) => { const dispatch = useDispatch(); const componentDetails = useSelector( @@ -29,29 +28,20 @@ const ComponentContentViewAddModal = ({ state => selectCVDetailStatus(state, componentCvId), shallowEqual, ); - const componentError = useSelector( - state => selectCVDetailError(state, componentCvId), - shallowEqual, - ); - const [cvName, setCvName] = useState(''); - const [options, setOptions] = useState([]); + const cvName = componentDetails?.name ?? ''; + const options = useMemo(() => (componentDetails?.versions ?? []).map(item => ({ + value: item.id, label: __(`Version ${item.version}`), description: item.description, publishedAtWords: __(` (${item.published_at_words} ago)`), + })), [componentDetails?.versions]); const [formLatest, setFormLatest] = useState(componentId ? latest : false); const [selected, setSelected] = useState(null); + const [prevOptions, setPrevOptions] = useState(options); const [cvVersionSelectOpen, setCvVersionSelectOpen] = useState(false); const versionsLoading = componentStatus === STATUS.PENDING; - useEffect(() => { - if (!versionsLoading && componentDetails) { - const { name, versions } = componentDetails; - const versionMutable = versions; - setCvName(name); - const opt = versionMutable.map(item => ({ - value: item.id, label: __(`Version ${item.version}`), description: item.description, publishedAtWords: __(` (${item.published_at_words} ago)`), - })); - setOptions([...opt].reverse()); - setSelected(opt.slice(-1)[0].value); - } - }, [componentDetails, componentStatus, componentError, versionsLoading]); + if (options !== prevOptions) { + setPrevOptions(options); + setSelected(componentVersionId ?? options[0]?.value); + } const getAddParams = () => { if (formLatest) { @@ -175,6 +165,10 @@ ComponentContentViewAddModal.propTypes = { PropTypes.string, ]), latest: PropTypes.bool, + componentVersionId: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.string, + ]), show: PropTypes.bool, setIsOpen: PropTypes.func, }; @@ -182,6 +176,7 @@ ComponentContentViewAddModal.propTypes = { ComponentContentViewAddModal.defaultProps = { componentId: null, latest: false, + componentVersionId: null, show: false, setIsOpen: null, }; diff --git a/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js b/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js index 9ae9f9997de..d78b42531d5 100644 --- a/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js +++ b/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js @@ -1,5 +1,4 @@ -import React, { useState, useMemo } from 'react'; -import { last } from 'lodash'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; import { Flex, Modal, ModalVariant, Select, SelectVariant, @@ -13,28 +12,19 @@ import { addComponent } from '../ContentViewDetailActions'; const ComponentContentViewBulkAddModal = ({ cvId, rowsToAdd, onClose }) => { const dispatch = useDispatch(); - const [versionSelectOptions, setVersionSelectOptions] = useState({}); - const [selectedVersion, setSelectedVersion] = useState({}); - const [selectedComponentLatest, setSelectedComponentLatest] = useState({}); + const versionSelect = {}; + const versionSelectedOption = {}; + const componentLatest = {}; + rowsToAdd.forEach((row) => { + const { componentCvVersions: versions, componentCvName: name } = row; + versionSelect[name] = versions; + versionSelectedOption[name] = versions[0]?.id; + componentLatest[name] = versions && versions?.length === 0; + }); + const [selectedVersion, setSelectedVersion] = useState(versionSelectedOption); + const [selectedComponentLatest, setSelectedComponentLatest] = useState(componentLatest); const [cvVersionSelectOpen, setCvVersionSelectOpen] = useState(''); - - useMemo(() => { - const versionSelect = {}; - const versionSelectedOption = {}; - const componentLatest = {}; - rowsToAdd.forEach((row) => { - const { componentCvVersions: versions, componentCvName: name } = row; - const sortedVersions = [].concat(versions).sort((a, b) => (a.id > b.id ? 1 : -1)); - versionSelect[name] = sortedVersions; - versionSelectedOption[name] = last(sortedVersions)?.id; - componentLatest[name] = sortedVersions && sortedVersions?.length === 0; - }); - setVersionSelectOptions(versionSelect); - setSelectedVersion(versionSelectedOption); - setSelectedComponentLatest(componentLatest); - }, [rowsToAdd, setVersionSelectOptions, setSelectedVersion, setSelectedComponentLatest]); - const bulkAddParams = () => rowsToAdd.map((row) => { const { componentCvId: id, componentCvName: name } = row; if (selectedComponentLatest[name]) { @@ -66,7 +56,7 @@ const ComponentContentViewBulkAddModal = ({ cvId, rowsToAdd, onClose }) => { onSubmit(); }} > - {Object.keys(versionSelectOptions).sort().map(componentCvName => ( + {Object.keys(versionSelect).sort().map(componentCvName => ( { variant={SelectVariant.typeahead} selections={selectedVersion[componentCvName]} ouiaId="select-version" - isDisabled={versionSelectOptions[componentCvName].length <= 1 || + isDisabled={versionSelect[componentCvName].length <= 1 || selectedComponentLatest[componentCvName]} onSelect={(__event, value) => { setSelectedVersion({ ...selectedVersion, ...{ [componentCvName]: value } }); @@ -94,7 +84,7 @@ const ComponentContentViewBulkAddModal = ({ cvId, rowsToAdd, onClose }) => { menuAppendTo="parent" maxHeight="20rem" > - {versionSelectOptions[componentCvName].map(version => ( + {versionSelect[componentCvName].map(version => ( { name="latest" label={__('Always update to latest version')} isChecked={selectedComponentLatest[componentCvName]} - onChange={checked => + onChange={(checked) => { setSelectedComponentLatest({ ...selectedComponentLatest, ...{ [componentCvName]: checked }, - }) + }); + setSelectedVersion({ + ...selectedVersion, + ...{ [componentCvName]: versionSelect[componentCvName][0]?.id }, + }); + } } /> { const [componentCvEditing, setComponentCvEditing] = useState(null); const [componentLatest, setComponentLatest] = useState(false); const [componentId, setComponentId] = useState(null); + const [componentVersionId, setComponentVersionId] = useState(null); const [selectedComponentsToAdd, setSelectedComponentsToAdd] = useState(null); const [bulkAdding, setBulkAdding] = useState(false); const [bulkActionOpen, setBulkActionOpen] = useState(false); @@ -86,6 +87,11 @@ const ContentViewComponents = ({ cvId, details }) => { setVersionEditing(true); setCompositeCvEditing(cvId); setComponentCvEditing(componentCvId); + if (added) { + setComponentVersionId(published?.id); + } else { + setComponentVersionId(null); + } setComponentLatest(latest); setComponentId(added); } else { // if no versions are present, default to always latest and add cv without modal @@ -297,6 +303,7 @@ const ContentViewComponents = ({ cvId, details }) => { componentCvId={componentCvEditing} componentId={componentId} latest={componentLatest} + componentVersionId={componentVersionId} show={versionEditing} setIsOpen={setVersionEditing} aria-label="edit_component_modal" diff --git a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.fixtures.json b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.fixtures.json index 64756668606..d545ab17bcf 100644 --- a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.fixtures.json +++ b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.fixtures.json @@ -128,10 +128,10 @@ }, "component_content_view_versions": [ { - "id": 36, - "version": "1.0", - "description": "Version 1.0", - "published_at_words": "5 days" + "id": 44, + "version": "4.0", + "description": "Version 4.0", + "published_at_words": "3 days" }, { "id": 42, @@ -140,10 +140,10 @@ "published_at_words": "4 days" }, { - "id": 44, - "version": "4.0", - "description": "Version 4.0", - "published_at_words": "3 days" + "id": 36, + "version": "1.0", + "description": "Version 1.0", + "published_at_words": "5 days" } ] }, diff --git a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js index f1748743e4a..9814a004cab 100644 --- a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js +++ b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js @@ -201,7 +201,7 @@ test('Can add published component views to content view with modal', async (done const addComponentParams = { compositeContentViewId: 4, - components: [{ content_view_version_id: 85 }], + components: [{ content_view_version_id: 13 }], }; const addComponentScope = nockInstance diff --git a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/publishedContentViewDetails.fixtures.json b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/publishedContentViewDetails.fixtures.json index fb4af0059f7..9dc0975d74b 100644 --- a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/publishedContentViewDetails.fixtures.json +++ b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/publishedContentViewDetails.fixtures.json @@ -139,214 +139,60 @@ "repositories": [], "versions": [ { - "id": 52, - "version": "1.0", - "published": "2021-06-22 06:07:43 -1000", - "environment_ids": [] - }, - { - "id": 53, - "version": "2.0", - "published": "2021-06-22 06:09:02 -1000", - "environment_ids": [] - }, - { - "id": 54, - "version": "3.0", - "published": "2021-06-22 06:09:33 -1000", - "environment_ids": [] - }, - { - "id": 55, - "version": "4.0", - "published": "2021-06-22 06:29:29 -1000", - "environment_ids": [] - }, - { - "id": 56, - "version": "5.0", - "published": "2021-06-22 06:29:56 -1000", - "environment_ids": [] - }, - { - "id": 57, + "id": 13, "version": "6.0", - "published": "2021-06-22 06:30:29 -1000", - "environment_ids": [] - }, - { - "id": 58, - "version": "7.0", - "published": "2021-06-22 06:32:10 -1000", - "environment_ids": [] - }, - { - "id": 59, - "version": "8.0", - "published": "2021-06-22 06:38:01 -1000", - "environment_ids": [] - }, - { - "id": 60, - "version": "9.0", - "published": "2021-06-22 06:41:03 -1000", - "environment_ids": [] - }, - { - "id": 61, - "version": "10.0", - "published": "2021-06-22 06:53:06 -1000", - "environment_ids": [] - }, - { - "id": 62, - "version": "11.0", - "published": "2021-06-22 06:55:03 -1000", - "environment_ids": [] - }, - { - "id": 63, - "version": "12.0", - "published": "2021-06-22 06:57:47 -1000", - "environment_ids": [] - }, - { - "id": 64, - "version": "13.0", - "published": "2021-06-22 06:58:13 -1000", - "environment_ids": [] - }, - { - "id": 65, - "version": "14.0", - "published": "2021-06-22 06:58:44 -1000", - "environment_ids": [] - }, - { - "id": 66, - "version": "15.0", - "published": "2021-06-22 07:00:51 -1000", - "environment_ids": [] - }, - { - "id": 67, - "version": "16.0", - "published": "2021-06-22 07:02:35 -1000", - "environment_ids": [] - }, - { - "id": 68, - "version": "17.0", - "published": "2021-06-22 07:03:15 -1000", - "environment_ids": [] - }, - { - "id": 69, - "version": "18.0", - "published": "2021-06-22 07:12:38 -1000", - "environment_ids": [] - }, - { - "id": 70, - "version": "19.0", - "published": "2021-06-22 07:38:55 -1000", - "environment_ids": [] - }, - { - "id": 71, - "version": "20.0", - "published": "2021-06-22 07:39:27 -1000", - "environment_ids": [] - }, - { - "id": 72, - "version": "21.0", - "published": "2021-06-22 08:09:53 -1000", - "environment_ids": [] - }, - { - "id": 73, - "version": "22.0", - "published": "2021-06-22 08:10:23 -1000", - "environment_ids": [] - }, - { - "id": 74, - "version": "23.0", - "published": "2021-06-22 09:24:48 -1000", - "environment_ids": [] - }, - { - "id": 75, - "version": "24.0", - "published": "2021-06-22 09:28:09 -1000", - "environment_ids": [] - }, - { - "id": 76, - "version": "25.0", - "published": "2021-06-22 09:31:50 -1000", - "environment_ids": [] - }, - { - "id": 77, - "version": "26.0", - "published": "2021-06-22 09:33:03 -1000", - "environment_ids": [] - }, - { - "id": 78, - "version": "27.0", - "published": "2021-06-22 09:34:31 -1000", - "environment_ids": [] - }, - { - "id": 79, - "version": "28.0", - "published": "2021-06-22 09:35:00 -1000", - "environment_ids": [] + "published": "2023-08-11 10:32:48 -0400", + "description": "aaa", + "environment_ids": [ + 1 + ], + "filters_applied": false, + "published_at_words": "3 days" }, { - "id": 80, - "version": "29.0", - "published": "2021-06-22 09:35:18 -1000", - "environment_ids": [] + "id": 12, + "version": "5.0", + "published": "2023-08-11 10:32:22 -0400", + "description": "aa", + "environment_ids": [], + "filters_applied": false, + "published_at_words": "3 days" }, { - "id": 81, - "version": "30.0", - "published": "2021-06-22 10:55:48 -1000", - "environment_ids": [] + "id": 11, + "version": "4.0", + "published": "2023-08-11 10:31:12 -0400", + "description": "aa", + "environment_ids": [], + "filters_applied": false, + "published_at_words": "3 days" }, { - "id": 83, - "version": "31.0", - "published": "2021-06-22 10:58:09 -1000", - "environment_ids": [] + "id": 9, + "version": "3.0", + "published": "2023-08-10 13:47:47 -0400", + "description": "ab", + "environment_ids": [], + "filters_applied": false, + "published_at_words": "4 days" }, { - "id": 84, - "version": "32.0", - "published": "2021-06-22 10:58:37 -1000", - "environment_ids": [ - 8, - 10, - 11, - 12, - 13 - ] + "id": 8, + "version": "2.0", + "published": "2023-08-10 13:47:09 -0400", + "description": "", + "environment_ids": [], + "filters_applied": false, + "published_at_words": "4 days" }, { - "id": 85, - "version": "33.0", - "published": "2021-06-22 11:03:15 -1000", - "environment_ids": [ - 1, - 5, - 6, - 7, - 9 - ] + "id": 7, + "version": "1.0", + "published": "2023-08-10 13:46:58 -0400", + "description": "", + "environment_ids": [], + "filters_applied": false, + "published_at_words": "4 days" } ], "components": [],