store: Use redux to store composes
This commit is contained in:
parent
b17be18dfd
commit
3e797b92b0
9 changed files with 144 additions and 75 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { actions } from '../redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
|
@ -32,8 +34,21 @@ class CreateImageCard extends Component {
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
let api = new DefaultApi();
|
let api = new DefaultApi();
|
||||||
|
let { updateCompose } = this.props;
|
||||||
api.composeImage(request).then(response => {
|
api.composeImage(request).then(response => {
|
||||||
this.props.onCompose(response.data.compose_id);
|
/* request failed? */
|
||||||
|
if (response.data.compose_id === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let compose = {};
|
||||||
|
compose[response.data.compose_id] = {
|
||||||
|
status: 'request sent',
|
||||||
|
distribution: request.image_builds[0].distribution,
|
||||||
|
architecture: request.image_builds[0].architecture,
|
||||||
|
image_type: request.image_builds[0].image_type,
|
||||||
|
};
|
||||||
|
updateCompose(compose);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,8 +69,14 @@ class CreateImageCard extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return {
|
||||||
|
updateCompose: (compose) => dispatch(actions.updateCompose(compose)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
CreateImageCard.propTypes = {
|
CreateImageCard.propTypes = {
|
||||||
onCompose: PropTypes.func,
|
updateCompose: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CreateImageCard;
|
export default connect(() => {}, mapDispatchToProps)(CreateImageCard);
|
||||||
|
|
|
||||||
70
src/SmartComponents/LandingPage/ImagesCard.js
Normal file
70
src/SmartComponents/LandingPage/ImagesCard.js
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { actions } from '../redux';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardBody,
|
||||||
|
} from '@patternfly/react-core';
|
||||||
|
|
||||||
|
import { DefaultApi } from '@redhat-cloud-services/osbuild-installer';
|
||||||
|
|
||||||
|
class ImagesCard extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.pollComposeStatuses = this.pollComposeStatuses.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.interval = setInterval(() => this.pollComposeStatuses(), 8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
pollComposeStatuses() {
|
||||||
|
let api = new DefaultApi();
|
||||||
|
let { updateCompose, composes } = this.props;
|
||||||
|
Object.entries(composes).map(([ id, compose ]) => {
|
||||||
|
api.getComposeStatus(id).then(response => {
|
||||||
|
let newCompose = {};
|
||||||
|
newCompose[id] = Object.assign({}, compose, { status: response.data.status });
|
||||||
|
updateCompose(newCompose);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { composes } = this.props;
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>Pending composes</CardHeader>
|
||||||
|
{ Object.entries(composes).map(([ id, compose ]) => {
|
||||||
|
return <CardBody key={ id }>
|
||||||
|
<label>{ id }</label>
|
||||||
|
<p>{ compose.architecture }, { compose.distribution }, { compose.image_type }</p>
|
||||||
|
<p>{ compose.status }</p>
|
||||||
|
</CardBody>;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Card>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
composes: state.composes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return {
|
||||||
|
updateCompose: (compose) => dispatch(actions.updateCompose(compose)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ImagesCard.propTypes = {
|
||||||
|
composes: PropTypes.object,
|
||||||
|
updateCompose: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ImagesCard);
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from '@redhat-cloud-services/frontend-components';
|
} from '@redhat-cloud-services/frontend-components';
|
||||||
|
|
||||||
import CreateImageCard from './CreateImageCard';
|
import CreateImageCard from './CreateImageCard';
|
||||||
import PendingImagesCard from './PendingImagesCard.js';
|
import ImagesCard from './ImagesCard.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A smart component that handles all the api calls and data needed by the dumb components.
|
* A smart component that handles all the api calls and data needed by the dumb components.
|
||||||
|
|
@ -21,20 +21,7 @@ import PendingImagesCard from './PendingImagesCard.js';
|
||||||
class LandingPage extends Component {
|
class LandingPage extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
|
||||||
pendingComposeIds: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onPendingCompose = this.onPendingCompose.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onPendingCompose(composeId) {
|
|
||||||
this.setState(oldState => {
|
|
||||||
return { pendingComposeIds: oldState.pendingComposeIds.concat(composeId) };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
|
@ -44,10 +31,10 @@ class LandingPage extends Component {
|
||||||
<Main>
|
<Main>
|
||||||
<Flex>
|
<Flex>
|
||||||
<FlexItem breakpointMods={ [{ modifier: FlexModifiers.column }, { modifier: FlexModifiers['flex-1'] }] }>
|
<FlexItem breakpointMods={ [{ modifier: FlexModifiers.column }, { modifier: FlexModifiers['flex-1'] }] }>
|
||||||
<CreateImageCard onCompose={ this.onPendingCompose } />
|
<CreateImageCard />
|
||||||
</FlexItem>
|
</FlexItem>
|
||||||
<FlexItem breakpointMods={ [{ modifier: FlexModifiers.column }, { modifier: FlexModifiers['flex-1'] }] }>
|
<FlexItem breakpointMods={ [{ modifier: FlexModifiers.column }, { modifier: FlexModifiers['flex-1'] }] }>
|
||||||
<PendingImagesCard pendingComposeIds={ this.state.pendingComposeIds } />
|
<ImagesCard />
|
||||||
</FlexItem>
|
</FlexItem>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Main>
|
</Main>
|
||||||
|
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
CardHeader,
|
|
||||||
CardBody,
|
|
||||||
} from '@patternfly/react-core';
|
|
||||||
|
|
||||||
import { DefaultApi } from '@redhat-cloud-services/osbuild-installer';
|
|
||||||
|
|
||||||
class PendingImagesCard extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
composeStatuses: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
this.pollComposeIds = this.pollComposeIds.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.interval = setInterval(() => this.pollComposeIds(), 8000);
|
|
||||||
}
|
|
||||||
|
|
||||||
pollComposeIds() {
|
|
||||||
let api = new DefaultApi();
|
|
||||||
for (let id of this.props.pendingComposeIds) {
|
|
||||||
api.getComposeStatus(id).then(response => {
|
|
||||||
this.setState(oldState => {
|
|
||||||
let composeStatuses = Object.assign({}, oldState.composeStatuses);
|
|
||||||
composeStatuses[id] = response.data.status;
|
|
||||||
return { composeStatuses };
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardHeader>Pending composes</CardHeader>
|
|
||||||
{ Object.entries(this.state.composeStatuses).map(([ id, status ]) => {
|
|
||||||
return <CardBody key={ id }><label>{ id }</label><p>{ status }</p></CardBody>;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</Card>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingImagesCard.propTypes = {
|
|
||||||
pendingComposeIds: PropTypes.array,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PendingImagesCard;
|
|
||||||
12
src/SmartComponents/redux/actions.js
Normal file
12
src/SmartComponents/redux/actions.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import types from './types';
|
||||||
|
|
||||||
|
function updateCompose(compose) {
|
||||||
|
return {
|
||||||
|
type: types.UPDATE_COMPOSE,
|
||||||
|
compose
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
updateCompose,
|
||||||
|
};
|
||||||
1
src/SmartComponents/redux/index.js
Normal file
1
src/SmartComponents/redux/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as actions } from './actions';
|
||||||
22
src/SmartComponents/redux/reducers.js
Normal file
22
src/SmartComponents/redux/reducers.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import types from './types';
|
||||||
|
|
||||||
|
// Example of action.compose
|
||||||
|
// {
|
||||||
|
// "xxxx-xxxx-xxxx-xxxx": {
|
||||||
|
// state: "uploading",
|
||||||
|
// distribution: "fedora-31",
|
||||||
|
// architecture: "x86_64",
|
||||||
|
// image_type: "qcow2"
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
export function composeReducer(state = { }, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case types.UPDATE_COMPOSE:
|
||||||
|
return Object.assign({}, state, action.compose);
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
...state
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/SmartComponents/redux/types.js
Normal file
6
src/SmartComponents/redux/types.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
const UPDATE_COMPOSE = 'UPDATE_COMPOSE';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
UPDATE_COMPOSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import ReducerRegistry from '@redhat-cloud-services/frontend-components-utilities/files/ReducerRegistry';
|
import ReducerRegistry from '@redhat-cloud-services/frontend-components-utilities/files/ReducerRegistry';
|
||||||
import promiseMiddleware from 'redux-promise-middleware';
|
import promiseMiddleware from 'redux-promise-middleware';
|
||||||
|
|
||||||
|
import { composeReducer } from '../SmartComponents/redux/reducers';
|
||||||
|
|
||||||
let registry;
|
let registry;
|
||||||
|
|
||||||
export function init (...middleware) {
|
export function init (...middleware) {
|
||||||
|
|
@ -13,6 +15,10 @@ export function init (...middleware) {
|
||||||
...middleware
|
...middleware
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
registry.register({
|
||||||
|
composes: composeReducer,
|
||||||
|
});
|
||||||
|
|
||||||
return registry;
|
return registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue