Commit 98f46013 authored by Viacheslav Pavlov's avatar Viacheslav Pavlov Committed by Matija Obreza
Browse files

More KPI runs

fixed styles for ExecutionDisplay
parent 51d4f2d7
......@@ -1457,7 +1457,9 @@
"runFrom": "Run from ",
"runs": "Runs",
"execute": "Execute",
"title": "Execution details"
"title": "Execution details",
"loadMore": "Load more",
"nothingToLoad": "No runs match entered date"
},
"parameterDialog": {
"button": "Add parameter",
......@@ -1472,7 +1474,8 @@
"NumericListDimension": "NumericListDimension",
"StringListDimension": "StringListDimension"
},
"showRun": "Show run info"
"showRun": "Show run info",
"executionRunsLoaded": "Execution runs loaded successfully"
}
}
,"list": {
......
// actions
import navigateTo from 'actions/navigation';
import { showSnackbar } from 'actions/snackbar';
// constants
import {
......@@ -7,6 +8,7 @@ import {
ADMIN_RECEIVE_PARAM, ADMIN_RECEIVE_DIMS,
ADMIN_RECEIVE_EXECS, ADMIN_RECEIVE_EXEC,
ADMIN_RECEIVE_EXEC_LASTRUN, ADMIN_RECEIVE_DIM,
ADMIN_RECEIVE_EXEC_RUNS, ADMIN_APPEND_EXEC_RUNS,
ADMIN_RECEIVE_EXEC_DET, ADMIN_REMOVE_DIM,
ADMIN_REMOVE_PARAM,
} from 'kpi/constants';
......@@ -72,6 +74,26 @@ const receiveExecutionRun = (executionRun: ExecutionRun): IReducerAction => ({
type: ADMIN_RECEIVE_EXEC_LASTRUN, payload: executionRun,
});
const receiveExecutionRuns = (runs: Page<ExecutionRun>): IReducerAction => ({
type: ADMIN_RECEIVE_EXEC_RUNS, payload: {runs},
});
const appendExecutionRuns = (runs: Page<ExecutionRun>): IReducerAction => ({
type: ADMIN_APPEND_EXEC_RUNS, payload: {runs},
});
export const loadMoreExecutionRuns = (executionName: string, page: number) => (dispatch) => {
return KpiService.executionRuns(executionName, {page, size: 10})
.then((runs) => {
if (runs.number === 0) {
dispatch(receiveExecutionRuns(runs));
} else {
dispatch(appendExecutionRuns(runs));
}
dispatch(showSnackbar('kpi.common.executionRunsLoaded'));
});
};
export const listDimensions = (page: IPageRequest) => (dispatch) => {
KpiService.listDimensions(page).then((data) => {
dispatch(receiveDimensions(ensureDimensionType(data)));
......
......@@ -17,6 +17,8 @@ export const ADMIN_RECEIVE_EXEC = 'kpi/admin/RECEIVE_EXEC';
export const ADMIN_REMOVE_EXEC = 'kpi/admin/REMOVE_EXEC';
export const ADMIN_RECEIVE_EXEC_DET = 'kpi/admin/RECEIVE_EXEC_DET';
export const ADMIN_RECEIVE_EXEC_LASTRUN = 'kpi/admin/RECEIVE_LASTRUN';
export const ADMIN_RECEIVE_EXEC_RUNS = 'kpi/admin/RECEIVE_EXEC_RUNS';
export const ADMIN_APPEND_EXEC_RUNS = 'kpi/admin/APPEND_EXEC_RUNS ';
export const ADMIN_RECEIVE_PARAMS = 'kpi/admin/RECEIVE_PARAMS';
export const ADMIN_RECEIVE_PARAM = 'kpi/admin/RECEIVE_PARAM';
......
import update from 'immutability-helper';
import {IReducerAction} from 'model/common.model';
import { IReducerAction } from 'model/common.model';
import {
ADMIN_APPEND_EXEC_RUNS,
ADMIN_RECEIVE_DIM,
ADMIN_RECEIVE_DIMS,
ADMIN_RECEIVE_EXEC,
ADMIN_RECEIVE_EXEC_DET,
ADMIN_RECEIVE_EXEC_LASTRUN,
ADMIN_RECEIVE_EXEC_RUNS,
ADMIN_RECEIVE_EXECS,
ADMIN_RECEIVE_PARAM,
ADMIN_RECEIVE_PARAMS,
......@@ -122,6 +124,31 @@ export default function admin(state = INITIAL_STATE, action: IReducerAction) {
exec: { details: { lastRun: { $set: action.payload } } },
});
}
case ADMIN_RECEIVE_EXEC_RUNS: {
const { runs } = action.payload;
return update(state, {
exec: {
details: {
runs: { $set: runs },
},
},
});
}
case ADMIN_APPEND_EXEC_RUNS: {
const { runs } = action.payload;
return update(state, {
exec: {
details: {
runs: {
content: { $push: runs.content },
number: { $set: runs.number },
last: { $set: runs.last },
first: { $set: runs.first },
},
},
},
});
}
case ADMIN_RECEIVE_DIMS: {
return update(state, {
dim: { page: { $set: action.payload } },
......
......@@ -86,7 +86,9 @@
"runFrom": "Run from ",
"runs": "Runs",
"execute": "Execute",
"title": "Execution details"
"title": "Execution details",
"loadMore": "Load more",
"nothingToLoad": "No runs match entered date"
},
"parameterDialog": {
"button": "Add parameter",
......@@ -101,6 +103,7 @@
"NumericListDimension": "NumericListDimension",
"StringListDimension": "StringListDimension"
},
"showRun": "Show run info"
"showRun": "Show",
"executionRunsLoaded": "Execution runs loaded successfully"
}
}
\ No newline at end of file
......@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { translate } from 'react-i18next';
// Actions
import { deleteExecution, executeExecution, getExecution, listDimensions, listParameters } from 'kpi/actions/admin';
import { deleteExecution, executeExecution, getExecution, listDimensions, listParameters, loadMoreExecutionRuns } from 'kpi/actions/admin';
import { showSnackbar } from 'actions/snackbar';
// Models
import ExecutionDetails from 'model/kpi/ExecutionDetails';
......@@ -23,14 +23,33 @@ import Button from '@material-ui/core/Button';
import RunTable from './c/RunTable';
import ExecutionDialog from './ExecutionDialog';
import FileCopyIcon from '@material-ui/icons/FileCopy';
import DateInput from './c/DateInput';
import withStyles from '@material-ui/core/styles/withStyles';
// import { parse } from 'query-string';
/*tslint:disable*/
const styles = (theme) => ({
runInfoHeaderActions: {
height: '24px',
display: 'flex' as 'flex',
'& > div': {
display: 'initial' as 'initial',
},
},
loadMoreButton: {
display: 'flex' as 'flex',
justifyContent: 'center' as 'center',
},
});
/*tslint:enable*/
interface IExecutionProps extends React.ClassAttributes<any> {
classes: any;
t?: any;
shortName: string;
loadMoreExecutionRuns: (name: string, page: number) => void;
executionDetails: ExecutionDetails;
getExecution: any;
executeExecution: any;
......@@ -107,6 +126,20 @@ class ExecutionDisplay extends React.Component<IExecutionProps, any> {
}
}
private loadRunInfoByDate = (date: string) => {
const { shortName, t, showSnackbar } = this.props;
if (shortName) {
KpiService.executionRunByDate(shortName, date).then((run) => {
if (!run) {
showSnackbar(t('kpi.admin.p.executionDisplay.nothingToLoad'));
} else {
this.setState({ currentRun: run });
}
});
}
}
public componentWillReceiveProps(nextProps) {
const { shortName, executionDetails, getExecution } = nextProps;
if (!executionDetails || !executionDetails.execution || executionDetails.execution.name !== shortName) {
......@@ -115,12 +148,19 @@ class ExecutionDisplay extends React.Component<IExecutionProps, any> {
}
}
private loadMoreExecutionRuns = () => {
const { shortName, executionDetails, loadMoreExecutionRuns } = this.props;
if (shortName && executionDetails && executionDetails.runs) {
loadMoreExecutionRuns(shortName, executionDetails.runs.number + 1);
}
}
public render() {
const { t, shortName, executionDetails } = this.props;
const { t, classes, shortName, executionDetails } = this.props;
const stillLoading = !executionDetails || !executionDetails.execution || executionDetails.execution.name !== shortName;
const execution = executionDetails === null ? null : executionDetails.execution;
const runs = executionDetails === null ? null : executionDetails.runs;
const runs = executionDetails === null || !executionDetails.runs ? null : executionDetails.runs.content;
const lastRun = executionDetails === null ? null : executionDetails.lastRun;
const {currentRun} = this.state;
......@@ -182,10 +222,13 @@ class ExecutionDisplay extends React.Component<IExecutionProps, any> {
<Grid item sm={ 12 } md={ 6 }>
<PageSection title={ currentRun === null ? t('kpi.admin.p.executionDisplay.lastRun') : <span>{ t('kpi.admin.p.executionDisplay.runFrom') }<PrettyDate value={ currentRun.timestamp }/></span> }
action={
<Button id="copyBtn" onClick={ this.copyRunTable }>
{ t('common:action.copyToClipboard') }&nbsp;&nbsp;
<FileCopyIcon fontSize="small"/>
</Button>
<span className={ classes.runInfoHeaderActions }>
{ (currentRun || lastRun) && <DateInput initialValue={ currentRun ? currentRun.timestamp : lastRun.timestamp } onSubmit={ this.loadRunInfoByDate }/> }
<Button id="copyBtn" onClick={ this.copyRunTable }>
{ t('common:action.copyToClipboard') }&nbsp;&nbsp;
<FileCopyIcon fontSize="small"/>
</Button>
</span>
}
>
<RunTable execution={ execution } runInfo={ currentRun || lastRun } />
......@@ -200,6 +243,13 @@ class ExecutionDisplay extends React.Component<IExecutionProps, any> {
<a onClick={ () => this.loadRunInfo(runInfo) }>{ t('kpi.common.showRun') }</a>
</PropertiesItem>
)) }
<PropertiesItem>
{ !executionDetails.runs.last &&
<a onClick={ this.loadMoreExecutionRuns } className={ classes.loadMoreButton }>
{ t('kpi.admin.p.executionDisplay.loadMore') }
</a>
}
</PropertiesItem>
</Properties>
</PageSection>
}
......@@ -218,10 +268,11 @@ const mapStateToProps = (state, ownProps) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
getExecution,
loadMoreExecutionRuns,
executeExecution,
deleteExecution,
showSnackbar,
}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)((translate()(ExecutionDisplay)));
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)((translate()(ExecutionDisplay))));
import * as React from 'react';
import TextField from '@material-ui/core/TextField';
class DateInput extends React.Component<any> {
public state = {
internalDate: '',
};
private toDateString = (date: any) => {
if (!date || date === '') {
return '';
}
const valueDate = date.getTime ? date : new Date(date);
let y = valueDate.getFullYear().toString();
let m = (valueDate.getMonth() + 1).toString();
let d = valueDate.getDate().toString();
d = d.length === 1 ? (`0${d}`) : d;
m = m.length === 1 ? (`0${m}`) : m;
y = y.length === 1 ? (`000${y}`) : y.length === 2 ? (`00${y}`) : y.length === 3 ? (`0${y}`) : y;
return `${y}-${m}-${d}`;
}
public componentWillMount(): void {
const { initialValue } = this.props;
this.setState({ internalDate: initialValue });
}
public componentWillReceiveProps(nextProps): void {
const { initialValue } = nextProps;
const { initialValue: oldValue } = this.props;
if (oldValue !== initialValue) {
this.setState({ internalDate: initialValue });
}
}
public render() {
return (
<TextField
type="date"
onKeyPress={ this.handleTextFieldType }
value={ this.toDateString(this.state.internalDate) }
onChange={ this.onInputChange }
InputLabelProps={ { shrink: true } }
/>
);
}
private onInputChange = (event) => {
this.setState({ internalDate: event.target.value });
}
private handleTextFieldType = (ev) => {
if (ev.key === 'Enter') {
this.handleSubmit();
ev.preventDefault();
}
}
private handleSubmit = () => {
const { onSubmit } = this.props;
const { internalDate } = this.state;
if (internalDate && onSubmit) {
onSubmit(internalDate);
}
}
}
export default DateInput;
import Execution from 'model/kpi/Execution';
import ExecutionRun from 'model/kpi/ExecutionRun';
import Page from 'model/Page';
/*
* Defined in Swagger as '#/definitions/ExecutionDetails'
*/
class ExecutionDetails {
public execution: Execution;
public runs: ExecutionRun[];
public runs: Page<ExecutionRun>;
public lastRun: ExecutionRun;
}
......
......@@ -18,6 +18,7 @@ const URL_LIST_EXECUTION = `/api/v1/kpi/executions`;
const URL_SAVE_EXECUTION = `/api/v1/kpi/executions/save`;
const URL_EXECUTION_DETAILS = UrlTemplate.parse(`/api/v1/kpi/executions/{name}`);
const URL_DELETE_EXECUTION = UrlTemplate.parse(`/api/v1/kpi/executions/{name}`);
const URL_EXECUTION_RUN_BY_DATE = UrlTemplate.parse(`/api/v1/kpi/executions/{name}/run`);
const URL_RUN_EXECUTION = UrlTemplate.parse(`/api/v1/kpi/executions/{name}/execute`);
const URL_EXECUTION_RUNS = UrlTemplate.parse(`/api/v1/kpi/executions/{name}/runs`);
const URL_EXECUTION_RUN = UrlTemplate.parse(`/api/v1/kpi/executions/{name}/runs/{runId}`);
......@@ -108,6 +109,28 @@ class KpiService {
}).then(({ data }) => data as Dimension<object>);
}
/**
* executionRunByDate at /api/v1/kpi/executions/{name}/run
*
* @param name name
* @param date date
*/
public static executionRunByDate(name: string, date: string): Promise<ExecutionRun> {
const qs = QueryString.stringify({
date: date || undefined,
}, {});
const apiUrl = URL_EXECUTION_RUN_BY_DATE.expand({name}) + (qs ? `?${qs}` : '');
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as ExecutionRun);
}
/**
* listExecutions at /api/v1/kpi/executions
*
......@@ -210,7 +233,7 @@ class KpiService {
* @param name name
* @param page undefined
*/
public static executionRuns(name: string, page?: IPageRequest): Promise<ExecutionRun[]> {
public static executionRuns(name: string, page?: IPageRequest): Promise<Page<ExecutionRun>> {
const qs = QueryString.stringify({
p: page.page || undefined,
......@@ -226,7 +249,7 @@ class KpiService {
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as ExecutionRun[]);
}).then(({ data }) => data as Page<ExecutionRun>);
}
/**
......
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