mirror of
https://github.com/yldio/copilot.git
synced 2024-12-01 07:30:07 +02:00
Add instances list
This commit is contained in:
parent
db4ac69452
commit
a8c34ee756
13
frontend/src/components/instances/empty.js
Normal file
13
frontend/src/components/instances/empty.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Column from '@ui/components/column';
|
||||||
|
import Row from '@ui/components/row';
|
||||||
|
import { P } from '@ui/components/base-elements';
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<Row>
|
||||||
|
<Column xs={12}>
|
||||||
|
<P>You don't have any instances</P>
|
||||||
|
</Column>
|
||||||
|
</Row>
|
||||||
|
);
|
2
frontend/src/components/instances/index.js
Normal file
2
frontend/src/components/instances/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export { default as EmptyInstances } from './empty';
|
||||||
|
export { default as InstanceListItem } from './list-item';
|
33
frontend/src/components/instances/list-item.js
Normal file
33
frontend/src/components/instances/list-item.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ListItem,
|
||||||
|
ListItemView,
|
||||||
|
ListItemMeta,
|
||||||
|
ListItemTitle,
|
||||||
|
ListItemOptions
|
||||||
|
} from '@ui/components/list';
|
||||||
|
|
||||||
|
const InstanceListItem = ({
|
||||||
|
instance = {},
|
||||||
|
onOptionsClick = () => null,
|
||||||
|
toggleCollapsed = () => null
|
||||||
|
}) => (
|
||||||
|
<ListItem collapsed={true} key={instance.uuid} >
|
||||||
|
<ListItemView>
|
||||||
|
<ListItemMeta onClick={toggleCollapsed}>
|
||||||
|
<ListItemTitle>{instance.name}</ListItemTitle>
|
||||||
|
</ListItemMeta>
|
||||||
|
</ListItemView>
|
||||||
|
<ListItemOptions onClick={onOptionsClick} />
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
|
||||||
|
InstanceListItem.propTypes = {
|
||||||
|
instance: PropTypes.object,
|
||||||
|
onOptionsClick: React.PropTypes.func,
|
||||||
|
toggleCollapsed: React.PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InstanceListItem;
|
@ -39,20 +39,11 @@ function getBreadcrumbLinks(links) {
|
|||||||
<BreadcrumbSpan key={breadcrumb.length}> / </BreadcrumbSpan>
|
<BreadcrumbSpan key={breadcrumb.length}> / </BreadcrumbSpan>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(index < links.length - 1) {
|
|
||||||
breadcrumb.push(
|
breadcrumb.push(
|
||||||
<BreadcrumbLink key={breadcrumb.length} to={link.pathname}>
|
<BreadcrumbLink key={breadcrumb.length} to={link.pathname}>
|
||||||
{link.name}
|
{link.name}
|
||||||
</BreadcrumbLink>
|
</BreadcrumbLink>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
else {
|
|
||||||
breadcrumb.push(
|
|
||||||
<span key={breadcrumb.length}>
|
|
||||||
{link.name}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return breadcrumb;
|
return breadcrumb;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import styled from 'styled-components';
|
|||||||
|
|
||||||
// import ItemMetricGroup from '@components/item-metric-group';
|
// import ItemMetricGroup from '@components/item-metric-group';
|
||||||
import { Link } from '@ui/components/anchor';
|
import { Link } from '@ui/components/anchor';
|
||||||
import { Checkbox, FormGroup } from '@ui/components/form';
|
|
||||||
import {
|
import {
|
||||||
DataCentersIcon,
|
DataCentersIcon,
|
||||||
HealthyIcon,
|
HealthyIcon,
|
||||||
@ -25,10 +24,6 @@ import {
|
|||||||
ListItemInfo
|
ListItemInfo
|
||||||
} from '@ui/components/list';
|
} from '@ui/components/list';
|
||||||
|
|
||||||
const StyledFormGroup = styled(FormGroup)`
|
|
||||||
width: auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TitleInnerContainer = styled.div`
|
const TitleInnerContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -52,7 +47,7 @@ const ServiceListItem = ({
|
|||||||
/>
|
/>
|
||||||
)) : null;
|
)) : null;
|
||||||
|
|
||||||
const to = `/deploymentGroups/${deploymentGroup}/services/${service.id}`;
|
const to = `/deployment-groups/${deploymentGroup}/services/${service.slug}`;
|
||||||
|
|
||||||
const title = service.parent ? (
|
const title = service.parent ? (
|
||||||
<ListItemTitle>
|
<ListItemTitle>
|
||||||
@ -61,9 +56,6 @@ const ServiceListItem = ({
|
|||||||
) : (
|
) : (
|
||||||
<ListItemTitle>
|
<ListItemTitle>
|
||||||
<TitleInnerContainer>
|
<TitleInnerContainer>
|
||||||
<StyledFormGroup>
|
|
||||||
<Checkbox />
|
|
||||||
</StyledFormGroup>
|
|
||||||
<Link secondary to={to}>
|
<Link secondary to={to}>
|
||||||
{service.name}
|
{service.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { graphql } from 'react-apollo';
|
import PropTypes from 'prop-types';
|
||||||
|
import { compose, graphql } from 'react-apollo';
|
||||||
|
import PortalQuery from '@graphql/Portal.gql';
|
||||||
import InstancesQuery from '@graphql/Instances.gql';
|
import InstancesQuery from '@graphql/Instances.gql';
|
||||||
|
|
||||||
|
import { LayoutContainer } from '@components/layout';
|
||||||
|
import { Loader, ErrorMessage } from '@components/messaging';
|
||||||
|
import { InstanceListItem, EmptyInstances } from '@components/instances';
|
||||||
|
|
||||||
class InstanceList extends Component {
|
class InstanceList extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -11,29 +17,58 @@ class InstanceList extends Component {
|
|||||||
loading,
|
loading,
|
||||||
error
|
error
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
console.log('instances = ', instances);
|
||||||
|
console.log('loading = ', loading);
|
||||||
|
console.log('error = ', error);
|
||||||
|
if(loading) {
|
||||||
|
return (
|
||||||
|
<LayoutContainer>
|
||||||
|
<Loader />
|
||||||
|
</LayoutContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else if(error) {
|
||||||
|
return (
|
||||||
|
<LayoutContainer>
|
||||||
|
<ErrorMessage
|
||||||
|
message='Oops, and error occured while loading your instances.'
|
||||||
|
/>
|
||||||
|
</LayoutContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const instanceList =
|
const instanceList = instances ? instances.map((instance, index) => (
|
||||||
loading ? <p>Loading...</p> :
|
<InstanceListItem
|
||||||
error ? <p>Error!!!</p> :
|
instance={instance}
|
||||||
instances.map((instance, index) =>
|
key={instance.uuid}
|
||||||
<p key={index}>{instance.name}</p>);
|
toggleCollapsed={() => null}
|
||||||
|
/>
|
||||||
|
)) : (
|
||||||
|
<EmptyInstances />
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<LayoutContainer>
|
||||||
<div>
|
<div>
|
||||||
<h2>Instance List</h2>
|
<h2>Instance List</h2>
|
||||||
</div>
|
</div>
|
||||||
{ instanceList }
|
{ instanceList }
|
||||||
</div>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InstanceListWithData = graphql(InstancesQuery, {
|
const PortalGql = graphql(PortalQuery, {});
|
||||||
|
|
||||||
|
const InstanceListGql = graphql(InstancesQuery, {
|
||||||
options(props) {
|
options(props) {
|
||||||
|
const params = props.match.params;
|
||||||
|
const deploymentGroupSlug = params.deploymentGroup;
|
||||||
|
const serviceSlug = params.service;
|
||||||
return {
|
return {
|
||||||
variables: {
|
variables: {
|
||||||
deploymentGroupSlug: props.match.params.deploymentGroup
|
deploymentGroupSlug,
|
||||||
|
serviceSlug
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -44,6 +79,11 @@ const InstanceListWithData = graphql(InstancesQuery, {
|
|||||||
loading,
|
loading,
|
||||||
error
|
error
|
||||||
})
|
})
|
||||||
})(InstanceList)
|
});
|
||||||
|
|
||||||
|
const InstanceListWithData = compose(
|
||||||
|
PortalGql,
|
||||||
|
InstanceListGql
|
||||||
|
)(InstanceList);
|
||||||
|
|
||||||
export default InstanceListWithData;
|
export default InstanceListWithData;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Breadcrumb as BreadcrumbComponent } from '@components/navigation';
|
import { Breadcrumb as BreadcrumbComponent } from '@components/navigation';
|
||||||
|
import { deploymentGroupBySlugSelector, serviceBySlugSelector} from '@root/state/selectors';
|
||||||
|
|
||||||
const Breadcrumb = ({
|
const Breadcrumb = ({
|
||||||
deploymentGroup,
|
deploymentGroup,
|
||||||
@ -36,32 +37,12 @@ const Breadcrumb = ({
|
|||||||
|
|
||||||
const ConnectedBreadcrumb = connect(
|
const ConnectedBreadcrumb = connect(
|
||||||
(state, ownProps) => {
|
(state, ownProps) => {
|
||||||
|
|
||||||
const params = ownProps.match.params;
|
const params = ownProps.match.params;
|
||||||
const deploymentGroupSlug = params.deploymentGroup;
|
const deploymentGroupSlug = params.deploymentGroup;
|
||||||
const serviceSlug = params.service;
|
const serviceSlug = params.service;
|
||||||
const apolloData = state.apollo.data;
|
|
||||||
const keys = Object.keys(apolloData);
|
|
||||||
|
|
||||||
let deploymentGroup, service;
|
|
||||||
if(keys.length) {
|
|
||||||
// These should be selectors
|
|
||||||
if(deploymentGroupSlug) {
|
|
||||||
deploymentGroup = keys.reduce((dg, k) =>
|
|
||||||
apolloData[k].__typename === 'DeploymentGroup' &&
|
|
||||||
apolloData[k].slug === deploymentGroupSlug ?
|
|
||||||
apolloData[k] : dg, {});
|
|
||||||
if(serviceSlug) {
|
|
||||||
service = keys.reduce((s, k) =>
|
|
||||||
apolloData[k].__typename === 'Service' &&
|
|
||||||
apolloData[k].slug === serviceSlug ?
|
|
||||||
apolloData[k] : s, {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
deploymentGroup,
|
deploymentGroup: deploymentGroupBySlugSelector(deploymentGroupSlug)(state),
|
||||||
service,
|
service: serviceBySlugSelector(serviceSlug)(state),
|
||||||
location: ownProps.location
|
location: ownProps.location
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -9,6 +9,7 @@ import ServicesQuery from '@graphql/Services.gql';
|
|||||||
import { processServices } from '@root/state/selectors';
|
import { processServices } from '@root/state/selectors';
|
||||||
|
|
||||||
import { LayoutContainer } from '@components/layout';
|
import { LayoutContainer } from '@components/layout';
|
||||||
|
import { Loader, ErrorMessage } from '@components/messaging';
|
||||||
import { ServiceListItem } from '@components/services';
|
import { ServiceListItem } from '@components/services';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -27,12 +28,21 @@ class ServiceList extends Component {
|
|||||||
error
|
error
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
console.log('services = ', services);
|
if(loading) {
|
||||||
|
|
||||||
if(loading || error) {
|
|
||||||
return (
|
return (
|
||||||
<p>Loading OR error</p>
|
<LayoutContainer>
|
||||||
);
|
<Loader />
|
||||||
|
</LayoutContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else if(error) {
|
||||||
|
return (
|
||||||
|
<LayoutContainer>
|
||||||
|
<ErrorMessage
|
||||||
|
message='Oops, and error occured while loading your services.'
|
||||||
|
/>
|
||||||
|
</LayoutContainer>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceList = services.map((service) => (
|
const serviceList = services.map((service) => (
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#import "./DeploymentGroupInfo.gql"
|
#import "./DeploymentGroupInfo.gql"
|
||||||
#import "./ServiceInfo.gql"
|
#import "./ServiceInfo.gql"
|
||||||
|
|
||||||
query Instances($deploymentGroupSlug: String!) {
|
query Instances($deploymentGroupSlug: String!, $serviceSlug: String) {
|
||||||
deploymentGroup(slug: $deploymentGroupSlug) {
|
deploymentGroup(slug: $deploymentGroupSlug) {
|
||||||
...DeploymentGroupInfo
|
...DeploymentGroupInfo
|
||||||
services {
|
services(slug: $serviceSlug) {
|
||||||
...ServiceInfo
|
...ServiceInfo
|
||||||
instances {
|
instances {
|
||||||
uuid
|
uuid
|
||||||
|
@ -22,6 +22,10 @@ const deploymentGroupRedirect = (p) => (
|
|||||||
<Redirect to={`/deployment-groups/${p.match.params.deploymentGroup}/services-list`} />
|
<Redirect to={`/deployment-groups/${p.match.params.deploymentGroup}/services-list`} />
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const serviceRedirect = (p) => (
|
||||||
|
<Redirect to={`/deployment-groups/${p.match.params.deploymentGroup}/services/${p.match.params.service}/instances`} />
|
||||||
|
);
|
||||||
|
|
||||||
const Router = (
|
const Router = (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<div>
|
<div>
|
||||||
@ -51,6 +55,7 @@ const Router = (
|
|||||||
<Route path='/deployment-groups/:deploymentGroup/services-topology' exact component={ServicesMenu} />
|
<Route path='/deployment-groups/:deploymentGroup/services-topology' exact component={ServicesMenu} />
|
||||||
<Route path='/deployment-groups/:deploymentGroup/services-topology' exact component={ServicesTopology} />
|
<Route path='/deployment-groups/:deploymentGroup/services-topology' exact component={ServicesTopology} />
|
||||||
|
|
||||||
|
<Route path='/deployment-groups/:deploymentGroup/services/:service' exact component={serviceRedirect} />
|
||||||
<Route path='/deployment-groups/:deploymentGroup/services/:service/instances' exact component={InstanceList} />
|
<Route path='/deployment-groups/:deploymentGroup/services/:service/instances' exact component={InstanceList} />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,18 +6,20 @@ const apollo = (state) => state.apollo;
|
|||||||
|
|
||||||
const deploymentGroupBySlug = (deploymentGroupSlug) => createSelector(
|
const deploymentGroupBySlug = (deploymentGroupSlug) => createSelector(
|
||||||
[apollo],
|
[apollo],
|
||||||
(apollo) => apollo ? Object.keys(apollo).reduce((dg, k) =>
|
(apollo) => apollo && apollo.data ?
|
||||||
apollo[k].__typename === 'DeploymentGroup' &&
|
Object.keys(apollo.data).reduce((dg, k) =>
|
||||||
apollo[k].slug === deploymentGroupSlug ?
|
apollo.data[k].__typename === 'DeploymentGroup' &&
|
||||||
apollo[k] : dg, {}) : null
|
apollo.data[k].slug === deploymentGroupSlug ?
|
||||||
|
apollo.data[k] : dg, null) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
const servicesBySlug = (serviceSlug) => createSelector(
|
const serviceBySlug = (serviceSlug) => createSelector(
|
||||||
[apollo],
|
[apollo],
|
||||||
(apollo) => apollo ? Object.keys(apollo).reduce((s, k) =>
|
(apollo) => apollo && apollo.data ?
|
||||||
apollo[k].__typename === 'Service' &&
|
Object.keys(apollo.data).reduce((s, k) =>
|
||||||
apollo[k].slug === serviceSlug ?
|
apollo.data[k].__typename === 'Service' &&
|
||||||
apollo[k] : s, {}) : null
|
apollo.data[k].slug === serviceSlug ?
|
||||||
|
apollo.data[k] : s, null) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
// apollo gql utils //
|
// apollo gql utils //
|
||||||
@ -64,6 +66,6 @@ const processServices = (services, datacenter) => {
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
deploymentGroupBySlug as deploymentGroupBySlugSelector,
|
deploymentGroupBySlug as deploymentGroupBySlugSelector,
|
||||||
servicesBySlug as servicesBySlugSelector,
|
serviceBySlug as serviceBySlugSelector,
|
||||||
processServices as processServices
|
processServices as processServices
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { find, filter } from 'lodash';
|
|||||||
import data from './mock-data';
|
import data from './mock-data';
|
||||||
import { normalMetricData, leakMetricData } from './mock-data/metrics';
|
import { normalMetricData, leakMetricData } from './mock-data/metrics';
|
||||||
|
|
||||||
|
// TMP / Util
|
||||||
const datacenter = {
|
const datacenter = {
|
||||||
uuid: 'datacenter-uuid',
|
uuid: 'datacenter-uuid',
|
||||||
region: 'us-east-1'
|
region: 'us-east-1'
|
||||||
@ -26,8 +27,9 @@ const getInstanceMetricData = (dataset, type) => {
|
|||||||
|
|
||||||
const tick = setInterval(() => index++, 15*1000);
|
const tick = setInterval(() => index++, 15*1000);
|
||||||
|
|
||||||
const resolveFunctions = {
|
// GraphQL
|
||||||
Query: {
|
|
||||||
|
const queries = {
|
||||||
portal() {
|
portal() {
|
||||||
return portal;
|
return portal;
|
||||||
},
|
},
|
||||||
@ -87,6 +89,9 @@ const resolveFunctions = {
|
|||||||
if(deploymentGroupSlug) {
|
if(deploymentGroupSlug) {
|
||||||
const deploymentGroup = find(deploymentGroups, { slug: deploymentGroupSlug });
|
const deploymentGroup = find(deploymentGroups, { slug: deploymentGroupSlug });
|
||||||
if(deploymentGroup) {
|
if(deploymentGroup) {
|
||||||
|
if(slug) {
|
||||||
|
return filter(services, { project: deploymentGroup.uuid, slug: slug });
|
||||||
|
}
|
||||||
return filter(services, { project: deploymentGroup.uuid });
|
return filter(services, { project: deploymentGroup.uuid });
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -147,19 +152,23 @@ const resolveFunctions = {
|
|||||||
data: getInstanceMetricData(leakMetricData, 'node_memory_rss_bytes')
|
data: getInstanceMetricData(leakMetricData, 'node_memory_rss_bytes')
|
||||||
};
|
};
|
||||||
}*/
|
}*/
|
||||||
},
|
}
|
||||||
|
|
||||||
|
const resolveFunctions = {
|
||||||
|
Query: queries,
|
||||||
Portal: {
|
Portal: {
|
||||||
deploymentGroups(portal) {
|
deploymentGroups(portal, args, context) {
|
||||||
return deploymentGroups;
|
return deploymentGroups;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DeploymentGroup: {
|
DeploymentGroup: {
|
||||||
services(deploymentGroup) {
|
services(deploymentGroup, args, context) {
|
||||||
return filter(services, { project: deploymentGroup.uuid });
|
const a = Object.assign({}, args, {deploymentGroupSlug: deploymentGroup.slug})
|
||||||
},
|
return queries.services(null, a);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Service: {
|
Service: {
|
||||||
instances(service) {
|
instances(service, args, context) {
|
||||||
return filter(instances, { service: service.uuid });
|
return filter(instances, { service: service.uuid });
|
||||||
},
|
},
|
||||||
/*metrics(service) {
|
/*metrics(service) {
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
uuid: ID!
|
uuid: ID!
|
||||||
name: String!
|
name: String!
|
||||||
slug: String!
|
slug: String!
|
||||||
services: [Service]!
|
services(slug: String): [Service]!
|
||||||
version: Version!
|
version: Version!
|
||||||
history: [Version]!
|
history: [Version]!
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user