Commit e235e2ce authored by charlie-ablett's avatar charlie-ablett

File list collapsing

parent be23b832
......@@ -2,3 +2,4 @@ import * from './authenticationActions.js';
import * from './recipeActions.js';
import * from './fileActions.js';
import * from './adminActions.js';
// import * from './uiActions.js'
......@@ -233,34 +233,58 @@ export function resetPlaceholders() {
}
///////////////////////////////////////////////////////////////
/////////////////////// mark chain state //////////////////////
//////////////// expand/collapse file lists ///////////////////
///////////////////////////////////////////////////////////////
//
// export function markAsStarted(recipeId, chainId) {
// console.log("marking chain id as started", chainId)
// return {
// type: actions.MARK_CHAIN_AS_STARTED,
// chainId: chainId,
// recipeId: recipeId
// };
// }
//
// export function markAsCompleted(recipeId, chainId) {
// console.log("marking chain id as completed", chainId)
// return {
// type: actions.MARK_CHAIN_AS_COMPLETED,
// chainId: chainId,
// recipeId: recipeId
// };
// }
//
// export function markAsErrored(recipeId, chainId) {
// return {
// type: actions.MARK_CHAIN_AS_ERRORED,
// chainId: chainId,
// recipeId: recipeId
// };
// }
export function expandChainInputFileList(chainId, recipeId) {
return {
type: actions.EXPAND_CHAIN_INPUT_FILE_LIST,
chainId: chainId,
recipeId: recipeId
};
}
export function collapseChainInputFileList(chainId, recipeId) {
return {
type: actions.COLLAPSE_CHAIN_INPUT_FILE_LIST,
chainId: chainId,
recipeId: recipeId
};
}
export function expandChainOutputFileList(chainId, recipeId) {
return {
type: actions.EXPAND_CHAIN_OUTPUT_FILE_LIST,
chainId: chainId,
recipeId: recipeId
};
}
export function collapseChainOutputFileList(chainId, recipeId) {
return {
type: actions.COLLAPSE_CHAIN_OUTPUT_FILE_LIST,
chainId: chainId,
recipeId: recipeId
};
}
export function expandStepFileList(stepId, chainId, recipeId) {
return {
type: actions.EXPAND_STEP_FILE_LIST,
chainId: chainId,
recipeId: recipeId,
stepId: stepId
};
}
export function collapseStepFileList(stepId, chainId, recipeId) {
return {
type: actions.COLLAPSE_STEP_FILE_LIST,
chainId: chainId,
recipeId: recipeId,
stepId: stepId
};
}
///////////////////////////////////////////////////////////////
///////////////// new recipe - step class list ////////////////
......
......@@ -38,8 +38,6 @@ export class ExecutionDetail extends Component {
if(_.isNil(processChain.finished_at)) {
return(<p><span className="fa fa-gear fa-spin fa-fw" />{this.renderInProgressTitle()}</p>);
}
// let className = (_.isNil(processChain.finished_at)) ? 'small-info-text' : 'successful';
return(<p><span className="fa fa-check" /> {this.renderFinishedTitle()}</p>);
}
......@@ -62,7 +60,7 @@ export class ExecutionDetail extends Component {
</tr>
</thead>
<tbody>
{processChain.process_steps.map(step => <ExecutionDetailStep key={step.id} processStep={step} dispatch={dispatch} appState={appState} />)}
{processChain.process_steps.map(step => <ExecutionDetailStep key={step.id} recipeId={processChain.recipe_id} processStep={step} dispatch={dispatch} appState={appState} />)}
</tbody>
</table>
</div>
......
......@@ -2,9 +2,11 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import _ from "lodash";
import SmoothCollapse from 'react-smooth-collapse';
import * as actions from '../actions/authenticationActions';
import { downloadOutputFile, downloadStepOutputZip } from '../businessLogic/fileLogic';
import { expandStepFileList, collapseStepFileList } from '../actions/recipeActions';
export class ExecutionDetailStep extends Component {
......@@ -20,6 +22,32 @@ export class ExecutionDetailStep extends Component {
dispatch(downloadStepOutputZip(processStepId, appState, dispatch));
}
handleToggle = (e, toExpand, processStepId, chainId, recipeId) => {
const { appState, dispatch } = this.props;
if (toExpand == true) {
dispatch(expandStepFileList(processStepId, chainId, recipeId));
} else {
dispatch(collapseStepFileList(processStepId, chainId, recipeId));
}
}
listExpandCollapseToggle(processStep) {
return(
<a href="#" onClick={e => this.handleToggle(e, processStep.file_list_collapse, processStep.id, processStep.process_chain_id, this.props.recipeId)}>
<span className={this.listIcon(processStep.file_list_collapse)}/>
&nbsp;Files ({_.size(processStep.output_file_manifest)})
</a>
);
}
listIcon(collapsed) {
if(collapsed == true || _.isNil(collapsed)) {
return "fa fa-caret-right";
} else {
return "fa fa-caret-down";
}
}
successClass(execution_errors, successful) {
if(successful === true) {
return("success");
......@@ -66,12 +94,28 @@ export class ExecutionDetailStep extends Component {
);
}
renderFileList(fileList) {
let { processStep } = this.props;
let collapsed = processStep.file_list_collapse;
return(
<SmoothCollapse expanded={!collapsed}>
{fileList.map( file =>
<li key={file.path} className="file-list-item monospace">
<span className="fa fa-hand-o-right small-info"/>
{this.renderLink(file.path, processStep.id, processStep.finished_at)}
<span className="small-info-text">({file.size})</span>
</li>)}
</SmoothCollapse>
);
}
renderOutputFiles(processStep) {
let fileList = processStep.output_file_manifest;
return(
<div>
<ul className="file-list">
{ fileList.map( file => <li key={file.path} className="file-list-item monospace"><span className="fa fa-hand-o-right small-info"/> {this.renderLink(file.path, processStep.id, processStep.finished_at)} <span className="small-info-text">({file.size})</span></li> ) }
{this.listExpandCollapseToggle(processStep)}
{this.renderFileList(fileList)}
</ul>
</div>
);
......@@ -170,7 +214,8 @@ export class ExecutionDetailStep extends Component {
ExecutionDetailStep.propTypes = {
dispatch: PropTypes.func,
processStep: PropTypes.object.isRequired,
appState: PropTypes.object
appState: PropTypes.object,
recipeId: PropTypes.number.isRequired
};
function mapStateToProps(state) {
......
......@@ -2,9 +2,11 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import _ from "lodash";
import SmoothCollapse from 'react-smooth-collapse';
import * as actions from '../actions/authenticationActions';
import { downloadInputFile, downloadOutputFile, downloadInputZip, downloadChainOutputZip, downloadChainOutputFile } from '../businessLogic/fileLogic';
import { collapseChainInputFileList, expandChainInputFileList, collapseChainOutputFileList, expandChainOutputFileList } from '../actions/recipeActions';
export class ExecutionFileList extends Component {
......@@ -30,6 +32,19 @@ export class ExecutionFileList extends Component {
dispatch(downloadInputFile(filePath, processChainId, appState, dispatch));
}
handleToggle = (e, isInput, toExpand, chainId, recipeId) => {
const { appState, dispatch } = this.props;
if(isInput == true && toExpand == true) {
dispatch(expandChainInputFileList(chainId, recipeId, appState));
} else if (isInput == true) {
dispatch(collapseChainInputFileList(chainId, recipeId, appState));
} else if (toExpand == true) {
dispatch(expandChainOutputFileList(chainId, recipeId, appState));
} else {
dispatch(collapseChainOutputFileList(chainId, recipeId, appState));
}
}
renderFileLink(filePath, isOutput, id) {
if(_.isNil(filePath) || _.isEmpty(filePath)) {
return(
......@@ -67,18 +82,21 @@ export class ExecutionFileList extends Component {
}
}
renderFileList(isOutput, fileList, chainId) {
renderFileList(isOutput, fileList, chainId, collapsed) {
if(_.isEmpty(fileList)) {
return(<span/>);
}
return(
<ul className="file-list">
{ fileList.map((file) =>
<li className="file-list-item monospace" key={file.path}>
<span className="fa fa-hand-o-right small-info" />
&nbsp;
{ this.renderFileLink(file.path, isOutput, chainId) } <span className="small-info-text">({ file.size })</span>
</li>) }
<SmoothCollapse expanded={!collapsed}>
{ fileList.map((file) =>
<li className="file-list-item monospace" key={file.path}>
<span className="fa fa-hand-o-right small-info" />
&nbsp;
{ this.renderFileLink(file.path, isOutput, chainId) } <span className="small-info-text">({ file.size })</span>
</li>)
}
</SmoothCollapse>
</ul>
);
}
......@@ -87,22 +105,47 @@ export class ExecutionFileList extends Component {
if(!_.isNil(processChain.finished_at)) {
return( this.renderChainZipLink(true, processChain.id) );
}
return(<span className="small-info">&nbsp;[ Not available yet ]</span>);
return(<span className="small-info">&nbsp;[ Not available ]</span>);
}
listExpandCollapseToggle(processChain, isInput) {
if(isInput == true) {
return(
<a href="#" onClick={e => this.handleToggle(e, isInput, processChain.input_file_list_collapse, processChain.id, processChain.recipe_id)}>
<span className={this.listIcon(processChain.input_file_list_collapse)}/>
&nbsp;Input Files ({_.size(processChain.input_file_manifest)})
</a>
);
} else {
return(
<a href="#" onClick={e => this.handleToggle(e, isInput, processChain.output_file_list_collapse, processChain.id, processChain.recipe_id)}>
<span className={this.listIcon(processChain.output_file_list_collapse)}/>
&nbsp;Output Files ({_.size(processChain.output_file_manifest)})
</a>
);
}
}
listIcon(collapsed) {
if(collapsed == true || _.isNil(collapsed)) {
return "fa fa-caret-right";
} else {
return "fa fa-caret-down";
}
}
render() {
const { processChain } = this.props;
return(
<div>
<div>
<span className="fa fa-sign-in"/> Input Files ({_.size(processChain.input_file_manifest)}): { this.renderChainZipLink(false, processChain.id) }
{this.listExpandCollapseToggle(processChain, true)} <span className="silver">|</span> { this.renderChainZipLink(false, processChain.id) }
</div>
<div>{ this.renderFileList(false, processChain.input_file_manifest, processChain.id) }</div>
<div>{ this.renderFileList(false, processChain.input_file_manifest, processChain.id, processChain.input_file_list_collapse) }</div>
<div>
<span className="fa fa-sign-out" /> Output Files ({_.size(processChain.output_file_manifest)}): { this.renderOutputLink(processChain) }
{this.listExpandCollapseToggle(processChain, false)} | { this.renderOutputLink(processChain) }
</div>
<div>{ this.renderFileList(true, processChain.output_file_manifest, processChain.id) }</div>
<div>{ this.renderFileList(true, processChain.output_file_manifest, processChain.id, processChain.output_file_list_collapse) }</div>
</div>
);
}
......
......@@ -55,6 +55,13 @@ export const AVAILABLE_STEP_LIST_REQUEST = "AVAILABLE_STEP_LIST_REQUEST";
export const AVAILABLE_STEP_LIST_SUCCESS = "AVAILABLE_STEP_LIST_SUCCESS";
export const AVAILABLE_STEP_LIST_FAILURE = "AVAILABLE_STEP_LIST_FAILURE";
export const COLLAPSE_CHAIN_INPUT_FILE_LIST = "COLLAPSE_CHAIN_INPUT_FILE_LIST";
export const EXPAND_CHAIN_INPUT_FILE_LIST = "EXPAND_CHAIN_INPUT_FILE_LIST";
export const COLLAPSE_CHAIN_OUTPUT_FILE_LIST = "COLLAPSE_CHAIN_OUTPUT_FILE_LIST";
export const EXPAND_CHAIN_OUTPUT_FILE_LIST = "EXPAND_CHAIN_OUTPUT_FILE_LIST";
export const COLLAPSE_STEP_FILE_LIST = "COLLAPSE_STEP_FILE_LIST";
export const EXPAND_STEP_FILE_LIST = "EXPAND_STEP_FILE_LIST";
/////////////////// admin //////////////////////
export const GET_ALL_USERS_REQUEST = "GET_ALL_USERS_REQUEST";
......
import { combineReducers } from 'redux';
// import authenticationReducer from './authenticationReducer';
import appState from './authenticationReducer';
// import recipesState from './RecipesReducer';
import appState from './reducer';
const rootReducer = combineReducers({
appState
// recipesState
});
export default rootReducer;
import * as types from '../constants/ActionTypes';
import { GET_ALL_RECIPES } from '../constants/ActionTypes';
import * as alerts from '../constants/Alerts.js';
import { initialState } from './authenticationReducer'
import objectAssign from 'object-assign';
// not being used right now
export default function recipesState(state = initialState, action) {
switch (action.type) {
case types.GET_ALL_RECIPES:
{
let newState = objectAssign({}, state);
newState.recipes = action.data.recipes;
return newState;
}
default:
return state;
}
}
......@@ -27,7 +27,6 @@ export const initialState = {
};
export default function appState(state = initialState, action) {
// export default function authenticationReducer(state = initialState, action) {
switch (action.type) {
case actionTypes.SET_ALERT:
{
......@@ -162,6 +161,15 @@ export default function appState(state = initialState, action) {
newState.getRecipesInProgress = false;
newState.recipes = action.data.recipes;
newState.recipes.map(recipe => {
recipe.process_chains.map(process_chain => {
process_chain.input_file_list_collapse = true;
process_chain.output_file_list_collapse = true;
process_chain.process_steps.map(process_step => {
process_step.file_list_collapse = true;
});
});
});
return newState;
}
......@@ -250,6 +258,14 @@ export default function appState(state = initialState, action) {
newState.selectedRecipe = action.recipe;
newState.selectedRecipeID = action.recipe.id;
newState.selectedRecipe.process_chains.map(process_chain => {
process_chain.input_file_list_collapse = true;
process_chain.output_file_list_collapse = true;
process_chain.process_steps.map(process_step => {
process_step.file_list_collapse = true;
});
});
return newState;
}
......@@ -421,6 +437,7 @@ export default function appState(state = initialState, action) {
theChain.finished_at = Date.now();
theChain.output_file_manifest = action.data.output_file_manifest;
theChain.output_file_list_collapse = true;
console.log("Chain completed: date", theChain.finished_at);
return newState;
......@@ -450,6 +467,7 @@ export default function appState(state = initialState, action) {
theStep.started_at = Date.now();
theStep.in_progress = true;
theStep.file_list_collapse = true;
console.log("Step started: position", action.data.position);
if(_.isNil(theChain.executed_at)) {
......@@ -475,6 +493,8 @@ export default function appState(state = initialState, action) {
theStep.notes = action.data.notes;
theStep.execution_errors = action.data.execution_errors;
theStep.in_progress = false;
theStep.file_list_collapse = true;
console.log("Step completed: position", action.data.position);
return newState;
......@@ -509,6 +529,80 @@ export default function appState(state = initialState, action) {
return newState;
}
case actionTypes.COLLAPSE_CHAIN_INPUT_FILE_LIST:
{
let newState = objectAssign({}, state);
let theRecipe = _.find(newState.recipes, _.matchesProperty('id', action.recipeId));
let theChain = _.find(theRecipe.process_chains, _.matchesProperty('id', action.chainId));
theChain.input_file_list_collapse = true;
return newState;
}
case actionTypes.EXPAND_CHAIN_INPUT_FILE_LIST:
{
let newState = objectAssign({}, state);
let theRecipe = _.find(newState.recipes, _.matchesProperty('id', action.recipeId));
let theChain = _.find(theRecipe.process_chains, _.matchesProperty('id', action.chainId));
theChain.input_file_list_collapse = false;
return newState;
}
case actionTypes.COLLAPSE_CHAIN_OUTPUT_FILE_LIST:
{
let newState = objectAssign({}, state);
let theRecipe = _.find(newState.recipes, _.matchesProperty('id', action.recipeId));
let theChain = _.find(theRecipe.process_chains, _.matchesProperty('id', action.chainId));
theChain.output_file_list_collapse = true;
return newState;
}
case actionTypes.EXPAND_CHAIN_OUTPUT_FILE_LIST:
{
let newState = objectAssign({}, state);
let theRecipe = _.find(newState.recipes, _.matchesProperty('id', action.recipeId));
let theChain = _.find(theRecipe.process_chains, _.matchesProperty('id', action.chainId));
theChain.output_file_list_collapse = false;
return newState;
}
case actionTypes.COLLAPSE_STEP_FILE_LIST:
{
let newState = objectAssign({}, state);
let theRecipe = _.find(newState.recipes, _.matchesProperty('id', action.recipeId));
let theChain = _.find(theRecipe.process_chains, _.matchesProperty('id', action.chainId));
let theStep = _.find(theChain.process_steps, _.matchesProperty('id', action.stepId));
theStep.file_list_collapse = true;
return newState;
}
case actionTypes.EXPAND_STEP_FILE_LIST:
{
let newState = objectAssign({}, state);
let theRecipe = _.find(newState.recipes, _.matchesProperty('id', action.recipeId));
let theChain = _.find(theRecipe.process_chains, _.matchesProperty('id', action.chainId));
let theStep = _.find(theChain.process_steps, _.matchesProperty('id', action.stepId));
theStep.file_list_collapse = false;
return newState;
}
default:
return state;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment