Skip to content
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

feat: [M3-6466] Add resource links to Images empty state #9095

Merged
merged 7 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [Unreleased]

### Added:

- Resource links to empty state Volumes landing page #9065
- Resource links to empty state Firewalls landing page #9078
- Resource links to empty state Domains landing page #9092
- Resource links to empty state Images landing page #9095
- Ability download DNS zone file #9075

### Changed:

- Removed MongoDB reference from ClusterControl description #9081
- Highlighted Marketplace apps and button card height on empty state Linodes landing page #9083

### Fixed:

- Ability to search Linodes by IPv6 #9073

### Tech Stories:

- Enable Cypress `experimentalMemoryManagement` #9076
- MUI v5 Migration - `Components > Table` #9082
- MUI v5 Migration - `Components > TableCell` #9082
Expand All @@ -36,15 +41,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [2023-05-01] - v1.92.0

### Added:

- No Results section for Marketplace Search #8999
- Private IP checkbox when cloning a Linode #9039
- Metadata migrate warning #9033

### Changed:

- Region Select will dynamically get country flags and group all countries based on API data #8996
- Removed MongoDB Marketplace Apps #9071

### Fixed:

- Kubernetes Delete Dialog clears when it is re-opened #9000
- HTML showing up in event messages #9003
- Inability to edit and save Linode Configurations #9053
Expand All @@ -55,6 +63,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Blank Kubernetes Node Pool plan selection #9009

### Tech Stories:

- MUI v5 Migration - `Components > CircleProgress` #9028
- MUI v5 Migration - `Components > StatusIcon` #9014
- MUI v5 Migration - `Components > TagsInput, TagsPanel` #8995
Expand Down Expand Up @@ -89,27 +98,32 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [2023-04-18] - v1.91.1

### Fixed:

- Add Premium plans to LKE #9021

## [2023-04-17] - v1.91.0

### Added:

- Cross Data Center Clone warning #8937
- `Plan` column header to plan select table #8943

### Changed:

- Use Akamai logo for TPA provider screen #8982
- Use Akamai logo for the favicon #8988
- Only fetch grants when the user is restricted #8941
- Improve the StackScript user defined fields (UDF) forms #8973

### Fixed:

- Styling of Linode Details Add Configurations modal header #8981
- Alignment issues with Kubernetes Node Pool table and buttons #8967
- Domain Records not updating when navigating #8957
- Notification menu displaying empty menu on secondary status click #8902

### Tech Story:

- React Query for NodeBalancers #8964
- React Query for Profile - Trusted Devices #8942
- React Query for OAuth Apps #8938
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const StyledResourcesLinksSection = styled('div', {
gridAutoFlow: 'column',
justifyItems: 'center',
maxWidth: props.wide === false ? 762 : '100%',
[theme.breakpoints.down('md')]: {
[theme.breakpoints.down(props.wide ? 'lg' : 'md')]: {
gridAutoFlow: 'row',
rowGap: theme.spacing(8),
justifyItems: 'start',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ const StyledResourcesLinksSubSection = styled('div', {
gridTemplateRows: `22px minmax(${theme.spacing(3)}, 100%) 1.125rem`,
rowGap: theme.spacing(2),
width: '100%',
[theme.breakpoints.between('md', 'lg')]: {
gridTemplateRows: `50px minmax(${theme.spacing(3)}, 100%) 1.125rem`,
},
'& > h2': {
color: theme.palette.text.primary,
},
Expand Down
86 changes: 26 additions & 60 deletions packages/manager/src/features/Images/ImagesLanding.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,48 @@
import { Event, Image, ImageStatus } from '@linode/api-v4';
import { APIError } from '@linode/api-v4/lib/types';
import produce from 'immer';
import { useSnackbar } from 'notistack';
import * as React from 'react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import ImageIcon from 'src/assets/icons/entityIcons/image.svg';
import ActionsPanel from 'src/components/ActionsPanel';
import Button from 'src/components/Button';
import { CircleProgress } from 'src/components/CircleProgress';
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
import ErrorState from 'src/components/ErrorState';
import Hidden from 'src/components/core/Hidden';
import imageEvents from 'src/store/selectors/imageEvents';
import ImageRow, { ImageWithEvent } from './ImageRow';
import ImagesDrawer, { DrawerMode } from './ImagesDrawer';
import LandingHeader from 'src/components/LandingHeader';
import Paper from 'src/components/core/Paper';
import { makeStyles } from '@mui/styles';
import { Theme } from '@mui/material/styles';
import { TableBody } from 'src/components/TableBody';
import { TableHead } from 'src/components/TableHead';
import produce from 'immer';
import TableRowEmptyState from 'src/components/TableRowEmptyState';
import Typography from 'src/components/core/Typography';
import { APIError } from '@linode/api-v4/lib/types';
import { ApplicationState } from 'src/store';
import { CircleProgress } from 'src/components/CircleProgress';
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import ErrorState from 'src/components/ErrorState';
import LandingHeader from 'src/components/LandingHeader';
import Link from 'src/components/Link';
import { Event, Image, ImageStatus } from '@linode/api-v4';
import { getErrorStringOrDefault } from 'src/utilities/errorUtils';
import { Handlers as ImageHandlers } from './ImagesActionMenu';
import { ImagesLandingEmptyState } from './ImagesLandingEmptyState';
import { listToItemsByID } from 'src/queries/base';
import { makeStyles } from '@mui/styles';
import { Notice } from 'src/components/Notice/Notice';
import { PaginationFooter } from 'src/components/PaginationFooter/PaginationFooter';
import Placeholder from 'src/components/Placeholder';
import { Table } from 'src/components/Table';
import { TableBody } from 'src/components/TableBody';
import { TableCell } from 'src/components/TableCell';
import { TableHead } from 'src/components/TableHead';
import { TableRow } from 'src/components/TableRow';
import TableRowEmptyState from 'src/components/TableRowEmptyState';
import { TableSortCell } from 'src/components/TableSortCell';
import { Theme } from '@mui/material/styles';
import { useHistory } from 'react-router-dom';
import { useOrder } from 'src/hooks/useOrder';
import { usePagination } from 'src/hooks/usePagination';
import { listToItemsByID } from 'src/queries/base';
import { useQueryClient } from 'react-query';
import { useSelector } from 'react-redux';
import { useSnackbar } from 'notistack';
import {
queryKey,
removeImageFromCache,
useDeleteImageMutation,
useImagesQuery,
} from 'src/queries/images';
import { ApplicationState } from 'src/store';
import imageEvents from 'src/store/selectors/imageEvents';
import { getErrorStringOrDefault } from 'src/utilities/errorUtils';
import ImageRow, { ImageWithEvent } from './ImageRow';
import { Handlers as ImageHandlers } from './ImagesActionMenu';
import ImagesDrawer, { DrawerMode } from './ImagesDrawer';
import { useQueryClient } from 'react-query';

const useStyles = makeStyles((theme: Theme) => ({
imageTable: {
Expand Down Expand Up @@ -273,10 +271,6 @@ export const ImagesLanding: React.FC<CombinedProps> = () => {
});
};

const onCreateButtonClick = () => {
history.push('/images/create');
};

const onRetryClick = (
imageId: string,
imageLabel: string,
Expand Down Expand Up @@ -420,35 +414,7 @@ export const ImagesLanding: React.FC<CombinedProps> = () => {
};

const renderEmpty = () => {
return (
<React.Fragment>
<DocumentTitleSegment segment="Images" />
<Placeholder
title="Images"
icon={ImageIcon}
isEntity
buttonProps={[
{
onClick: onCreateButtonClick,
children: 'Create Image',
},
]}
>
<Typography variant="subtitle1">
Adding an image is easy. Click here to
</Typography>
<Typography variant="subtitle1">
<Link to="https://linode.com/docs/platform/disk-images/linode-images-new-manager/">
learn more about Images
</Link>
&nbsp;or&nbsp;
<Link to="https://linode.com/docs/quick-answers/linode-platform/deploy-an-image-to-a-linode">
deploy an Image to a Linode.
</Link>
</Typography>
</Placeholder>
</React.Fragment>
);
return <ImagesLandingEmptyState />;
};

if (manualImagesLoading || automaticImagesLoading) {
Expand Down Expand Up @@ -489,7 +455,7 @@ export const ImagesLanding: React.FC<CombinedProps> = () => {
<LandingHeader
title="Images"
entity="Image"
onButtonClick={onCreateButtonClick}
onButtonClick={() => history.push('/images/create')}
docsLink="https://www.linode.com/docs/platform/disk-images/linode-images/"
/>
<Paper className={classes.imageTable}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as React from 'react';
import ImageIcon from 'src/assets/icons/entityIcons/image.svg';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
import { sendEvent } from 'src/utilities/ga';
import { useHistory } from 'react-router-dom';
import {
gettingStartedGuides,
headers,
linkGAEvent,
youtubeLinkData,
} from './ImagesLandingEmptyStateData';

export const ImagesLandingEmptyState = () => {
const { push } = useHistory();

return (
<ResourcesSection
buttonProps={[
{
onClick: () => {
sendEvent({
category: linkGAEvent.category,
action: 'Click:button',
label: 'Create Image',
});
push('/images/create');
},
children: 'Create Image',
},
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
icon={ImageIcon}
linkGAEvent={linkGAEvent}
youtubeLinkData={youtubeLinkData}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
youtubeChannelLink,
youtubeMoreLinkText,
} from 'src/utilities/emptyStateLandingUtils';
import type {
ResourcesHeaders,
ResourcesLinkSection,
ResourcesLinks,
} from 'src/components/EmptyLandingPageResources/ResourcesLinksTypes';

export const headers: ResourcesHeaders = {
description:
'Store your own custom Linux images, enabling you to rapidly deploy Linode Compute Instances preconfigured with the software and settings you require.',
subtitle: '',
title: 'Images',
};

export const gettingStartedGuides: ResourcesLinkSection = {
links: [
{
to: 'https://www.linode.com/docs/products/tools/images/',
text: 'Overview of Custom Images',
},
{
to: 'https://www.linode.com/docs/products/tools/images/get-started/',
text: 'Getting Started with Custom Images',
},
{
to:
'https://www.linode.com/docs/products/tools/images/guides/capture-an-image/',
text: 'Capture an Image from a Linode',
},
{
to:
'https://www.linode.com/docs/products/tools/images/guides/upload-an-image/',
text: 'Upload a Custom Image',
},
],
moreInfo: {
to: 'https://www.linode.com/docs/products/tools/images/guides/',
text: 'View additional Images guides',
},
title: 'DNS Manager Guides',
};

export const youtubeLinkData: ResourcesLinkSection = {
links: [
{
to: 'https://www.youtube.com/watch?v=1nYhLui1urQ',
text:
'How to use Linode Images | Learn how to Create, Upload, and Deploy Custom Images on Linode',
external: true,
},
{
to: 'https://www.youtube.com/watch?v=GdEFNHTCGqA',
text:
'Custom Images on Linode | Create, Upload, and Deploy Custom iso Images to Deploy on Linode',
external: true,
},
{
to: 'https://www.youtube.com/watch?v=UNlJUzQrBBI',
text: 'Using Images and Backups on Linode',
external: true,
},
],
moreInfo: {
to: youtubeChannelLink,
text: youtubeMoreLinkText,
},
title: 'Video Playlist',
};

export const linkGAEvent: ResourcesLinks['linkGAEvent'] = {
action: 'Click:link',
category: 'Images landing page empty',
};