Skip to content

Commit

Permalink
Enhance UX on Bucket & Data Browser: ZENKO-3185, ZENKO-3202, ZENKO-3212
Browse files Browse the repository at this point in the history
  • Loading branch information
theocerutti committed Apr 26, 2021
1 parent 6973784 commit 948db40
Show file tree
Hide file tree
Showing 20 changed files with 276 additions and 55 deletions.
7 changes: 7 additions & 0 deletions assetsTransformer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const path = require('path');

module.exports = {
process(src, filename, config, options) {
return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
},
};
2 changes: 2 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module.exports = {
testMatch: [ '**/__tests__/?(*.)+(test).js?(x)'],
moduleNameMapper: {
'\\.(css|scss)$': 'identity-obj-proxy',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/assetsTransformer.js',
'\\.(css|less)$': '<rootDir>/assetsTransformer.js',
},
setupFiles: ['<rootDir>/.jest-setup.js'],
};
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"@fortawesome/fontawesome-free": "5.7.2",
"@hapi/joi": "^17.1.1",
"@hookform/resolvers": "^0.1.0",
"@scality/core-ui": "github:scality/core-ui.git#v0.16.0",
"@scality/core-ui": "github:scality/core-ui.git#v0.18.0",
"async": "^3.2.0",
"aws-sdk": "^2.616.0",
"connected-react-router": "^6.7.0",
Expand Down
4 changes: 4 additions & 0 deletions public/assets/logo-multi-buckets.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 7 additions & 4 deletions src/react/ZenkoUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ErrorHandlerModal from './ui-elements/ErrorHandlerModal';
import Loader from './ui-elements/Loader';
import ReauthDialog from './ui-elements/ReauthDialog';
import Routes from './Routes';
import ScrollbarWrapper from './ui-elements/ScrollbarWrapper';
import { ThemeProvider } from 'styled-components';
import { loadAppConfig } from './actions';

Expand Down Expand Up @@ -52,10 +53,12 @@ function ZenkoUI() {
}

return <ThemeProvider theme={theme}>
<MainContainer>
<ReauthDialog/>
{content()}
</MainContainer>
<ScrollbarWrapper> { /* TODO: replace with core-ui scrollbar when colors are set correctly */ }
<MainContainer>
<ReauthDialog/>
{content()}
</MainContainer>
</ScrollbarWrapper>
</ThemeProvider>;
}

Expand Down
31 changes: 16 additions & 15 deletions src/react/databrowser/buckets/BucketHead.jsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
// @flow
import * as L from '../../ui-elements/ListLayout2';

import MultiBucketsLogo from '../../../../public/assets/logo-multi-buckets.svg';
import React from 'react';
import type { S3BucketList } from '../../../types/s3';
import styled from 'styled-components';

const Number = styled.div`
font-size: 50px;
`;

const Unit = styled.div`
`;

import { TextBadge } from '../../ui-elements/TextBadge';

type Props = {
buckets: S3BucketList,
};
export default function BucketHead({ buckets }: Props){
export default function BucketHead({ buckets }: Props) {
const bucketLength = buckets ? buckets.size : 0;

return <L.Head>
<L.HeadSlice>
<Number>
{ buckets.size }
</Number>
<Unit> bucket{ buckets.size > 1 && 's' } </Unit>
<L.HeadIcon>
<img src={ MultiBucketsLogo } alt="Multi Buckets Logo" />
</L.HeadIcon>
</L.HeadSlice>
<L.HeadBody>
<L.HeadTitleContainer>
<L.HeadTitle>
All Buckets
<TextBadge text={ bucketLength } variant='infoPrimary'/>
</L.HeadTitle>
</L.HeadTitleContainer>
</L.HeadBody>
</L.Head>;
}
15 changes: 11 additions & 4 deletions src/react/databrowser/objects/ObjectHead.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// @flow
// @noflow
import * as L from '../../ui-elements/ListLayout2';
import React from 'react';

type Props = {
bucketNameParam?: string,
bucketName?: string,
};
export default function ObjectHead({ bucketNameParam }: Props){
export default function ObjectHead({ bucketName }: Props) {
return <L.Head>
<L.HeadSlice>
{bucketNameParam}
<L.HeadIcon className="fa fa-glass-whiskey"/>
</L.HeadSlice>
<L.HeadBody>
<L.HeadTitleContainer>
<L.HeadTitle>
{ bucketName }
</L.HeadTitle>
</L.HeadTitleContainer>
</L.HeadBody>
</L.Head>;
}
30 changes: 15 additions & 15 deletions src/react/databrowser/objects/ObjectListTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { useFilters, useFlexLayout, useSortBy, useTable } from 'react-table';
import type { AppState } from '../../../types/state';
import { AutoSizer } from 'react-virtualized';
import { Checkbox } from '../../ui-elements/FormLayout';
import { FixedSizeList } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
import { List } from 'immutable';
Expand Down Expand Up @@ -57,23 +58,22 @@ export default function ObjectListTable({ objects, bucketName, toggled, isVersio
accessor: '',
Cell({ row: { original } }: CellProps) {
return (
<input
type="checkbox"
className="checkbox"
checked={original.toggled}
onClick={(e) => {
e.stopPropagation(); // Prevent checkbox and clickable table row conflict.
dispatch(toggleObject(original.key, original.versionId));
}}
/>
<div style={{ textOverflow: 'clip' }}>
<Checkbox
name="objectCheckbox"
checked={original.toggled}
onClick={(e) => e.stopPropagation() } // Prevent checkbox and clickable table row conflict.
onChange={() => dispatch(toggleObject(original.key, original.versionId)) }
/>
</div>
);
},
Header: <input
type="checkbox"
className="checkbox"
checked={isToggledFull}
onChange={() => dispatch(toggleAllObjects(!isToggledFull))}
/>,
Header:
<Checkbox
name="objectsHeaderCheckbox"
checked={isToggledFull}
onChange={() => dispatch(toggleAllObjects(!isToggledFull))}
/>,
disableSortBy: true,
width: 1,
},
Expand Down
2 changes: 1 addition & 1 deletion src/react/databrowser/objects/Objects.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function Objects(){
<ObjectDelete bucketInfo={bucketInfo} bucketName={bucketNameParam} toggled={toggled} prefixWithSlash={prefixWithSlash}/>
<ObjectUpload bucketName={bucketNameParam} prefixWithSlash={prefixWithSlash}/>
<FolderCreate bucketName={bucketNameParam} prefixWithSlash={prefixWithSlash}/>
<ObjectHead bucketNameParam={bucketNameParam}/>
<ObjectHead bucketName={bucketNameParam}/>

<L.Body>
<ObjectList bucketInfo={bucketInfo} toggled={toggled} objects={objects} bucketName={bucketNameParam} prefixWithSlash={prefixWithSlash} listType={listType} />
Expand Down
5 changes: 2 additions & 3 deletions src/react/databrowser/objects/__tests__/ObjectList.test.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as s3object from '../../../actions/s3object';
import { BUCKET_INFO, FIRST_FORMATTED_OBJECT, SECOND_FORMATTED_OBJECT } from './utils/testUtil';
import { LIST_OBJECTS_METADATA_TYPE, LIST_OBJECTS_S3_TYPE } from '../../../utils/s3';
import { checkBox, reduxMount } from '../../../utils/test';
import { BUCKET_NAME } from '../../../actions/__tests__/utils/testUtil';
import { List } from 'immutable';
import ObjectList from '../ObjectList';
import React from 'react';
import { reduxMount } from '../../../utils/test';

describe('ObjectList', () => {
afterEach(() => {
Expand Down Expand Up @@ -84,8 +84,7 @@ describe('ObjectList', () => {
bucketName={BUCKET_NAME} prefixWithSlash='' toggled={List()} bucketInfo={BUCKET_INFO}/>,
);

const toggleAllObjectsButton = component.find('th#object-list-table-head-checkbox > input');
toggleAllObjectsButton.simulate('change');
checkBox(component, 'objectsHeaderCheckbox', true);
expect(toggleAllObjectsSpy).toHaveBeenCalledTimes(1);
});

Expand Down
10 changes: 8 additions & 2 deletions src/react/databrowser/objects/details/Properties.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ import { formatBytes, formatDate } from '../../../utils';
import { Clipboard } from '../../../ui-elements/Clipboard';
import type { ObjectMetadata } from '../../../../types/s3';
import React from 'react';
import TruncatedText from '../../../ui-elements/TruncatedText';
import styled from 'styled-components';

type Props = {
objectMetadata: ObjectMetadata,
};

const TruncatedValue = styled(T.Value)`
max-width: 300px;
`;

function Properties({ objectMetadata }: Props) {
return (
<div>
Expand All @@ -20,7 +26,7 @@ function Properties({ objectMetadata }: Props) {
</T.Row>
<T.Row hidden={!objectMetadata.versionId}>
<T.Key> Version ID </T.Key>
<T.Value> {objectMetadata.versionId} </T.Value>
<TruncatedValue copiable> <TruncatedText text={objectMetadata.versionId} trailingCharCount={7} /> </TruncatedValue>
<T.ExtraCell> <Clipboard text={objectMetadata.versionId}/> </T.ExtraCell>
</T.Row>
<T.Row>
Expand All @@ -33,7 +39,7 @@ function Properties({ objectMetadata }: Props) {
</T.Row>
<T.Row>
<T.Key> ETag </T.Key>
<T.Value> {objectMetadata.eTag} </T.Value>
<T.Value copiable>{objectMetadata.eTag}</T.Value>
<T.ExtraCell> <Clipboard text={objectMetadata.eTag}/> </T.ExtraCell>
</T.Row>
</T.Body>
Expand Down
6 changes: 3 additions & 3 deletions src/react/ui-elements/Breadcrumb.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ const breadcrumbPaths = (pathname: string): Array<Element<'label'>> => {
return <label key={s}><Link to={{ pathname: `/buckets/${bucketName}/objects/${prefix}` }}> {s} </Link></label>;
});
return [
<label key='buckets'> <Link to={{ pathname: '/buckets' }}> buckets </Link> </label>,
<label key='buckets'> <Link to={{ pathname: '/buckets' }}> All Buckets </Link> </label>,
<label key='objects'> <Link to={{ pathname: `/buckets/${bucketName}/objects` }}> {bucketName} </Link></label>,
...splitLabels,
];
}
match = matchPath(pathname, { path: '/buckets/:bucketName/objects' });
if (match) {
return [
<label key='buckets'><Link to={{ pathname: '/buckets' }}> buckets </Link></label>,
<label key='buckets'><Link to={{ pathname: '/buckets' }}> All Buckets </Link></label>,
<label key='bucket-name'>{match.params.bucketName}</label>,
];
}
match = matchPath(pathname, { path: '/buckets/:bucketName' });
if (match) {
return [
<label key='buckets'>buckets</label>,
<label key='buckets'>All Buckets</label>,
];
}
return [];
Expand Down
2 changes: 1 addition & 1 deletion src/react/ui-elements/Container.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const MainContainer = styled.div`
display: flex;
width: 100%;
height: 100vh;
overflow: scroll;
overflow: auto;
color: ${props => props.theme.brand.textPrimary};
font-size: ${fontSize.base};
Expand Down
46 changes: 42 additions & 4 deletions src/react/ui-elements/ListLayout2.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,58 @@ export const ContentContainer = styled.div`

export const Head = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
min-height: 80px;
padding: ${padding.base};
padding-left: 32px;
background-color: ${props => props.theme.brand.backgroundLevel3};
`;

export const HeadContainer = styled.div`
display: flex;
align-items: center;
`;

export const HeadTitleContainer = styled.div`
display: flex;
margin-top: ${padding.base};
`;

export const HeadTitle = styled.div`
display: flex;
color: ${props => props.theme.brand.textSecondary};
font-size: ${fontSize.large};
margin-right: ${padding.small};
align-items: center;
`;

export const HeadSlice = styled.div`
display: flex;
flex: 0 1 100px;
flex-direction: column;
justify-content: center;
align-self: center;
text-align: center;
margin-right: ${padding.large};
`;

export const HeadBody = styled.div`
`;

export const HeadIcon = styled.i`
display: flex;
color: ${props => props.theme.brand.statusHealthy};
background-color: ${props => props.theme.brand.backgroundLevel1};
border-radius: 100%;
border: 1px solid ${props => props.theme.brand.infoPrimary};
width: 80px;
height: 80px;
text-align: center;
line-height: 80px;
vertical-align: middle;
margin-right: ${padding.base};
font-size: 32px;
align-items: center;
justify-content: center;
`;

export const Body = styled.div`
Expand Down
46 changes: 46 additions & 0 deletions src/react/ui-elements/ScrollbarWrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import styled, { css } from 'styled-components';

const ScrollbarWrapper = styled.div`
${props => {
const brand = props.theme.brand;
return css`
* {
// Chrome / Safari / Edge
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: ${brand.backgroundLevel1};
}
::-webkit-scrollbar-thumb {
width: 4px;
height: 4px;
background: ${brand.buttonSecondary};
border-radius: 4px;
-webkit-border-radius: 4px;
background-clip: padding-box;
border: 2px solid rgba(0, 0, 0, 0);
}
::-webkit-scrollbar-button {
width: 0;
height: 0;
display: none;
}
::-webkit-scrollbar-corner {
background-color: transparent;
}
// Firefox
scrollbar-color: ${brand.buttonSecondary} ${brand.backgroundLevel1};
scrollbar-width: thin;
}
`;
}}
`;

export default ScrollbarWrapper;
Loading

0 comments on commit 948db40

Please sign in to comment.