Skip to content

Commit

Permalink
CLAPPS: Add Images subtab (#4599)
Browse files Browse the repository at this point in the history
* WIP

* WIP 2

* Fix styling

* Fix StackScripts to use new SelectImagePanel

* Fix tab labels

* Add empty state for private images

* Review feedback

- Combine renderPublicImages and renderOlderPublicImages into a single function
- Use <span> instead of <Typography> for placeholder message
- Only pass needed props to FromImageContent

* Pass fewer props to other FromImagesContent instance

* Clean up post-rebase
  • Loading branch information
Jskobos authored Mar 4, 2019
1 parent c1eeee9 commit 01fe2ae
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 145 deletions.
47 changes: 44 additions & 3 deletions src/features/linodes/LinodesCreate/CALinodeCreate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,21 @@ export class LinodeCreate extends React.PureComponent<
linodesData,
linodesError,
linodesLoading,
handleSelectUDFs,
selectedUDFs,
updateStackScript,
availableStackScriptImages,
availableUserDefinedFields,
selectedStackScriptID,
selectedDiskSize,
selectedStackScriptUsername,
selectedStackScriptLabel,
selectedLinodeID,
...rest
} = this.props;
return (
<FromImageContent
publicOnly
variant="public"
imagePanelTitle="Choose a Distribution"
{...rest}
/>
Expand Down Expand Up @@ -136,14 +146,45 @@ export class LinodeCreate extends React.PureComponent<

myImagesTabs = (): Tab[] => [
{
title: 'Backups and My Images',
title: 'Images',
type: 'fromImage',
render: () => {
const {
history,
linodesData,
linodesError,
linodesLoading,
handleSelectUDFs,
selectedUDFs,
updateStackScript,
availableStackScriptImages,
availableUserDefinedFields,
selectedStackScriptID,
selectedDiskSize,
selectedStackScriptUsername,
selectedStackScriptLabel,
selectedLinodeID,
...rest
} = this.props;

return (
<FromImageContent
variant={'private'}
imagePanelTitle="Choose an Image"
{...rest}
/>
);
}
},
{
title: 'Backups',
type: 'fromBackup',
render: () => {
return <React.Fragment />;
}
},
{
title: 'Clone from Existing Linode',
title: 'Clone Linode',
type: 'fromLinode',
render: () => {
/**
Expand Down
48 changes: 48 additions & 0 deletions src/features/linodes/LinodesCreate/Panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react';

import {
StyleRulesCallback,
withStyles,
WithStyles
} from 'src/components/core/styles';

import Paper from 'src/components/core/Paper';
import Typography from 'src/components/core/Typography';
import Notice from 'src/components/Notice';

type ClassNames = 'root' | 'flatImagePanel';

const styles: StyleRulesCallback<ClassNames> = theme => ({
flatImagePanel: {
padding: theme.spacing.unit * 3
},
root: {}
});

interface Props {
children: React.ReactElement;
error?: string;
title?: string;
}

type CombinedProps = Props & WithStyles<ClassNames>;

const Panel: React.StatelessComponent<CombinedProps> = (props) => {
const { classes, children, error, title } = props;
return (
<Paper
className={classes.flatImagePanel}
data-qa-tp="Select Image"
>
{error && <Notice text={error} error />}
<Typography role="header" variant="h2" data-qa-tp="Select Image">
{title || 'Select an Image'}
</Typography>
{children}
</Paper>
)
}

const styled = withStyles(styles);

export default styled(Panel);
51 changes: 51 additions & 0 deletions src/features/linodes/LinodesCreate/PrivateImages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from 'react';

import {
StyleRulesCallback,
withStyles,
WithStyles
} from 'src/components/core/styles';
import Grid from 'src/components/Grid';
import SelectionCard from 'src/components/SelectionCard';

type ClassNames = 'root' | 'flatImagePanelSelections';

const styles: StyleRulesCallback<ClassNames> = theme => ({
flatImagePanelSelections: {
marginTop: theme.spacing.unit * 2,
padding: `${theme.spacing.unit}px 0`
},
root: {}
});
interface Props {
images: Linode.Image[];
disabled?: boolean;
selectedImageID?: string;
handleSelection: (id: string) => void;
}

type CombinedProps = Props & WithStyles<ClassNames>;

const PrivateImages: React.StatelessComponent<CombinedProps> = (props) => {
const { classes, disabled, handleSelection, images, selectedImageID } = props;
return (
<Grid container className={classes.flatImagePanelSelections} >
{images &&
images.map((image: Linode.Image, idx: number) => (
<SelectionCard
key={idx}
checked={image.id === String(selectedImageID)}
onClick={() => handleSelection(image.id)}
renderIcon={() => <span className="fl-tux" />}
heading={image.label as string}
subheadings={[image.description as string]}
disabled={disabled}
/>
))}
</Grid>
)
}

const styled = withStyles(styles);

export default styled(PrivateImages);
89 changes: 89 additions & 0 deletions src/features/linodes/LinodesCreate/PublicImages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as React from 'react';

import {
StyleRulesCallback,
withStyles,
WithStyles
} from 'src/components/core/styles';
import Grid from 'src/components/Grid';
import SelectionCard from 'src/components/SelectionCard';
import ShowMoreExpansion from 'src/components/ShowMoreExpansion';

type ClassNames = 'root' | 'flatImagePanelSelections';

const styles: StyleRulesCallback<ClassNames> = theme => ({
flatImagePanelSelections: {
marginTop: theme.spacing.unit * 2,
padding: `${theme.spacing.unit}px 0`
},
root: {}
});
interface Props {
images: Linode.Image[];
oldImages: Linode.Image[];
selectedImageID?: string;
disabled?: boolean;
handleSelection: (id: string) => void;
}

type CombinedProps = Props & WithStyles<ClassNames>;

const distroIcons = {
Arch: 'archlinux',
CentOS: 'centos',
CoreOS: 'coreos',
Debian: 'debian',
Fedora: 'fedora',
Gentoo: 'gentoo',
openSUSE: 'opensuse',
Slackware: 'slackware',
Ubuntu: 'ubuntu'
};

const PublicImages: React.StatelessComponent<CombinedProps> = props => {
const {
classes,
disabled,
images,
handleSelection,
oldImages,
selectedImageID
} = props;
const renderImages = (images: Linode.Image[]) =>
images.length &&
images.map((image: Linode.Image, idx: number) => (
<SelectionCard
key={idx}
checked={image.id === String(selectedImageID)}
onClick={() => handleSelection(image.id)}
renderIcon={() => {
return (
<span className={`fl-${distroIcons[image.vendor as string]}`} />
);
}}
heading={image.vendor as string}
subheadings={[image.label]}
data-qa-selection-card
disabled={disabled}
/>
));

return (
<>
<Grid className={classes.flatImagePanelSelections} container>
{renderImages(images)}
</Grid>
{oldImages.length > 0 && (
<ShowMoreExpansion name="Show Older Images">
<Grid container spacing={16} style={{ marginTop: 16 }}>
{renderImages(oldImages)}
</Grid>
</ShowMoreExpansion>
)}
</>
);
};

const styled = withStyles(styles);

export default styled(PublicImages);
Loading

0 comments on commit 01fe2ae

Please sign in to comment.