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

[KED-2872] Create global toolbar UI #576

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
25,266 changes: 9,256 additions & 16,010 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,4 @@
"not op_mini all"
],
"snyk": true
}
}
2 changes: 2 additions & 0 deletions src/components/app/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
--color-bg-3: #{$color-bg-light-3};
--color-bg-alt: #{$color-bg-light-alt};
--color-sidebar-background: #{$color-bg-light-3};
--color-global-toolbar-background: #{$color-bg-light-2};
--color-sidebar-border: rgba(0, 0, 0, 0.05);
--color-sidebar-shadow: rgba(0, 0, 0, 0.07);
}
Expand All @@ -24,6 +25,7 @@
--color-bg-3: #{$color-bg-dark-2};
--color-bg-alt: #{$color-light};
--color-sidebar-background: #{$color-bg-dark-2};
--color-global-toolbar-background: #{$color-bg-dark-1};
--color-sidebar-border: rgba(0, 0, 0, 0.2);
--color-sidebar-shadow: rgba(0, 0, 0, 0.3);
}
2 changes: 0 additions & 2 deletions src/components/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,7 @@ App.propTypes = {
labelBtn: PropTypes.bool,
layerBtn: PropTypes.bool,
exportBtn: PropTypes.bool,
settingsBtn: PropTypes.bool,
sidebar: PropTypes.bool,
themeBtn: PropTypes.bool,
}),
};

Expand Down
1 change: 0 additions & 1 deletion src/components/export-modal/export-modal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ describe('ExportModal', () => {
theme: expect.stringMatching(/light|dark/),
visible: expect.objectContaining({
exportBtn: expect.any(Boolean),
settingsBtn: expect.any(Boolean),
exportModal: expect.any(Boolean),
settingsModal: expect.any(Boolean),
}),
Expand Down
3 changes: 2 additions & 1 deletion src/components/flowchart/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { interpolatePath } from 'd3-interpolate-path';
import { select } from 'd3-selection';
import { curveBasis, line } from 'd3-shape';
import { paths as nodeIcons } from '../icons/node-icon';
import { globalToolbarWidth } from '../../config';

const lineShape = line()
.x((d) => d.x)
Expand Down Expand Up @@ -62,7 +63,7 @@ export const drawLayerNames = function () {
this.el.layerNameGroup
.transition('layer-names-sidebar-width')
.duration(this.DURATION)
.style('transform', `translateX(${sidebarWidth}px)`);
.style('transform', `translateX(${sidebarWidth + globalToolbarWidth}px)`);

this.el.layerNames = this.el.layerNameGroup
.selectAll('.pipeline-layer-name')
Expand Down
45 changes: 45 additions & 0 deletions src/components/global-toolbar/global-toolbar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@import '../../styles/variables';
@import '../../styles/extends';

.pipeline-global-toolbar {
background: var(--color-global-toolbar-background);
display: flex;
flex-direction: column;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: $global-toolbar-width;
z-index: 5;
}

.pipeline-global-routes-toolbar {
@extend %listReset;
}

.pipeline-global-control-toolbar {
@extend %listReset;

margin-top: auto;
}

.pipeline-menu-button--large {
height: $global-toolbar-width;
width: $global-toolbar-width;
}

.pipeline-menu-button--link {
&:hover {
background-color: var(--color-bg-2);
}
}

.pipeline-menu-button--logo {
margin-bottom: 40px;

svg {
height: 2.9em;
opacity: 1;
width: 2.9em;
}
}
71 changes: 71 additions & 0 deletions src/components/global-toolbar/global-toolbar.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import ConnectedGlobalToolbar, {
GlobalToolbar,
mapStateToProps,
mapDispatchToProps,
} from './index';
import { mockState, setup } from '../../utils/state.mock';

describe('GlobalToolbar', () => {
it('renders without crashing', () => {
const wrapper = setup.mount(<ConnectedGlobalToolbar />);
expect(wrapper.find('.pipeline-icon-toolbar__button').length).toBe(5);
});

const functionCalls = [
['.pipeline-menu-button--theme', 'onToggleTheme'],
['.pipeline-menu-button--settings', 'onToggleSettingsModal'],
];

test.each(functionCalls)(
'calls %s function on %s button click',
(selector, callback) => {
const mockFn = jest.fn();
const props = {
theme: mockState.animals.theme,
visible: mockState.animals.visible,
[callback]: mockFn,
};
const wrapper = setup.mount(<GlobalToolbar {...props} />);
expect(mockFn.mock.calls.length).toBe(0);
wrapper.find(selector).find('button').simulate('click');
expect(mockFn.mock.calls.length).toBe(1);
}
);

it('maps state to props', () => {
const expectedResult = {
theme: expect.stringMatching(/light|dark/),
visible: expect.objectContaining({
exportBtn: expect.any(Boolean),
exportModal: expect.any(Boolean),
plotModal: expect.any(Boolean),
settingsModal: expect.any(Boolean),
labelBtn: expect.any(Boolean),
layerBtn: expect.any(Boolean),
sidebar: expect.any(Boolean),
}),
};
expect(mapStateToProps(mockState.animals)).toEqual(expectedResult);
});

describe('mapDispatchToProps', () => {
it('onToggleTheme', () => {
const dispatch = jest.fn();
mapDispatchToProps(dispatch).onToggleTheme('light');
expect(dispatch.mock.calls[0][0]).toEqual({
theme: 'light',
type: 'TOGGLE_THEME',
});
});

it('onToggleSettingsModal', () => {
const dispatch = jest.fn();
mapDispatchToProps(dispatch).onToggleSettingsModal(true);
expect(dispatch.mock.calls[0][0]).toEqual({
visible: true,
type: 'TOGGLE_SETTINGS_MODAL',
});
});
});
});
90 changes: 90 additions & 0 deletions src/components/global-toolbar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import { connect } from 'react-redux';
import { toggleSettingsModal, toggleTheme } from '../../actions';
import ExperimentsIcon from '../icons/experiments';
import IconButton from '../icon-button';
import LogoIcon from '../icons/logo';
import SettingsIcon from '../icons/settings';
import ThemeIcon from '../icons/theme';
import TreeIcon from '../icons/tree';

import './global-toolbar.css';

/**
* Main controls for filtering the chart data
* @param {Function} onToggleTheme Handle toggling theme between light/dark
* @param {string} theme Kedro UI light/dark theme
*/
export const GlobalToolbar = ({
onToggleSettingsModal,
onToggleTheme,
theme,
visible,
}) => {
return (
<>
<div className="pipeline-global-toolbar">
<ul className="pipeline-global-routes-toolbar kedro">
<IconButton
ariaLabel={'Kedro Viz logo and link'}
className={'pipeline-menu-button--logo pipeline-menu-button--large'}
disabled={false}
icon={LogoIcon}
/>
<IconButton
ariaLabel={'View your pipeline'}
className={'pipeline-menu-button--large pipeline-menu-button--link'}
disabled={false}
icon={TreeIcon}
/>
<IconButton
ariaLabel={'View your experiments'}
className={'pipeline-menu-button--large pipeline-menu-button--link'}
disabled={false}
icon={ExperimentsIcon}
/>
</ul>
<ul className="pipeline-global-control-toolbar kedro">
<IconButton
ariaLive="polite"
ariaLabel={`Change to ${
theme === 'light' ? 'dark' : 'light'
} theme`}
className={
'pipeline-menu-button--theme pipeline-menu-button--large'
}
onClick={() => onToggleTheme(theme === 'light' ? 'dark' : 'light')}
icon={ThemeIcon}
labelText="Toggle theme"
/>
<IconButton
ariaLabel={'Change the settings flags'}
className={
'pipeline-menu-button--settings pipeline-menu-button--large'
}
onClick={() => onToggleSettingsModal(true)}
icon={SettingsIcon}
disabled={false}
labelText={'Settings'}
/>
</ul>
</div>
</>
);
};

export const mapStateToProps = (state) => ({
theme: state.theme,
visible: state.visible,
});

export const mapDispatchToProps = (dispatch) => ({
onToggleSettingsModal: (value) => {
dispatch(toggleSettingsModal(value));
},
onToggleTheme: (value) => {
dispatch(toggleTheme(value));
},
});

export default connect(mapStateToProps, mapDispatchToProps)(GlobalToolbar);
4 changes: 2 additions & 2 deletions src/components/icon-button/icon-button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
}

svg {
width: 1.8em;
height: 1.8em;
width: 2.175em;
height: 2.175em;
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/components/icons/experiments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

const ExperimentsIcon = ({ className }) => (
<svg className={className} viewBox="0 0 24 24">
<path d="M13 10V6h-2v4l-.766 2-.83 1.66 4.571-1.225-.218-.435L13 10zm1.889 4.261-6.68 1.79L7.235 18h9.526l-1.872-3.739zM20 20H4l4.999-10H9V6H8V4h8v2h-1v4h-.007L20 20z" />
</svg>
);

export default ExperimentsIcon;
15 changes: 15 additions & 0 deletions src/components/icons/logo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

const LogoIcon = ({ className }) => (
<svg className={className} viewBox="24 25 32 30">
<path
d="M40 25.414 54.586 40 40 54.586 25.414 40 40 25.414z"
fill="none"
fillRule="evenodd"
stroke="#FFBC00"
strokeWidth="2"
/>
</svg>
);

export default LogoIcon;
2 changes: 1 addition & 1 deletion src/components/icons/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

const MenuIcon = ({ className }) => (
<svg className={className} viewBox="0 0 24 24">
<path d="M15.3 3.3l1.4 1.4L9.4 12l7.3 7.3-1.4 1.4L6.6 12z" />
<path d="M10.667 5 12 6.4 6.667 12 12 17.6 10.667 19 4 12l6.667-7zm8 0L20 6.4 14.667 12 20 17.6 18.667 19 12 12l6.667-7z" />
</svg>
);

Expand Down
9 changes: 9 additions & 0 deletions src/components/icons/tree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

const TreeIcon = ({ className }) => (
<svg className={className} viewBox="0 0 24 24">
<path d="M12 2a3 3 0 0 1 2.16 5.082l4.47 8.94a3 3 0 1 1-1.79.895l-4.469-8.94a3.03 3.03 0 0 1-.742 0l-4.47 8.94a3 3 0 1 1-1.789-.895l4.47-8.94A3 3 0 0 1 12 2z" />
</svg>
);

export default TreeIcon;
15 changes: 7 additions & 8 deletions src/components/minimap-toolbar/minimap-toolbar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@
}

.pipeline-minimap-toolbar {
display: block;
@extend %listReset;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice one!


margin-top: auto;
padding: 0;
list-style: none;
}

.pipeline-minimap-button {
height: $sidebar-width-closed - 14;
transition: background-color 300ms ease;
}

Expand All @@ -30,11 +28,12 @@
}

.pipeline-minimap-toolbar__scale {
display: block;
width: 100%;
padding: 6px 8px 6px;
color: var(--color-text);
display: block;
font-size: 12px;
font-weight: bold;
font-size: 10px;
margin-top: 16px;
padding: 6px 8px 6px;
text-align: center;
width: 100%;
}
Loading