Migrate Images plugin to ant.design
Summary: {gif:xcsasxxe}
Reviewed By: mweststrate
Differential Revision: D28463799
fbshipit-source-id: 280eaaf0ad5858b3507055a278d1f98fd5668fd0
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6e206fc054
commit
996e8ab87c
@@ -10,23 +10,22 @@
|
||||
import {CacheInfo, ImageId, ImageData, ImagesList} from './api';
|
||||
import {ImageEventWithId} from './index';
|
||||
|
||||
import {styled, Layout, Toolbar, theme} from 'flipper-plugin';
|
||||
import {
|
||||
Toolbar,
|
||||
Button,
|
||||
Spacer,
|
||||
colors,
|
||||
FlexBox,
|
||||
FlexRow,
|
||||
FlexColumn,
|
||||
LoadingIndicator,
|
||||
styled,
|
||||
ToggleButton,
|
||||
Text,
|
||||
} from 'flipper';
|
||||
Switch,
|
||||
Empty,
|
||||
Skeleton,
|
||||
Typography,
|
||||
Image,
|
||||
Row,
|
||||
Col,
|
||||
Badge,
|
||||
} from 'antd';
|
||||
import MultipleSelect from './MultipleSelect';
|
||||
import {ImagesMap} from './ImagePool';
|
||||
import {clipboard} from 'electron';
|
||||
import React, {ChangeEvent, KeyboardEvent, PureComponent} from 'react';
|
||||
import React, {PureComponent} from 'react';
|
||||
import {DeleteFilled} from '@ant-design/icons';
|
||||
|
||||
function formatMB(bytes: number) {
|
||||
return Math.floor(bytes / (1024 * 1024)) + 'MB';
|
||||
@@ -42,26 +41,16 @@ type ToggleProps = {
|
||||
toggled: boolean;
|
||||
};
|
||||
|
||||
const ToolbarToggleButton = styled(ToggleButton)(() => ({
|
||||
alignSelf: 'center',
|
||||
marginRight: 4,
|
||||
minWidth: 30,
|
||||
}));
|
||||
|
||||
const ToggleLabel = styled(Text)(() => ({
|
||||
whiteSpace: 'nowrap',
|
||||
}));
|
||||
|
||||
function Toggle(props: ToggleProps) {
|
||||
return (
|
||||
<>
|
||||
<ToolbarToggleButton
|
||||
<Switch
|
||||
onClick={() => {
|
||||
props.onClick && props.onClick(!props.toggled);
|
||||
}}
|
||||
toggled={props.toggled}
|
||||
checked={props.toggled}
|
||||
/>
|
||||
<ToggleLabel>{props.label}</ToggleLabel>
|
||||
<Typography.Text>{props.label}</Typography.Text>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -104,39 +93,11 @@ export default class ImagesCacheOverview extends PureComponent<
|
||||
size: 150,
|
||||
};
|
||||
|
||||
static Container = styled(FlexColumn)({
|
||||
backgroundColor: colors.white,
|
||||
});
|
||||
|
||||
static Content = styled(FlexColumn)({
|
||||
flex: 1,
|
||||
overflow: 'auto',
|
||||
});
|
||||
|
||||
static Empty = styled(FlexBox)({
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
onImageSelected = (selectedImage: ImageId) => {
|
||||
this.setState({selectedImage});
|
||||
this.props.onImageSelected(selectedImage);
|
||||
};
|
||||
|
||||
onKeyDown = (e: KeyboardEvent) => {
|
||||
const selectedImage = this.state.selectedImage;
|
||||
const imagesMap = this.props.imagesMap;
|
||||
|
||||
if (selectedImage) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
|
||||
clipboard.writeText(String(imagesMap[selectedImage]));
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onEnableDebugOverlayToggled = () => {
|
||||
this.props.onEnableDebugOverlay(!this.props.isDebugOverlayEnabled);
|
||||
};
|
||||
@@ -145,9 +106,6 @@ export default class ImagesCacheOverview extends PureComponent<
|
||||
this.props.onEnableAutoRefresh(!this.props.isAutoRefreshEnabled);
|
||||
};
|
||||
|
||||
onChangeSize = (e: ChangeEvent<HTMLInputElement>) =>
|
||||
this.setState({size: parseInt(e.target.value, 10)});
|
||||
|
||||
onSurfaceOptionsChange = (selectedItem: string, checked: boolean) => {
|
||||
const {allSurfacesOption, surfaceOptions} = this.props;
|
||||
const selectedSurfaces = new Set([...this.props.selectedSurfaces]);
|
||||
@@ -190,12 +148,11 @@ export default class ImagesCacheOverview extends PureComponent<
|
||||
) > 0;
|
||||
|
||||
return (
|
||||
<ImagesCacheOverview.Container
|
||||
grow
|
||||
onKeyDown={this.onKeyDown}
|
||||
tabIndex={0}>
|
||||
<Toolbar position="top">
|
||||
<Button icon="trash" onClick={this.props.onTrimMemory}>
|
||||
<Layout.Top>
|
||||
<Toolbar>
|
||||
<Button
|
||||
icon={<DeleteFilled></DeleteFilled>}
|
||||
onClick={this.props.onTrimMemory}>
|
||||
Trim Memory
|
||||
</Button>
|
||||
<Button onClick={this.props.onRefresh}>Refresh</Button>
|
||||
@@ -230,21 +187,13 @@ export default class ImagesCacheOverview extends PureComponent<
|
||||
onClick={this.props.onShowDiskImages}
|
||||
label="Show Disk Images"
|
||||
/>
|
||||
<Spacer />
|
||||
<input
|
||||
type="range"
|
||||
onChange={this.onChangeSize}
|
||||
min={50}
|
||||
max={150}
|
||||
value={this.state.size}
|
||||
/>
|
||||
</Toolbar>
|
||||
{!hasImages ? (
|
||||
<ImagesCacheOverview.Empty>
|
||||
<LoadingIndicator size={50} />
|
||||
</ImagesCacheOverview.Empty>
|
||||
<Layout.Container pad>
|
||||
<Empty />
|
||||
</Layout.Container>
|
||||
) : (
|
||||
<ImagesCacheOverview.Content>
|
||||
<Layout.ScrollContainer>
|
||||
{this.props.images.map((data: CacheInfo, index: number) => {
|
||||
const maxSize = data.maxSizeBytes;
|
||||
const subtitle = maxSize
|
||||
@@ -263,15 +212,14 @@ export default class ImagesCacheOverview extends PureComponent<
|
||||
onImageSelected={this.onImageSelected}
|
||||
selectedImage={this.state.selectedImage}
|
||||
imagesMap={this.props.imagesMap}
|
||||
size={this.state.size}
|
||||
events={this.props.events}
|
||||
onClear={onClear}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ImagesCacheOverview.Content>
|
||||
</Layout.ScrollContainer>
|
||||
)}
|
||||
</ImagesCacheOverview.Container>
|
||||
</Layout.Top>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -284,7 +232,6 @@ class ImageGrid extends PureComponent<{
|
||||
onImageSelected: (image: ImageId) => void;
|
||||
onClear: (() => void) | undefined;
|
||||
imagesMap: ImagesMap;
|
||||
size: number;
|
||||
events: Array<ImageEventWithId>;
|
||||
}> {
|
||||
static Content = styled.div({
|
||||
@@ -298,31 +245,48 @@ class ImageGrid extends PureComponent<{
|
||||
return null;
|
||||
}
|
||||
|
||||
const ROW_SIZE = 6;
|
||||
const imageRows = Array(Math.ceil(images.length / ROW_SIZE))
|
||||
.fill(0)
|
||||
.map((_, index) => index * ROW_SIZE)
|
||||
.map((begin) => images.slice(begin, begin + ROW_SIZE));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout.Container gap>
|
||||
<ImageGridHeader
|
||||
key="header"
|
||||
title={this.props.title}
|
||||
subtitle={this.props.subtitle}
|
||||
onClear={this.props.onClear}
|
||||
/>
|
||||
<ImageGrid.Content key="content">
|
||||
{images.map((imageId) => (
|
||||
<ImageItem
|
||||
imageId={imageId}
|
||||
image={this.props.imagesMap[imageId]}
|
||||
key={imageId}
|
||||
selected={selectedImage != null && selectedImage === imageId}
|
||||
onSelected={onImageSelected}
|
||||
size={this.props.size}
|
||||
numberOfRequests={
|
||||
this.props.events.filter((e) => e.imageIds.includes(imageId))
|
||||
.length
|
||||
}
|
||||
/>
|
||||
|
||||
<Layout.Container pad>
|
||||
{imageRows.map((row, rowIndex) => (
|
||||
<Layout.Container pad key={rowIndex}>
|
||||
<Row key={rowIndex} align={'middle'} gutter={[8, 24]}>
|
||||
{row.map((imageId, colIndex) => (
|
||||
<Col key={colIndex} span={24 / ROW_SIZE}>
|
||||
<ImageItem
|
||||
imageId={imageId}
|
||||
image={this.props.imagesMap[imageId]}
|
||||
key={imageId}
|
||||
selected={
|
||||
selectedImage != null && selectedImage === imageId
|
||||
}
|
||||
onSelected={onImageSelected}
|
||||
numberOfRequests={
|
||||
this.props.events.filter((e) =>
|
||||
e.imageIds.includes(imageId),
|
||||
).length
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</Layout.Container>
|
||||
))}
|
||||
</ImageGrid.Content>
|
||||
</>
|
||||
</Layout.Container>
|
||||
</Layout.Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -332,56 +296,23 @@ class ImageGridHeader extends PureComponent<{
|
||||
subtitle: string;
|
||||
onClear: (() => void) | undefined;
|
||||
}> {
|
||||
static Container = styled(FlexRow)({
|
||||
color: colors.dark70,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
marginLeft: 15,
|
||||
marginRight: 15,
|
||||
marginBottom: 15,
|
||||
borderBottom: `1px solid ${colors.light10}`,
|
||||
flexShrink: 0,
|
||||
alignItems: 'center',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
backgroundColor: colors.white,
|
||||
zIndex: 3,
|
||||
});
|
||||
|
||||
static Heading = styled.span({
|
||||
fontSize: 22,
|
||||
fontWeight: 600,
|
||||
});
|
||||
|
||||
static Subtitle = styled.span({
|
||||
fontSize: 22,
|
||||
fontWeight: 300,
|
||||
marginLeft: 15,
|
||||
});
|
||||
|
||||
static ClearButton = styled(Button)({
|
||||
alignSelf: 'center',
|
||||
height: 30,
|
||||
marginLeft: 'auto',
|
||||
width: 100,
|
||||
});
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ImageGridHeader.Container>
|
||||
<ImageGridHeader.Heading>{this.props.title}</ImageGridHeader.Heading>
|
||||
<Layout.Horizontal gap pad grow borderBottom>
|
||||
<Typography.Title>{this.props.title}</Typography.Title>
|
||||
<ImageGridHeader.Subtitle>
|
||||
{this.props.subtitle}
|
||||
</ImageGridHeader.Subtitle>
|
||||
<Spacer />
|
||||
|
||||
{this.props.onClear ? (
|
||||
<ImageGridHeader.ClearButton onClick={this.props.onClear}>
|
||||
Clear Cache
|
||||
</ImageGridHeader.ClearButton>
|
||||
<Button onClick={this.props.onClear}>Clear Cache</Button>
|
||||
) : null}
|
||||
</ImageGridHeader.Container>
|
||||
</Layout.Horizontal>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -394,36 +325,16 @@ class ImageItem extends PureComponent<{
|
||||
size: number;
|
||||
numberOfRequests: number;
|
||||
}> {
|
||||
static Container = styled(FlexBox)<{size: number}>((props) => ({
|
||||
float: 'left',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
height: props.size,
|
||||
width: props.size,
|
||||
borderRadius: 4,
|
||||
marginRight: 15,
|
||||
marginBottom: 15,
|
||||
backgroundColor: colors.light02,
|
||||
}));
|
||||
|
||||
static Image = styled.img({
|
||||
borderRadius: 4,
|
||||
maxHeight: '100%',
|
||||
maxWidth: '100%',
|
||||
objectFit: 'contain',
|
||||
});
|
||||
|
||||
static Loading = styled.span({
|
||||
padding: '0 0',
|
||||
});
|
||||
static defaultProps = {
|
||||
size: 150,
|
||||
};
|
||||
|
||||
static SelectedHighlight = styled.div<{selected: boolean}>((props) => ({
|
||||
borderColor: colors.highlight,
|
||||
borderColor: theme.primaryColor,
|
||||
borderStyle: 'solid',
|
||||
borderWidth: props.selected ? 3 : 0,
|
||||
borderRadius: 4,
|
||||
boxShadow: props.selected ? `inset 0 0 0 1px ${colors.white}` : 'none',
|
||||
boxShadow: props.selected ? `inset 0 0 0 1px ${theme.white}` : 'none',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
@@ -431,25 +342,26 @@ class ImageItem extends PureComponent<{
|
||||
top: 0,
|
||||
}));
|
||||
|
||||
static HoverOverlay = styled(FlexColumn)<{selected: boolean; size: number}>(
|
||||
(props) => ({
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.whiteAlpha80,
|
||||
bottom: props.selected ? 4 : 0,
|
||||
fontSize: props.size > 100 ? 16 : 11,
|
||||
justifyContent: 'center',
|
||||
left: props.selected ? 4 : 0,
|
||||
opacity: 0,
|
||||
position: 'absolute',
|
||||
right: props.selected ? 4 : 0,
|
||||
top: props.selected ? 4 : 0,
|
||||
overflow: 'hidden',
|
||||
transition: '.1s opacity',
|
||||
'&:hover': {
|
||||
opacity: 1,
|
||||
},
|
||||
}),
|
||||
);
|
||||
static HoverOverlay = styled(Layout.Container)<{
|
||||
selected: boolean;
|
||||
size: number;
|
||||
}>((props) => ({
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(255,255,255,0.8)',
|
||||
bottom: props.selected ? 4 : 0,
|
||||
fontSize: props.size > 100 ? 16 : 11,
|
||||
justifyContent: 'center',
|
||||
left: props.selected ? 4 : 0,
|
||||
opacity: 0,
|
||||
position: 'absolute',
|
||||
right: props.selected ? 4 : 0,
|
||||
top: props.selected ? 4 : 0,
|
||||
overflow: 'hidden',
|
||||
transition: '.1s opacity',
|
||||
'&:hover': {
|
||||
opacity: 1,
|
||||
},
|
||||
}));
|
||||
|
||||
static MemoryLabel = styled.span({
|
||||
fontWeight: 600,
|
||||
@@ -460,25 +372,13 @@ class ImageItem extends PureComponent<{
|
||||
fontWeight: 300,
|
||||
});
|
||||
|
||||
static Events = styled.div({
|
||||
static EventBadge = styled(Badge)({
|
||||
position: 'absolute',
|
||||
top: -5,
|
||||
right: -5,
|
||||
color: colors.white,
|
||||
backgroundColor: colors.highlight,
|
||||
fontWeight: 600,
|
||||
borderRadius: 10,
|
||||
fontSize: '0.85em',
|
||||
zIndex: 2,
|
||||
lineHeight: '20px',
|
||||
width: 20,
|
||||
textAlign: 'center',
|
||||
top: 0,
|
||||
right: 0,
|
||||
zIndex: 1,
|
||||
});
|
||||
|
||||
static defaultProps = {
|
||||
size: 150,
|
||||
};
|
||||
|
||||
onClick = () => {
|
||||
this.props.onSelected(this.props.imageId);
|
||||
};
|
||||
@@ -487,14 +387,14 @@ class ImageItem extends PureComponent<{
|
||||
const {image, selected, size, numberOfRequests} = this.props;
|
||||
|
||||
return (
|
||||
<ImageItem.Container onClick={this.onClick} size={size}>
|
||||
<Layout.Container onClick={this.onClick} gap>
|
||||
{numberOfRequests > 0 && image != null && (
|
||||
<ImageItem.Events>{numberOfRequests}</ImageItem.Events>
|
||||
<ImageItem.EventBadge count={numberOfRequests}></ImageItem.EventBadge>
|
||||
)}
|
||||
{image != null ? (
|
||||
<ImageItem.Image src={image.data} />
|
||||
<Image src={image.data} preview={false} />
|
||||
) : (
|
||||
<LoadingIndicator size={25} />
|
||||
<Skeleton.Image />
|
||||
)}
|
||||
<ImageItem.SelectedHighlight selected={selected} />
|
||||
{image != null && (
|
||||
@@ -507,7 +407,7 @@ class ImageItem extends PureComponent<{
|
||||
</ImageItem.SizeLabel>
|
||||
</ImageItem.HoverOverlay>
|
||||
)}
|
||||
</ImageItem.Container>
|
||||
</Layout.Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user