-
Notifications
You must be signed in to change notification settings - Fork 396
upcoming: [UIE-9818, UIE-9820, UIE-9821, UIE-9822] - Implement product details for Marketplace #13271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
… details page for partner referral product
|
Ignore the styling for the content received from api in the tabs. Davyd will be providing the styling for different html elements and once we get I add it here accordingly. For now i have added sample styles to make the content look good. |
…html received as per figma
pmakode-akamai
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left some initial comments and will revisit the PR for a second look
packages/manager/src/features/Marketplace/ProductDetails/ProductDetails.tsx
Outdated
Show resolved
Hide resolved
packages/manager/src/features/Marketplace/ProductDetails/ProductDetails.tsx
Outdated
Show resolved
Hide resolved
packages/manager/src/features/Marketplace/ProductDetails/ProductDetails.tsx
Outdated
Show resolved
Hide resolved
packages/manager/src/features/Marketplace/ProductDetails/ProductDetails.tsx
Outdated
Show resolved
Hide resolved
packages/manager/src/features/Marketplace/ProductDetails/ProductDetailsTabs.tsx
Outdated
Show resolved
Hide resolved
packages/manager/src/features/Marketplace/ProductDetails/ProductDetailsTabs.tsx
Outdated
Show resolved
Hide resolved
harsh-akamai
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packages/manager/src/features/Marketplace/ProductDetails/sanitizeHtml.ts
Outdated
Show resolved
Hide resolved
packages/manager/src/features/Marketplace/ProductDetails/ProductDetails.tsx
Outdated
Show resolved
Hide resolved
| fontSize: theme.tokens.font.FontSize.Xs, | ||
| lineHeight: theme.tokens.font.LineHeight.Xs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fontSize and lineHeight is redundant. font covers both the properties
| fontSize: theme.tokens.font.FontSize.Xs, | ||
| lineHeight: theme.tokens.font.LineHeight.Xs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
| <HtmlContentRenderer content={details.overview.description} /> | ||
| </ContentSection> | ||
| <VideoPlaceholder> | ||
| <PlayCircleIcon /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (details.pricing?.description) { | ||
| availableTabs.push({ | ||
| content: <HtmlContentRenderer content={details.pricing.description} />, | ||
| label: 'Pricing', | ||
| pendoId: 'Cloud Marketplace Details-Pricing', | ||
| }); | ||
| } | ||
|
|
||
| if (details.documentation?.description) { | ||
| availableTabs.push({ | ||
| content: ( | ||
| <HtmlContentRenderer content={details.documentation.description} /> | ||
| ), | ||
| label: 'Documentation', | ||
| pendoId: 'Cloud Marketplace Details-Documentation', | ||
| }); | ||
| } | ||
|
|
||
| if (details.support?.description) { | ||
| availableTabs.push({ | ||
| content: <HtmlContentRenderer content={details.support.description} />, | ||
| label: 'Support', | ||
| pendoId: 'Cloud Marketplace Details-Support', | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: We could instead have a map containing the pendoId and label instead of defining separate if conditions for non-overview tabs
| paddingLeft: '8px', | ||
| paddingRight: '8px', | ||
| paddingTop: '8px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we can remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tvijay-akamai Any update on this if it's required or not? If required, then we should use spacingFunction here and for the gap
packages/manager/src/features/Marketplace/ProductDetails/ProductDetails.tsx
Outdated
Show resolved
Hide resolved
|
Can we add a changeset for this pr? |
|
What is the reason for one PR covering 4 tickets and nearing 1000 lined addition to the codebase? From what I can see this is a sensitive feature rendering server side sent HTML? Apart from being quite a suspicious pattern, this kind of work warrants a more careful approach with small bits PRs. I am already seeing far too many comments and I am concerned about the cleanliness of this feature as a whole, especially when I see the omission of sanitizing HTML that shouldn't be returned by an APIv4 endpoint. I'd recommend taking a step back - preventing merging for the time being |
| </table> | ||
| <h3>Status Page</h3> | ||
| <p>Check the current status of Akamai services at <a href="https://status.akamai.com">status.akamai.com</a></p> | ||
| `, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a fundamental issue if your endpoint is returning this random HTML. Who allowed this design?
|
This PR is stale because it has been open 15 days with no activity. Please attend to this PR or it will be closed in 5 days |
…details with new static design with approach
|
|
||
| import type { ProductTabDetails } from '.'; | ||
|
|
||
| const details: ProductTabDetails = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels a bit hard to read as is. Since we're not planning to use separate .md files, maybe we could define overview, pricing, documentation, and support as separate markdown constants above and then reference them here. That would make the file easier to scan and maintain.
| export interface ProductTabDetails { | ||
| documentation?: { | ||
| description: string; | ||
| }; | ||
| overview?: { | ||
| description: string; | ||
| }; | ||
| pricing?: { | ||
| description: string; | ||
| }; | ||
| support?: { | ||
| description: string; | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| export interface ProductTabDetails { | |
| documentation?: { | |
| description: string; | |
| }; | |
| overview?: { | |
| description: string; | |
| }; | |
| pricing?: { | |
| description: string; | |
| }; | |
| support?: { | |
| description: string; | |
| }; | |
| } | |
| export interface ProductTabDetails { | |
| documentation?: string; | |
| overview?: string; | |
| pricing?: string; | |
| support?: string; | |
| } |
Since this is currently static content and not coming from an API, do we need the extra { description } nesting? Using documentation?: string (and similar for other tabs) will simplify the model.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be better to move the data/details package under ProductDetails/ for better organization (and rename it to something like pages). Since these files represent product details page content, a structure like ProductDetails/pages/* would keep them closer to where they're used and make the intent clearer.
| * Each product's details are imported statically and available synchronously. | ||
| */ | ||
| const detailsMap: Record<number, ProductTabDetails> = { | ||
| 100001: product100001, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a blocker, but it might be worth checking with Product or UX whether we're okay with using sequential IDs like 100001, 100002, etc., OR if there's a recommended convention. For eg., OneClickApps uses larger non-sequential numeric IDs (e.g. 401697), so it might be worth aligning with that pattern if there's a reason behind it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned above, please use slugs
| fontSize: theme.tokens.font.FontSize.Xxxs, | ||
| fontFamily: theme.font.bold, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fontFamily doesn't seem to be working here. The text should be bold as per the Figma. I think we can achieve this by setting font and fontSize afterward
font: theme.font.bold,
fontSize: theme.tokens.font.FontSize.Xxxs, // Must come after font
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, let's add a changeset for this new icon (PlayCircleIcon) in the ui package
packages/manager/src/features/Marketplace/ProductDetails/ProductDetailsTabs.tsx
Show resolved
Hide resolved
harsh-akamai
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ); | ||
|
|
||
| // Tab content is optional. If not present for this product, we still show the page. | ||
| const details = getProductTabDetails(numericProductId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const details = getProductTabDetails(numericProductId); | |
| const details = React.useMemo( () => getProductTabDetails(numericProductId), [numericProductId])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useMemo Not needed as we're already fetching from map.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also no clarity on video yet, not important for now. we can leave it as is.
| if (!product) { | ||
| return ( | ||
| <ErrorState | ||
| errorText={'Unable to load product details. Please try again later.'} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we can move this if-block before the productDetails are fetched?
packages/manager/src/features/Marketplace/ProductDetails/ProductDetails.tsx
Outdated
Show resolved
Hide resolved
packages/manager/src/features/Marketplace/ProductDetails/TabContent.styles.ts
Show resolved
Hide resolved
| * This provides consistent styling for all HTML elements across tabs | ||
| * Styles follow Figma design specifications | ||
| */ | ||
| export const StyledHtmlContent = styled('div')(({ theme }) => ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| export const StyledHtmlContent = styled('div')(({ theme }) => ({ | |
| export const StyledTabContent = styled('div')(({ theme }) => ({ |
pmakode-akamai
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @tvijay-akamai -- overall this looks good. I've left a few more comments and questions that need to be looked into.
| paddingLeft: '8px', | ||
| paddingRight: '8px', | ||
| paddingTop: '8px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tvijay-akamai Any update on this if it's required or not? If required, then we should use spacingFunction here and for the gap
| alignItems: 'flex-start', | ||
| alignSelf: 'stretch', | ||
| display: 'flex', | ||
| gap: '24px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use spacingFunction for all gap values in this file
| alignItems: 'flex-start', | ||
| alignSelf: 'stretch', | ||
| display: 'flex', | ||
| gap: '24px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use spacingFunction here and below as well?
| fontStyle: 'normal', | ||
| lineHeight: theme.tokens.font.LineHeight.M, | ||
| margin: 0, | ||
| paddingBottom: theme.tokens.spacing.S16, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that we generally use spacingFunction, and we're already using it in the styles above. I don't think using theme.tokens.spacing.S16 is wrong either, but I'm not sure which way we should standardize on for consistency. @abailly-akamai thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will indeed result in the same outcome, but for consistency spacingFunction is preferred.
| support: supportMarkdown, | ||
| }; | ||
|
|
||
| export default details; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's use named exports
| @@ -0,0 +1,55 @@ | |||
| /** | |||
| * Product tab details for id 100001. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we please have IDs as product name slugs?? Static magic numbers are far more confusing and not appropriate for this, especially as your list will grow.
- Poor URL readability: /catalog/spinkube is more intuitive than /catalog/100001
- Not self-documenting: Looking at 100001.ts, you have no idea what product it represents without looking it up
- Developer experience: When debugging or creating new products, you have to constantly look up which ID maps to which product
- URL sharing: Users sharing links can't tell what product they're sharing
| * Each product's details are imported statically and available synchronously. | ||
| */ | ||
| const detailsMap: Record<number, ProductTabDetails> = { | ||
| 100001: product100001, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned above, please use slugs
| alignSelf: 'stretch', | ||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: '16px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use spacingFunction for ALL your gaps
| alignItems: 'flex-start', | ||
| alignSelf: 'stretch', | ||
| display: 'flex', | ||
| gap: '24px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same with gaps
| fontSize: theme.tokens.font.FontSize.Xs, | ||
| gap: '8px', | ||
| lineHeight: theme.tokens.font.LineHeight.Xs, | ||
| padding: '12px 16px 12px 12px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment with paddings and gaps
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: theme.spacingFunction(8), | ||
| height: '202px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we ok with a set height here rather than a responsive container?
Also, are we serving videos locally? Pictures is one thing but this is concerning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No videos will not be served locally. Currently there are no videos in beta.
Cloud Manager UI test results🎉 865 passing tests on test run #12 ↗︎
|
abailly-akamai
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your patience, finding a good MVP implementation and addressing a lot of feedback. While this will likely be revisited as the feature grows, this is a good start - to go on my end 👍



Details page for partner referral product
Description 📝
Refactor Marketplace details and Add dynamic product content to each tab for Products details page.
Note
There have been some changes in the approach for Marketplace from the Product. The APIs will no longer be available, and we will fully rely on client-side filtering and client-side management of Marketplace products
Changes 🔄
List any change(s) relevant to the reviewer.
Scope 🚢
Upon production release, changes in this PR will be visible to:
Target release date 🗓️
27 Feb 2026
How to test 🧪
Prerequisites
Reproduction steps
Verification steps
(How to verify changes)
Author Checklists
As an Author, to speed up the review process, I considered 🤔
👀 Doing a self review
❔ Our contribution guidelines
🤏 Splitting feature into small PRs
➕ Adding a changeset
🧪 Providing/improving test coverage
🔐 Removing all sensitive information from the code and PR description
🚩 Using a feature flag to protect the release
👣 Providing comprehensive reproduction steps
📑 Providing or updating our documentation
🕛 Scheduling a pair reviewing session
📱 Providing mobile support
♿ Providing accessibility support
As an Author, before moving this PR from Draft to Open, I confirmed ✅