mirror of
https://github.com/yldio/copilot.git
synced 2024-11-28 14:10:04 +02:00
feat(joyent-ui-toolkit,joyent-cp-frontend): Quick actions show and hide
This commit is contained in:
parent
c3b0dac605
commit
cab7411454
@ -36,6 +36,7 @@
|
|||||||
"react-styled-flexboxgrid": "^1.1.2",
|
"react-styled-flexboxgrid": "^1.1.2",
|
||||||
"redux": "^3.6.0",
|
"redux": "^3.6.0",
|
||||||
"redux-actions": "^2.0.3",
|
"redux-actions": "^2.0.3",
|
||||||
|
"redux-batched-actions": "^0.2.0",
|
||||||
"redux-form": "^6.7.0",
|
"redux-form": "^6.7.0",
|
||||||
"remcalc": "^1.0.5",
|
"remcalc": "^1.0.5",
|
||||||
"reselect": "^3.0.1",
|
"reselect": "^3.0.1",
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export { default as EmptyServices } from './empty';
|
export { default as EmptyServices } from './empty';
|
||||||
export { default as ServiceListItem } from './list-item';
|
export { default as ServiceListItem } from './list-item';
|
||||||
export { default as ServicesTooltip } from './tooltip';
|
export { default as ServicesQuickActions } from './quick-actions';
|
||||||
|
@ -21,6 +21,12 @@ import {
|
|||||||
// InstancesMultipleIcon
|
// InstancesMultipleIcon
|
||||||
} from 'joyent-ui-toolkit';
|
} from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
|
import { ServicesQuickActions } from '@components/services';
|
||||||
|
|
||||||
|
const StyledCardHeader = styled(CardHeader)`
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
const TitleInnerContainer = styled.div`
|
const TitleInnerContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -29,7 +35,9 @@ const TitleInnerContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const ServiceListItem = ({
|
const ServiceListItem = ({
|
||||||
// OnQuickActions=() => {},
|
showQuickActions,
|
||||||
|
onQuickActionsClick = () => {},
|
||||||
|
onQuickActionsBlur = () => {},
|
||||||
deploymentGroup = '',
|
deploymentGroup = '',
|
||||||
service = {}
|
service = {}
|
||||||
}) => {
|
}) => {
|
||||||
@ -61,13 +69,17 @@ const ServiceListItem = ({
|
|||||||
|
|
||||||
const subtitle = <CardSubTitle>{service.instances} instances</CardSubTitle>;
|
const subtitle = <CardSubTitle>{service.instances} instances</CardSubTitle>;
|
||||||
|
|
||||||
const onOptionsClick = evt => {
|
const handleCardOptionsClick = evt => {
|
||||||
// OnQuickActions(evt, service.uuid);
|
onQuickActionsClick({ service });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleQuickActionsBlur = evt => {
|
||||||
|
onQuickActionsBlur({ show: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
const header = isChild
|
const header = isChild
|
||||||
? null
|
? null
|
||||||
: <CardHeader>
|
: <StyledCardHeader>
|
||||||
<CardMeta>
|
<CardMeta>
|
||||||
{title}
|
{title}
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
@ -82,8 +94,14 @@ const ServiceListItem = ({
|
|||||||
/> */}
|
/> */}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardMeta>
|
</CardMeta>
|
||||||
<CardOptions onClick={onOptionsClick} />
|
<CardOptions onClick={handleCardOptionsClick} />
|
||||||
</CardHeader>;
|
<ServicesQuickActions
|
||||||
|
position={{ top: '47px', right: '-98px' }}
|
||||||
|
service={service}
|
||||||
|
show={showQuickActions}
|
||||||
|
onBlur={handleQuickActionsBlur}
|
||||||
|
/>
|
||||||
|
</StyledCardHeader>;
|
||||||
|
|
||||||
const view = children
|
const view = children
|
||||||
? <CardGroupView>
|
? <CardGroupView>
|
||||||
@ -117,7 +135,9 @@ const ServiceListItem = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
ServiceListItem.propTypes = {
|
ServiceListItem.propTypes = {
|
||||||
// OnQuickActions: PropTypes.func,
|
showQuickActions: PropTypes.bool,
|
||||||
|
onQuickActionsClick: PropTypes.func,
|
||||||
|
onQuickActionsBlur: PropTypes.func,
|
||||||
deploymentGroup: PropTypes.string,
|
deploymentGroup: PropTypes.string,
|
||||||
service: PropTypes.object.isRequired // Define better
|
service: PropTypes.object.isRequired // Define better
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Tooltip, TooltipButton, TooltipDivider } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
|
const ServicesQuickActions = ({ show, position, service, onBlur }) => {
|
||||||
|
if (!show) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const p = Object.keys(position).reduce((p, key) => {
|
||||||
|
if (typeof position[key] === 'number') {
|
||||||
|
p[key] = `${position[key]}px`;
|
||||||
|
} else {
|
||||||
|
p[key] = position[key];
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip {...p} onBlur={onBlur}>
|
||||||
|
<TooltipButton onClick={() => {}}>Scale</TooltipButton>
|
||||||
|
<TooltipButton>Restart</TooltipButton>
|
||||||
|
<TooltipButton>Stop</TooltipButton>
|
||||||
|
<TooltipDivider />
|
||||||
|
<TooltipButton>Delete</TooltipButton>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ServicesQuickActions.propTypes = {
|
||||||
|
service: PropTypes.object,
|
||||||
|
position: PropTypes.object,
|
||||||
|
show: PropTypes.bool,
|
||||||
|
onBlur: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServicesQuickActions;
|
@ -1,41 +0,0 @@
|
|||||||
// Import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
// Import Tooltip, { TooltipButton, TooltipDivider } from 'joyent-ui-toolkit';
|
|
||||||
|
|
||||||
const ServicesTooltip = ({ show, position, data, ...rest }) => {
|
|
||||||
if (!show) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Return (
|
|
||||||
// <Tooltip {...position} {...rest}>
|
|
||||||
// <li>
|
|
||||||
// <TooltipButton>Scale</TooltipButton>
|
|
||||||
// </li>
|
|
||||||
// <li>
|
|
||||||
// <TooltipButton>Start</TooltipButton>
|
|
||||||
// </li>
|
|
||||||
// <li>
|
|
||||||
// <TooltipButton>Restart</TooltipButton>
|
|
||||||
// </li>
|
|
||||||
// <TooltipDivider />
|
|
||||||
// <li>
|
|
||||||
// <TooltipButton>Stop</TooltipButton>
|
|
||||||
// </li>
|
|
||||||
// <li>
|
|
||||||
// <TooltipButton>Delete</TooltipButton>
|
|
||||||
// </li>
|
|
||||||
// </Tooltip>
|
|
||||||
// );
|
|
||||||
};
|
|
||||||
|
|
||||||
ServicesTooltip.propTypes = {
|
|
||||||
data: PropTypes.object,
|
|
||||||
position: PropTypes.object,
|
|
||||||
show: PropTypes.bool
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ServicesTooltip;
|
|
@ -1,11 +1,11 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { compose, graphql } from 'react-apollo';
|
import { compose, graphql } from 'react-apollo';
|
||||||
// Import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
// Import { Link } from 'react-router-dom';
|
|
||||||
import ServicesQuery from '@graphql/Services.gql';
|
import ServicesQuery from '@graphql/Services.gql';
|
||||||
|
|
||||||
import { processServices } from '@root/state/selectors';
|
import { processServices } from '@root/state/selectors';
|
||||||
|
import { toggleServicesQuickActions } from '@root/state/actions';
|
||||||
|
|
||||||
import { LayoutContainer } from '@components/layout';
|
import { LayoutContainer } from '@components/layout';
|
||||||
import { Loader, ErrorMessage } from '@components/messaging';
|
import { Loader, ErrorMessage } from '@components/messaging';
|
||||||
@ -17,7 +17,14 @@ const StyledContainer = styled.div`
|
|||||||
|
|
||||||
class ServiceList extends Component {
|
class ServiceList extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { deploymentGroup, services, loading, error } = this.props;
|
const {
|
||||||
|
deploymentGroup,
|
||||||
|
services,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
servicesQuickActions,
|
||||||
|
toggleServicesQuickActions
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@ -33,13 +40,25 @@ class ServiceList extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleQuickActionsClick = o => {
|
||||||
|
toggleServicesQuickActions(o);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleQuickActionsBlur = o => {
|
||||||
|
toggleServicesQuickActions(o);
|
||||||
|
};
|
||||||
|
|
||||||
const serviceList = services.map(service => (
|
const serviceList = services.map(service => (
|
||||||
<ServiceListItem
|
<ServiceListItem
|
||||||
key={service.uuid}
|
key={service.uuid}
|
||||||
onQuickActions={null /* onQuickActions */}
|
|
||||||
deploymentGroup={deploymentGroup.slug}
|
deploymentGroup={deploymentGroup.slug}
|
||||||
service={service}
|
service={service}
|
||||||
uiTooltip={null /* uiTooltip */}
|
showQuickActions={
|
||||||
|
servicesQuickActions.service &&
|
||||||
|
servicesQuickActions.service.uuid === service.uuid
|
||||||
|
}
|
||||||
|
onQuickActionsClick={handleQuickActionsClick}
|
||||||
|
onQuickActionsBlur={handleQuickActionsBlur}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -57,6 +76,16 @@ class ServiceList extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
|
servicesQuickActions: state.ui.services.quickActions
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
toggleServicesQuickActions: data => dispatch(toggleServicesQuickActions(data))
|
||||||
|
});
|
||||||
|
|
||||||
|
const UiConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
const ServicesGql = graphql(ServicesQuery, {
|
const ServicesGql = graphql(ServicesQuery, {
|
||||||
options(props) {
|
options(props) {
|
||||||
return {
|
return {
|
||||||
@ -75,6 +104,6 @@ const ServicesGql = graphql(ServicesQuery, {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const ServiceListWithData = compose(ServicesGql)(ServiceList);
|
const ServiceListWithData = compose(ServicesGql, UiConnect)(ServiceList);
|
||||||
|
|
||||||
export default ServiceListWithData;
|
export default ServiceListWithData;
|
||||||
|
@ -1,31 +1,38 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { compose, graphql } from 'react-apollo';
|
import { compose, graphql } from 'react-apollo';
|
||||||
// Import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import ServicesQuery from '@graphql/ServicesTopology.gql';
|
import ServicesQuery from '@graphql/ServicesTopology.gql';
|
||||||
import unitcalc from 'unitcalc';
|
import unitcalc from 'unitcalc';
|
||||||
|
|
||||||
import { processServices } from '@root/state/selectors';
|
import { processServices } from '@root/state/selectors';
|
||||||
|
import { toggleServicesQuickActions } from '@root/state/actions';
|
||||||
|
|
||||||
import { LayoutContainer } from '@components/layout';
|
import { LayoutContainer } from '@components/layout';
|
||||||
import { Loader, ErrorMessage } from '@components/messaging';
|
import { Loader, ErrorMessage } from '@components/messaging';
|
||||||
// Import { ServicesTooltip } from '@components/services';
|
import { ServicesQuickActions } from '@components/services';
|
||||||
|
|
||||||
import { Topology } from 'joyent-ui-toolkit';
|
import { Topology } from 'joyent-ui-toolkit';
|
||||||
/* Import ServicesTooltip from '@components/services/tooltip';
|
|
||||||
|
|
||||||
import { toggleTooltip } from '@state/actions'; */
|
|
||||||
|
|
||||||
const StyledBackground = styled.div`
|
const StyledBackground = styled.div`
|
||||||
|
padding: ${unitcalc(4)};
|
||||||
background-color: ${props => props.theme.whiteActive};
|
background-color: ${props => props.theme.whiteActive};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: ${unitcalc(4)};
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ServicesTopology = ({ push, services, datacenter, loading, error }) => {
|
const ServicesTopology = ({
|
||||||
|
url,
|
||||||
|
push,
|
||||||
|
services,
|
||||||
|
datacenter,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
servicesQuickActions,
|
||||||
|
toggleServicesQuickActions
|
||||||
|
}) => {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
@ -40,15 +47,48 @@ const ServicesTopology = ({ push, services, datacenter, loading, error }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleQuickActionsClick = (evt, tooltipData) => {
|
||||||
|
toggleServicesQuickActions(tooltipData);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTooltipBlur = evt => {
|
||||||
|
toggleServicesQuickActions({ show: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNodeTitleClick = (evt, { service }) => {
|
||||||
|
push(`${url.split('/').slice(0, 3).join('/')}/services/${service.slug}`);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledBackground>
|
<StyledBackground>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<Topology services={services} />
|
<Topology
|
||||||
|
services={services}
|
||||||
|
onQuickActionsClick={handleQuickActionsClick}
|
||||||
|
onNodeTitleClick={handleNodeTitleClick}
|
||||||
|
/>
|
||||||
|
<ServicesQuickActions
|
||||||
|
show={servicesQuickActions.show}
|
||||||
|
position={servicesQuickActions.position}
|
||||||
|
onBlur={handleTooltipBlur}
|
||||||
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</StyledBackground>
|
</StyledBackground>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
|
servicesQuickActions: state.ui.services.quickActions,
|
||||||
|
url: ownProps.match.url,
|
||||||
|
push: ownProps.history.push
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
toggleServicesQuickActions: data => dispatch(toggleServicesQuickActions(data))
|
||||||
|
});
|
||||||
|
|
||||||
|
const UiConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
const ServicesGql = graphql(ServicesQuery, {
|
const ServicesGql = graphql(ServicesQuery, {
|
||||||
options(props) {
|
options(props) {
|
||||||
return {
|
return {
|
||||||
@ -66,6 +106,8 @@ const ServicesGql = graphql(ServicesQuery, {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const ServicesTopologyWithData = compose(ServicesGql)(ServicesTopology);
|
const ServicesTopologyWithData = compose(ServicesGql, UiConnect)(
|
||||||
|
ServicesTopology
|
||||||
|
);
|
||||||
|
|
||||||
export default ServicesTopologyWithData;
|
export default ServicesTopologyWithData;
|
||||||
|
@ -5,4 +5,6 @@ const APP = constantCase(process.env.APP_NAME);
|
|||||||
|
|
||||||
/** ***************************** UI ****************************** */
|
/** ***************************** UI ****************************** */
|
||||||
|
|
||||||
export const addMemberToProject = createAction(`${APP}/PROJECT_ADD_MEMBER`);
|
export const toggleServicesQuickActions = createAction(
|
||||||
|
`${APP}/TOGGLE_SERVICES_QUICK_ACTIONS`
|
||||||
|
);
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export { default as ui } from './ui';
|
36
packages/cp-frontend/src/state/reducers/ui.js
Normal file
36
packages/cp-frontend/src/state/reducers/ui.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { handleActions } from 'redux-actions';
|
||||||
|
import { toggleServicesQuickActions } from '@state/actions';
|
||||||
|
|
||||||
|
export default handleActions(
|
||||||
|
{
|
||||||
|
[toggleServicesQuickActions.toString()]: (state, action) => {
|
||||||
|
const { position, service, show } = action.payload;
|
||||||
|
|
||||||
|
const s = show === undefined
|
||||||
|
? !state.services.quickActions.service ||
|
||||||
|
service.uuid !== state.services.quickActions.service.uuid
|
||||||
|
: show;
|
||||||
|
|
||||||
|
const quickActions = s
|
||||||
|
? {
|
||||||
|
show: s,
|
||||||
|
position,
|
||||||
|
service
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
show: false
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
services: {
|
||||||
|
...state.services,
|
||||||
|
quickActions
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
@ -21,6 +21,11 @@ const state = {
|
|||||||
name: 'Instances'
|
name: 'Instances'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
services: {
|
||||||
|
quickActions: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
|
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
|
||||||
|
import { enableBatching } from 'redux-batched-actions';
|
||||||
import { ApolloClient, createNetworkInterface } from 'react-apollo';
|
import { ApolloClient, createNetworkInterface } from 'react-apollo';
|
||||||
import state from './state';
|
import state from './state';
|
||||||
|
import { ui } from './reducers';
|
||||||
|
|
||||||
export const client = new ApolloClient({
|
export const client = new ApolloClient({
|
||||||
dataIdFromObject: o => {
|
dataIdFromObject: o => {
|
||||||
@ -22,12 +24,10 @@ export const client = new ApolloClient({
|
|||||||
|
|
||||||
export const store = createStore(
|
export const store = createStore(
|
||||||
combineReducers({
|
combineReducers({
|
||||||
ui: s => {
|
ui,
|
||||||
return s ? s : state.ui;
|
|
||||||
},
|
|
||||||
apollo: client.reducer()
|
apollo: client.reducer()
|
||||||
}),
|
}),
|
||||||
{}, // Initial state
|
state, // Initial state
|
||||||
compose(
|
compose(
|
||||||
applyMiddleware(client.middleware()),
|
applyMiddleware(client.middleware()),
|
||||||
// If you are using the devToolsExtension, you can add it here also
|
// If you are using the devToolsExtension, you can add it here also
|
||||||
|
@ -12,7 +12,8 @@ export { default as Small } from './text/small';
|
|||||||
export { default as theme } from './theme';
|
export { default as theme } from './theme';
|
||||||
export { default as typography, fonts } from './typography';
|
export { default as typography, fonts } from './typography';
|
||||||
export { default as Topology } from './topology';
|
export { default as Topology } from './topology';
|
||||||
export { default as Tooltip } from './tooltip';
|
|
||||||
|
export { Tooltip, TooltipButton, TooltipDivider } from './tooltip';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
borderRadius,
|
borderRadius,
|
||||||
|
14
packages/ui-toolkit/src/modal/index.js
Normal file
14
packages/ui-toolkit/src/modal/index.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
class Modal extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Modal</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Modal;
|
@ -1,79 +1,3 @@
|
|||||||
import React from 'react';
|
export { default as Tooltip } from './tooltip';
|
||||||
import PropTypes from 'prop-types';
|
export { default as TooltipButton } from './button';
|
||||||
import styled from 'styled-components';
|
export { default as TooltipDivider } from './divider';
|
||||||
import unitcalc from 'unitcalc';
|
|
||||||
import remcalc from 'remcalc';
|
|
||||||
import theme from '../theme';
|
|
||||||
import { border, borderRadius, tooltipShadow } from '../boxes';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
position: absolute;
|
|
||||||
top: ${props => props.top};
|
|
||||||
left: ${props => props.left};
|
|
||||||
bottom: ${props => props.bottoms};
|
|
||||||
right: ${props => props.right};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledList = styled.ul`
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
top: ${remcalc(5)};
|
|
||||||
left: -50%;
|
|
||||||
margin: 0;
|
|
||||||
padding: ${unitcalc(2)} 0;
|
|
||||||
list-style-type: none;
|
|
||||||
background-color: ${theme.white};
|
|
||||||
border: ${border.unchecked};
|
|
||||||
drop-shadow: ${tooltipShadow};
|
|
||||||
border-radius: ${borderRadius};
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
&:after, &:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
bottom: 100%;
|
|
||||||
left: 50%;
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
border: solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
border-bottom-color: ${theme.white};
|
|
||||||
border-width: ${remcalc(3)};
|
|
||||||
margin-left: ${remcalc(-3)};
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
border-bottom-color: ${theme.grey};
|
|
||||||
border-width: ${remcalc(5)};
|
|
||||||
margin-left: ${remcalc(-5)};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @example ./usage.md
|
|
||||||
*/
|
|
||||||
const Tooltip = ({
|
|
||||||
children,
|
|
||||||
top = 'auto',
|
|
||||||
left = 'auto',
|
|
||||||
bottom = 'auto',
|
|
||||||
right = 'auto'
|
|
||||||
}) => (
|
|
||||||
<StyledContainer top={top} left={left} bottom={bottom} right={right}>
|
|
||||||
<StyledList>
|
|
||||||
{children}
|
|
||||||
</StyledList>
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
|
||||||
|
|
||||||
Tooltip.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
top: PropTypes.number,
|
|
||||||
left: PropTypes.number,
|
|
||||||
bottom: PropTypes.number,
|
|
||||||
right: PropTypes.number
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Tooltip;
|
|
||||||
|
113
packages/ui-toolkit/src/tooltip/tooltip.js
Normal file
113
packages/ui-toolkit/src/tooltip/tooltip.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import unitcalc from 'unitcalc';
|
||||||
|
import remcalc from 'remcalc';
|
||||||
|
import theme from '../theme';
|
||||||
|
import { border, borderRadius, tooltipShadow } from '../boxes';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
position: absolute;
|
||||||
|
top: ${props => props.top};
|
||||||
|
left: ${props => props.left};
|
||||||
|
bottom: ${props => props.bottoms};
|
||||||
|
right: ${props => props.right};
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledList = styled.ul`
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
top: ${remcalc(5)};
|
||||||
|
left: -50%;
|
||||||
|
margin: 0;
|
||||||
|
padding: ${unitcalc(2)} 0;
|
||||||
|
list-style-type: none;
|
||||||
|
background-color: ${theme.white};
|
||||||
|
border: ${border.unchecked};
|
||||||
|
box-shadow: ${tooltipShadow};
|
||||||
|
border-radius: ${borderRadius};
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&:after, &:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
border: solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
border-bottom-color: ${theme.white};
|
||||||
|
border-width: ${remcalc(3)};
|
||||||
|
margin-left: ${remcalc(-3)};
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
border-bottom-color: ${theme.grey};
|
||||||
|
border-width: ${remcalc(5)};
|
||||||
|
margin-left: ${remcalc(-5)};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @example ./usage.md
|
||||||
|
*/
|
||||||
|
class Tooltip extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.windowClickHandler = this.handleWindowClick.bind(this);
|
||||||
|
this.windowClickCounter = 0;
|
||||||
|
window.addEventListener('click', this.windowClickHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
this.windowClickCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener('click', this.windowClickHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleWindowClick(evt) {
|
||||||
|
if (this.windowClickCounter) {
|
||||||
|
if (this.props.onBlur) {
|
||||||
|
this.props.onBlur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.windowClickCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
children,
|
||||||
|
top = 'auto',
|
||||||
|
left = 'auto',
|
||||||
|
bottom = 'auto',
|
||||||
|
right = 'auto'
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledContainer top={top} left={left} bottom={bottom} right={right}>
|
||||||
|
<StyledList>
|
||||||
|
{children}
|
||||||
|
</StyledList>
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
top: PropTypes.string,
|
||||||
|
left: PropTypes.string,
|
||||||
|
bottom: PropTypes.string,
|
||||||
|
right: PropTypes.string,
|
||||||
|
onBlur: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tooltip;
|
@ -1,14 +1,14 @@
|
|||||||
```
|
```
|
||||||
const Tooltip = require('./index').default;
|
const Tooltip = require('./tooltip').default;
|
||||||
const TooltipButton = require('./button').default;
|
const TooltipButton = require('./button').default;
|
||||||
const TooltipDivider = require('./divider').default;
|
const TooltipDivider = require('./divider').default;
|
||||||
|
|
||||||
<div style={{ position: 'relative', height: '175px' }}>
|
<div style={{ position: 'relative', height: '175px' }}>
|
||||||
<Tooltip top='5px' left='60px'>
|
<Tooltip top='5px' left='55px'>
|
||||||
<TooltipButton>Scale</TooltipButton>
|
<TooltipButton>Scale</TooltipButton>
|
||||||
<TooltipButton>Restart</TooltipButton>
|
<TooltipButton>Restart</TooltipButton>
|
||||||
<TooltipDivider />
|
|
||||||
<TooltipButton>Stop</TooltipButton>
|
<TooltipButton>Stop</TooltipButton>
|
||||||
|
<TooltipDivider />
|
||||||
<TooltipButton>Delete</TooltipButton>
|
<TooltipButton>Delete</TooltipButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
@ -119,7 +119,7 @@ class Topology extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { onQuickActions, services } = this.props;
|
const { onQuickActionsClick, onNodeTitleClick, services } = this.props;
|
||||||
|
|
||||||
const { nodes, links } = this.state;
|
const { nodes, links } = this.state;
|
||||||
|
|
||||||
@ -197,17 +197,14 @@ class Topology extends React.Component {
|
|||||||
this.setDragInfo(false);
|
this.setDragInfo(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onTitleClick = serviceUUID =>
|
|
||||||
this.props.onNodeTitleClick(serviceUUID);
|
|
||||||
|
|
||||||
const renderedNode = (n, index) => (
|
const renderedNode = (n, index) => (
|
||||||
<TopologyNode
|
<TopologyNode
|
||||||
key={index}
|
key={index}
|
||||||
data={n}
|
data={n}
|
||||||
index={index}
|
index={index}
|
||||||
onDragStart={onDragStart}
|
onDragStart={onDragStart}
|
||||||
onNodeTitleClick={onTitleClick}
|
onNodeTitleClick={onNodeTitleClick}
|
||||||
onQuickActions={onQuickActions}
|
onQuickActions={onQuickActionsClick}
|
||||||
connected={n.id !== 'consul'}
|
connected={n.id !== 'consul'}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -288,7 +285,7 @@ class Topology extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Topology.propTypes = {
|
Topology.propTypes = {
|
||||||
onQuickActions: PropTypes.func,
|
onQuickActionsClick: PropTypes.func,
|
||||||
onNodeTitleClick: PropTypes.func,
|
onNodeTitleClick: PropTypes.func,
|
||||||
services: PropTypes.array
|
services: PropTypes.array
|
||||||
};
|
};
|
||||||
|
@ -27,6 +27,7 @@ const NodeButton = ({ connected, onButtonClick, index }) => {
|
|||||||
return (
|
return (
|
||||||
<g transform={`translate(${x}, ${y})`}>
|
<g transform={`translate(${x}, ${y})`}>
|
||||||
<GraphLine x1={0} y1={0} x2={0} y2={height} connected={connected} />
|
<GraphLine x1={0} y1={0} x2={0} y2={height} connected={connected} />
|
||||||
|
{buttonCircles}
|
||||||
<GraphButtonRect
|
<GraphButtonRect
|
||||||
height={height}
|
height={height}
|
||||||
onClick={onButtonClick}
|
onClick={onButtonClick}
|
||||||
@ -35,7 +36,6 @@ const NodeButton = ({ connected, onButtonClick, index }) => {
|
|||||||
role="button"
|
role="button"
|
||||||
tabIndex={100 + index}
|
tabIndex={100 + index}
|
||||||
/>
|
/>
|
||||||
{buttonCircles}
|
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -42,7 +42,7 @@ const GraphNode = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const d = {
|
const d = {
|
||||||
service: data.uuid,
|
service: data,
|
||||||
position: {
|
position: {
|
||||||
left: tooltipPosition.x,
|
left: tooltipPosition.x,
|
||||||
top: tooltipPosition.y
|
top: tooltipPosition.y
|
||||||
@ -52,7 +52,7 @@ const GraphNode = ({
|
|||||||
onQuickActions(evt, d);
|
onQuickActions(evt, d);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onTitleClick = () => onNodeTitleClick(data.uuid);
|
const onTitleClick = evt => onNodeTitleClick(evt, { service: data });
|
||||||
|
|
||||||
const onStart = evt => {
|
const onStart = evt => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
@ -77,6 +77,10 @@ export const GraphText = styled.text`
|
|||||||
export const GraphButtonRect = styled.rect`
|
export const GraphButtonRect = styled.rect`
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const GraphButtonCircle = styled.circle`
|
export const GraphButtonCircle = styled.circle`
|
||||||
|
@ -63,7 +63,7 @@ module.exports = {
|
|||||||
'src/list/ul.js',
|
'src/list/ul.js',
|
||||||
'src/list/li.js',
|
'src/list/li.js',
|
||||||
'src/topology/index.js',
|
'src/topology/index.js',
|
||||||
'src/tooltip/index.js'
|
'src/tooltip/tooltip.js'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -68,6 +68,8 @@ const staged = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('existing = ', existing);
|
||||||
|
|
||||||
return run(existing);
|
return run(existing);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user