From 8680aaecf122266dd10acf0215371539487583ce Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Fri, 26 Sep 2025 10:40:03 -0400 Subject: [PATCH 01/12] Added missing padding around the Managed dashboard card --- .../Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx b/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx index aac50be3668..37a315b01a3 100644 --- a/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx +++ b/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx @@ -18,6 +18,7 @@ export const StyledOuterContainerGrid = styled(Grid, { background: theme.bg.bgPaper, flexDirection: 'column', margin: '-8px', + padding: theme.spacing(2), [theme.breakpoints.up('sm')]: { flexDirection: 'row', flexWrap: 'nowrap', From d53e3f63d283531199921ea176b39e57633f6131 Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Fri, 26 Sep 2025 13:46:44 -0400 Subject: [PATCH 02/12] changed spacing to spacingFunction --- .../ManagedDashboardCard/ManagedDashboardCard.styles.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx b/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx index 37a315b01a3..9d03064cd63 100644 --- a/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx +++ b/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedDashboardCard.styles.tsx @@ -18,7 +18,7 @@ export const StyledOuterContainerGrid = styled(Grid, { background: theme.bg.bgPaper, flexDirection: 'column', margin: '-8px', - padding: theme.spacing(2), + padding: theme.spacingFunction(12), [theme.breakpoints.up('sm')]: { flexDirection: 'row', flexWrap: 'nowrap', From 9a5347d2ba92b48b6a90bb026ac884a9372177da Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Wed, 8 Apr 2026 11:43:57 -0400 Subject: [PATCH 03/12] Implement the images multi-select table --- .../ImageSelect/ImageSelectTable.tsx | 80 +++++++++++++------ .../ImageSelect/ImageSelectTableRow.tsx | 73 +++++++++++------ .../src/components/ImageSelect/constants.ts | 15 ++++ .../v2/ImageLibrary/ImagesTable.styles.ts | 4 - .../ShareGroupsCreate/ShareGroupsCreate.tsx | 47 +++++++++-- .../ShareGroupsCreateContainer.tsx | 2 + .../Images/ImagesLanding/v2/constants.ts | 7 ++ .../Linodes/LinodeCreate/Tabs/Images.tsx | 3 +- .../LinodesDetail/LinodeRebuild/Image.tsx | 3 +- 9 files changed, 175 insertions(+), 59 deletions(-) diff --git a/packages/manager/src/components/ImageSelect/ImageSelectTable.tsx b/packages/manager/src/components/ImageSelect/ImageSelectTable.tsx index 46c5456320c..d39c89c7d90 100644 --- a/packages/manager/src/components/ImageSelect/ImageSelectTable.tsx +++ b/packages/manager/src/components/ImageSelect/ImageSelectTable.tsx @@ -45,6 +45,9 @@ import type { } from './constants'; import type { Filter, Image } from '@linode/api-v4'; import type { LinkProps } from '@tanstack/react-router'; +import type { IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS } from 'src/components/ImageSelect/constants'; + +type SelectionMode = 'multi' | 'single'; interface Props { /** @@ -56,6 +59,8 @@ interface Props { * Error message to display above the table, e.g. from form validation. */ errorText?: string; + + onCheckboxSelect?: (image: Image) => void; /** * Callback fired when the user selects an image row. */ @@ -65,12 +70,19 @@ interface Props { */ pendoIDs: | typeof IMAGE_SELECT_TABLE_LINODE_CREATE_PENDO_IDS - | typeof IMAGE_SELECT_TABLE_LINODE_REBUILD_PENDO_IDS; + | typeof IMAGE_SELECT_TABLE_LINODE_REBUILD_PENDO_IDS + | typeof IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS; queryParamsPrefix?: string; /** - * The ID of the currently selected image. + * The IDs of the currently selected images, when using multi-select mode with checkboxes. + */ + selectedImageIds: string[]; + + /** + * Whether this table should use single-select mode with radio buttons, or multi-select mode with checkboxes. + * The default is single select. */ - selectedImageId?: null | string; + selectionMode: SelectionMode; } type OptionType = { label: string; value: string }; @@ -82,7 +94,8 @@ export const ImageSelectTable = (props: Props) => { onSelect, pendoIDs, queryParamsPrefix, - selectedImageId, + selectionMode = 'single', + selectedImageIds, } = props; const theme = useTheme(); @@ -256,29 +269,31 @@ export const ImageSelectTable = (props: Props) => { Replicated in - - - - Share Group - - - - + {selectionMode === 'single' && ( + + + + Share Group + + + + + )} - Size + {selectionMode === 'single' ? 'Size' : 'Original Image'} { )} {!isLoading && !imagesError && + selectionMode === 'single' && pagination.paginatedData.map((image) => ( { onSelect={() => onSelect(image)} pendoIDs={pendoIDs} regions={regions ?? []} - selected={image.id === selectedImageId} + selected={selectedImageIds?.includes(image.id)} + selectedImages={selectedImageIds} + selectionMode={selectionMode} + timezone={profile?.timezone} + /> + ))} + {!isLoading && + !imagesError && + pagination.paginatedData.map((image) => ( + onSelect(image)} + pendoIDs={pendoIDs} + regions={regions ?? []} + selectedImages={selectedImageIds ?? []} + selectionMode={selectionMode} timezone={profile?.timezone} /> ))} diff --git a/packages/manager/src/components/ImageSelect/ImageSelectTableRow.tsx b/packages/manager/src/components/ImageSelect/ImageSelectTableRow.tsx index 98dd251e9a4..114585013fc 100644 --- a/packages/manager/src/components/ImageSelect/ImageSelectTableRow.tsx +++ b/packages/manager/src/components/ImageSelect/ImageSelectTableRow.tsx @@ -26,20 +26,35 @@ import type { } from './constants'; import type { Image, ImageRegion, Region } from '@linode/api-v4'; import type { Theme } from '@linode/ui'; +import type { IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS } from 'src/components/ImageSelect/constants'; interface Props { image: Image; - onSelect: () => void; + onCheckboxSelect?: () => void; + onSelect?: () => void; pendoIDs: | typeof IMAGE_SELECT_TABLE_LINODE_CREATE_PENDO_IDS - | typeof IMAGE_SELECT_TABLE_LINODE_REBUILD_PENDO_IDS; + | typeof IMAGE_SELECT_TABLE_LINODE_REBUILD_PENDO_IDS + | typeof IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS; regions: Region[]; - selected: boolean; + selected?: boolean; + selectedImages: string[]; + selectionMode: 'multi' | 'single'; timezone?: string; } export const ImageSelectTableRow = (props: Props) => { - const { image, onSelect, pendoIDs, regions, selected, timezone } = props; + const { + image, + onSelect, + onCheckboxSelect, + pendoIDs, + regions, + selected, + selectedImages, + timezone, + selectionMode, + } = props; const { capabilities, @@ -90,15 +105,25 @@ export const ImageSelectTableRow = (props: Props) => { ); return ( - + - } - label={label} - onChange={onSelect} - sx={{ gap: 2 }} - /> + {selectionMode === 'single' ? ( + } + label={label} + onChange={onSelect} + sx={{ gap: 2 }} + /> + ) : ( + label + )} {type === 'manual' && capabilities.includes('cloud-init') && ( { /> - - - {getShareGroupDisplay()} - - + {selectionMode === 'single' && ( + + + {getShareGroupDisplay()} + + + )} {getSizeDisplay()} diff --git a/packages/manager/src/components/ImageSelect/constants.ts b/packages/manager/src/components/ImageSelect/constants.ts index 705234914b8..8f0480791f6 100644 --- a/packages/manager/src/components/ImageSelect/constants.ts +++ b/packages/manager/src/components/ImageSelect/constants.ts @@ -22,3 +22,18 @@ export const IMAGE_SELECT_TABLE_LINODE_REBUILD_PENDO_IDS = { replicatedRegionPopover: 'Linodes Rebuild Images-Replicated in', shareGroupInfoIcon: 'Linodes Rebuild Images-Share Group info icon', }; + +export const IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS = { + searchImagesBar: 'Share Groups Create Images-Search click', + tagFilterSelect: 'Share Groups Create Images-Filter by Tag click', + regionFilterSelect: 'Share Groups Create Images-Filter by Region click', + metadataSupportedIcon: 'Share Groups Create Images-Metadata Supported icon', + replicatedRegionPopover: 'Share Groups Create Images-Replicated in', + shareGroupInfoIcon: 'Share Groups Create Images-Share Group info icon', + createImageLink: 'Share Groups Create Images-Create Image Link', + uploadImageLink: 'Share Groups Create Images-Upload Image Link', + imageCheckbox: 'Share Groups Create Images-Image Checkbox', + pageSizeSelect: 'Share Groups Create Images-Page Size Select', + previousPageButton: 'Share Groups Create Images-Previous Page Button', + nextPageButton: 'Share Groups Create Images-Next Page Button', +}; diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/ImageLibrary/ImagesTable.styles.ts b/packages/manager/src/features/Images/ImagesLanding/v2/ImageLibrary/ImagesTable.styles.ts index 8f4eea5e6aa..c61583d2128 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/ImageLibrary/ImagesTable.styles.ts +++ b/packages/manager/src/features/Images/ImagesLanding/v2/ImageLibrary/ImagesTable.styles.ts @@ -37,8 +37,4 @@ export const StyledImageTableContainer = styled(Box, { '& cds-table-row:last-child:not([rowborder])': { borderBottom: `1px solid ${theme.tokens.component.Table.Row.Border}`, }, - - '& cds-table-header-cell, & cds-table-cell': { - boxSizing: 'border-box', - }, })); diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx index 1a0fef28bec..5df35021647 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx +++ b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx @@ -11,9 +11,14 @@ import { } from '@linode/ui'; import { useNavigate } from '@tanstack/react-router'; import * as React from 'react'; -import { Controller, useForm } from 'react-hook-form'; +import { Controller, useController, useForm } from 'react-hook-form'; -import type { CreateSharegroupPayload } from '@linode/api-v4'; +import { IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS } from 'src/components/ImageSelect/constants'; +import { ImageSelectTable } from 'src/components/ImageSelect/ImageSelectTable'; + +import { CREATE_SHARE_GROUP_PENDO_IDS } from '../../constants'; + +import type { CreateSharegroupPayload, Image } from '@linode/api-v4'; export const ShareGroupsCreate = () => { const navigate = useNavigate(); @@ -23,7 +28,10 @@ export const ShareGroupsCreate = () => { const { control, handleSubmit, setError } = useForm(); - const selectedImages = []; + const { field: imagesField, fieldState } = useController({ + control, + name: 'images', + }); const onSubmit = handleSubmit(async (values) => { try { @@ -43,6 +51,20 @@ export const ShareGroupsCreate = () => { } } }); + + const onChange = async (image: Image) => { + const selectedImages = imagesField.value ?? []; + + const { id, label, description } = image; + const imagePayload = { id, label, description: description ?? undefined }; + + if (!selectedImages.some((img) => img.id === id)) { + imagesField.onChange([...selectedImages, imagePayload]); + } else { + imagesField.onChange(selectedImages.filter((img) => img.id !== id)); + } + }; + return (
@@ -61,6 +83,7 @@ export const ShareGroupsCreate = () => { noMarginTop required {...field} + data-pendo-id={CREATE_SHARE_GROUP_PENDO_IDS.label} errorText={fieldState.error?.message} onChange={(e) => field.onChange( @@ -81,6 +104,7 @@ export const ShareGroupsCreate = () => { multiline noMarginTop {...field} + data-pendo-id={CREATE_SHARE_GROUP_PENDO_IDS.description} onChange={(e) => field.onChange( e.target.value === '' ? undefined : e.target.value @@ -95,18 +119,29 @@ export const ShareGroupsCreate = () => { Images - Images table is coming soon... + img.id) ?? []} + selectionMode="multi" + /> - Selected images ({selectedImages.length}) + Selected images ({imagesField.value?.length ?? 0}) Selected images is coming soon... - diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreateContainer.tsx b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreateContainer.tsx index 2c298112a3b..7bf395df54b 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreateContainer.tsx +++ b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreateContainer.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import { DocumentTitleSegment } from 'src/components/DocumentTitle/DocumentTitle'; import { LandingHeader } from 'src/components/LandingHeader/LandingHeader'; +import { CREATE_SHARE_GROUP_PENDO_IDS } from '../../constants'; import { ShareGroupsCreate } from './ShareGroupsCreate'; export const ShareGroupsCreateContainer = () => { @@ -11,6 +12,7 @@ export const ShareGroupsCreateContainer = () => { <> { errorText={fieldState.error?.message} onSelect={onChange} pendoIDs={IMAGE_SELECT_TABLE_LINODE_CREATE_PENDO_IDS} - selectedImageId={field.value} + selectedImageIds={field.value ? [field.value] : []} + selectionMode="single" /> ) : ( diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeRebuild/Image.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeRebuild/Image.tsx index 53b582e89c6..ed70fc7e2d9 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeRebuild/Image.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeRebuild/Image.tsx @@ -51,7 +51,8 @@ export const Image = (props: Props) => { onSelect={(image) => field.onChange(image?.id ?? null)} pendoIDs={IMAGE_SELECT_TABLE_LINODE_REBUILD_PENDO_IDS} queryParamsPrefix="images" - selectedImageId={field.value} + selectedImageIds={field.value ? [field.value] : []} + selectionMode="single" /> ) : ( Date: Wed, 8 Apr 2026 11:50:15 -0400 Subject: [PATCH 04/12] Remove unnecessary async statement --- .../v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx index 5df35021647..22fb77c9ebd 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx +++ b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx @@ -52,7 +52,7 @@ export const ShareGroupsCreate = () => { } }); - const onChange = async (image: Image) => { + const onChange = (image: Image) => { const selectedImages = imagesField.value ?? []; const { id, label, description } = image; From 135a683f83a2550b2b14fea328bc1260d8d5c184 Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Wed, 8 Apr 2026 14:05:21 -0400 Subject: [PATCH 05/12] Improve the image select component --- .../ImageSelect/ImageSelectTable.tsx | 22 ++----------------- .../ImageSelect/ImageSelectTableRow.tsx | 13 +++++------ 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/packages/manager/src/components/ImageSelect/ImageSelectTable.tsx b/packages/manager/src/components/ImageSelect/ImageSelectTable.tsx index d39c89c7d90..fd2684599ad 100644 --- a/packages/manager/src/components/ImageSelect/ImageSelectTable.tsx +++ b/packages/manager/src/components/ImageSelect/ImageSelectTable.tsx @@ -60,7 +60,6 @@ interface Props { */ errorText?: string; - onCheckboxSelect?: (image: Image) => void; /** * Callback fired when the user selects an image row. */ @@ -77,7 +76,6 @@ interface Props { * The IDs of the currently selected images, when using multi-select mode with checkboxes. */ selectedImageIds: string[]; - /** * Whether this table should use single-select mode with radio buttons, or multi-select mode with checkboxes. * The default is single select. @@ -94,7 +92,7 @@ export const ImageSelectTable = (props: Props) => { onSelect, pendoIDs, queryParamsPrefix, - selectionMode = 'single', + selectionMode, selectedImageIds, } = props; @@ -327,7 +325,6 @@ export const ImageSelectTable = (props: Props) => { )} {!isLoading && !imagesError && - selectionMode === 'single' && pagination.paginatedData.map((image) => ( { onSelect={() => onSelect(image)} pendoIDs={pendoIDs} regions={regions ?? []} - selected={selectedImageIds?.includes(image.id)} - selectedImages={selectedImageIds} - selectionMode={selectionMode} - timezone={profile?.timezone} - /> - ))} - {!isLoading && - !imagesError && - pagination.paginatedData.map((image) => ( - onSelect(image)} - pendoIDs={pendoIDs} - regions={regions ?? []} - selectedImages={selectedImageIds ?? []} + selectedImageIds={selectedImageIds} selectionMode={selectionMode} timezone={profile?.timezone} /> diff --git a/packages/manager/src/components/ImageSelect/ImageSelectTableRow.tsx b/packages/manager/src/components/ImageSelect/ImageSelectTableRow.tsx index 114585013fc..5752aef2766 100644 --- a/packages/manager/src/components/ImageSelect/ImageSelectTableRow.tsx +++ b/packages/manager/src/components/ImageSelect/ImageSelectTableRow.tsx @@ -30,15 +30,13 @@ import type { IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS } from 'src/compon interface Props { image: Image; - onCheckboxSelect?: () => void; onSelect?: () => void; pendoIDs: | typeof IMAGE_SELECT_TABLE_LINODE_CREATE_PENDO_IDS | typeof IMAGE_SELECT_TABLE_LINODE_REBUILD_PENDO_IDS | typeof IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS; regions: Region[]; - selected?: boolean; - selectedImages: string[]; + selectedImageIds: string[]; selectionMode: 'multi' | 'single'; timezone?: string; } @@ -47,11 +45,9 @@ export const ImageSelectTableRow = (props: Props) => { const { image, onSelect, - onCheckboxSelect, pendoIDs, regions, - selected, - selectedImages, + selectedImageIds, timezone, selectionMode, } = props; @@ -104,13 +100,14 @@ export const ImageSelectTableRow = (props: Props) => { ); + const selected = selectedImageIds.includes(id); return ( {selectionMode === 'single' ? ( From 7fe6322fbc15088ebf018ad8c5e43db55ffdb65f Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Wed, 8 Apr 2026 14:11:07 -0400 Subject: [PATCH 06/12] Rename variable for clarity --- .../ShareGroupsCreate/ShareGroupsCreate.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx index 22fb77c9ebd..66f24756e02 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx +++ b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx @@ -28,7 +28,7 @@ export const ShareGroupsCreate = () => { const { control, handleSubmit, setError } = useForm(); - const { field: imagesField, fieldState } = useController({ + const { field: imagesController, fieldState } = useController({ control, name: 'images', }); @@ -53,15 +53,15 @@ export const ShareGroupsCreate = () => { }); const onChange = (image: Image) => { - const selectedImages = imagesField.value ?? []; + const selectedImages = imagesController.value ?? []; const { id, label, description } = image; const imagePayload = { id, label, description: description ?? undefined }; if (!selectedImages.some((img) => img.id === id)) { - imagesField.onChange([...selectedImages, imagePayload]); + imagesController.onChange([...selectedImages, imagePayload]); } else { - imagesField.onChange(selectedImages.filter((img) => img.id !== id)); + imagesController.onChange(selectedImages.filter((img) => img.id !== id)); } }; @@ -124,14 +124,16 @@ export const ShareGroupsCreate = () => { errorText={fieldState.error?.message} onSelect={onChange} pendoIDs={IMAGE_SELECT_TABLE_SHARE_GROUP_CREATE_PENDO_IDS} - selectedImageIds={imagesField.value?.map((img) => img.id) ?? []} + selectedImageIds={ + imagesController.value?.map((img) => img.id) ?? [] + } selectionMode="multi" /> - Selected images ({imagesField.value?.length ?? 0}) + Selected images ({imagesController.value?.length ?? 0}) Selected images is coming soon... From fb074ec48d2cf8cdd798b41b57fadc471fb455b4 Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Wed, 8 Apr 2026 14:59:09 -0400 Subject: [PATCH 07/12] Added changeset: Private Image Sharing: implement the images select table in the create share groups page --- .../.changeset/pr-13567-upcoming-features-1775674749388.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md diff --git a/packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md b/packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md new file mode 100644 index 00000000000..39304aa2fdd --- /dev/null +++ b/packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Private Image Sharing: implement the images select table in the create share groups page ([#13567](https://github.com/linode/manager/pull/13567)) From 3cf7aeabc873f4a50b5f8329a94f3f6c08d7dcff Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Wed, 8 Apr 2026 15:58:13 -0400 Subject: [PATCH 08/12] Update packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md Co-authored-by: Dajahi Wiley <114682940+dwiley-akamai@users.noreply.github.com> --- .../.changeset/pr-13567-upcoming-features-1775674749388.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md b/packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md index 39304aa2fdd..04fd0c9e1ee 100644 --- a/packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md +++ b/packages/manager/.changeset/pr-13567-upcoming-features-1775674749388.md @@ -2,4 +2,4 @@ "@linode/manager": Upcoming Features --- -Private Image Sharing: implement the images select table in the create share groups page ([#13567](https://github.com/linode/manager/pull/13567)) +Private Image Sharing: implement Select Images table on Share Group Create page ([#13567](https://github.com/linode/manager/pull/13567)) From b1f39cdc181fac7bfeeef8f7e0f27df6122d695c Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Wed, 8 Apr 2026 17:17:59 -0400 Subject: [PATCH 09/12] Fix bug with the image description in the image payload --- .../v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx index 66f24756e02..a65df7fbbd6 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx +++ b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx @@ -56,7 +56,7 @@ export const ShareGroupsCreate = () => { const selectedImages = imagesController.value ?? []; const { id, label, description } = image; - const imagePayload = { id, label, description: description ?? undefined }; + const imagePayload = { id, label, ...(description && { description }) }; if (!selectedImages.some((img) => img.id === id)) { imagesController.onChange([...selectedImages, imagePayload]); From 18ff17a5b58d9c8e89ed73554e4c426ff6e4de3c Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Thu, 9 Apr 2026 15:21:35 -0400 Subject: [PATCH 10/12] Add pendoId support for the landing header --- packages/manager/src/components/Breadcrumb/Breadcrumb.tsx | 6 ++++++ .../manager/src/components/LandingHeader/LandingHeader.tsx | 3 +++ .../ShareGroupsCreate/ShareGroupsCreateContainer.tsx | 2 +- .../src/features/Images/ImagesLanding/v2/constants.ts | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/components/Breadcrumb/Breadcrumb.tsx b/packages/manager/src/components/Breadcrumb/Breadcrumb.tsx index 6f9b14cfa49..d552503e5e8 100644 --- a/packages/manager/src/components/Breadcrumb/Breadcrumb.tsx +++ b/packages/manager/src/components/Breadcrumb/Breadcrumb.tsx @@ -40,6 +40,10 @@ export interface BreadcrumbProps { * A string representation of the path of a resource. Each crumb is separated by a `/` character. */ pathname: string; + /** + * A string that can be used to set a custom Pendo ID for the breadcrumb for tracking purposes. + */ + pendoId?: string; /** * A number indicating the position of the crumb to remove. Not zero indexed. */ @@ -65,6 +69,7 @@ export const Breadcrumb = (props: BreadcrumbProps) => { labelTitle, onEditHandlers, pathname, + pendoId, removeCrumbX, sx, } = props; @@ -91,6 +96,7 @@ export const Breadcrumb = (props: BreadcrumbProps) => { theme.spacing(3) }) }} {...breadcrumbDataAttrs} + data-pendo-id={pendoId} > void; onButtonKeyPress?: (e: React.KeyboardEvent) => void; onDocsClick?: () => void; + pendoId?: string; removeCrumbX?: number | number[]; shouldHideDocsAndCreateButtons?: boolean; spacingBottom?: 0 | 4 | 16 | 24; @@ -46,6 +47,7 @@ export const LandingHeader = ({ breadcrumbProps, buttonDataAttrs, createButtonText, + pendoId, disabledBreadcrumbEditButton, disabledCreateButton, docsLabel, @@ -98,6 +100,7 @@ export const LandingHeader = ({ {...breadcrumbDataAttrs} {...breadcrumbProps} disabledBreadcrumbEditButton={disabledBreadcrumbEditButton} + pendoId={pendoId} /> {!shouldHideDocsAndCreateButtons && ( diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreateContainer.tsx b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreateContainer.tsx index 7bf395df54b..536704009c9 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreateContainer.tsx +++ b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreateContainer.tsx @@ -12,9 +12,9 @@ export const ShareGroupsCreateContainer = () => { <> diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/constants.ts b/packages/manager/src/features/Images/ImagesLanding/v2/constants.ts index ab557b986e7..7413ba56074 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/constants.ts +++ b/packages/manager/src/features/Images/ImagesLanding/v2/constants.ts @@ -1,7 +1,7 @@ export const DEFAULT_PAGE_SIZES = [25, 50, 75, 100]; export const CREATE_SHARE_GROUP_PENDO_IDS = { - landingHeader: 'Share Groups Create Images-Landing Header', + landingHeader: 'Images Share Groups Create-Landing Header', label: 'Share Groups Create Images-Label', description: 'Share Groups Create Images-Description', createButton: 'Share Groups Create Images-Create Button', From 43326bdc3139486f28a6b599dcf4eb36faaa6fad Mon Sep 17 00:00:00 2001 From: fabrice-akamai Date: Fri, 10 Apr 2026 10:02:40 -0400 Subject: [PATCH 11/12] Add loading state for the submit button --- .../ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx index a65df7fbbd6..55bf18aecf0 100644 --- a/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx +++ b/packages/manager/src/features/Images/ImagesLanding/v2/ShareGroups/ShareGroupsCreate/ShareGroupsCreate.tsx @@ -25,8 +25,12 @@ export const ShareGroupsCreate = () => { const { mutateAsync: createShareGroup } = useCreateShareGroupMutation(); - const { control, handleSubmit, setError } = - useForm(); + const { + control, + handleSubmit, + setError, + formState: { isSubmitting }, + } = useForm(); const { field: imagesController, fieldState } = useController({ control, @@ -142,6 +146,7 @@ export const ShareGroupsCreate = () => {