<commit_before>﻿import * as moment from 'moment'
import * as numbro from 'numbro'
import * as React from 'react'
import { Modal, ModalProps, ModalClass, ButtonToolbar, Tabs, Tab } from 'react-bootstrap'
import { openModal, IModalProps } from '../../../../Framework/Signum.React/Scripts/Modals';
import * as Finder from '../../../../Framework/Signum.React/Scripts/Finder';
import * as Navigator from '../../../../Framework/Signum.React/Scripts/Navigator';
import { Dic } from '../../../../Framework/Signum.React/Scripts/Globals';
import { SelectorMessage, JavascriptMessage } from '../../../../Framework/Signum.React/Scripts/Signum.Entities'
import { TypeInfo, TypeReference, Binding } from '../../../../Framework/Signum.React/Scripts/Reflection'
import { FormGroupStyle, TypeContext } from '../../../../Framework/Signum.React/Scripts/TypeContext'
import { ValueLineType, ValueLine } from '../../../../Framework/Signum.React/Scripts/Lines/ValueLine'
import { CaseActivityStats } from "../WorkflowClient";
import { FormGroup, StyleContext } from "../../../../Framework/Signum.React/Scripts/Lines";
import { CaseActivityEntity, WorkflowActivityEntity, WorkflowActivityMessage, DoneType, CaseNotificationEntity, CaseActivityMessage, WorkflowActivityType, CaseEntity } from "../Signum.Entities.Workflow";
import { EntityLink, SearchControl } from "../../../../Framework/Signum.React/Scripts/Search";
import { OperationLogEntity } from "../../../../Framework/Signum.React/Scripts/Signum.Entities.Basics";


interface CaseActivityStatsModalProps extends React.Props<CaseActivityStatsModal>, IModalProps {
    case: CaseEntity;
    caseActivityStats: CaseActivityStats[];
}

export default class CaseActivityStatsModal extends React.Component<CaseActivityStatsModalProps, { show: boolean }>  {

    constructor(props: CaseActivityStatsModalProps) {
        super(props);

        this.state = {
            show: true,
        };
    }

    handleCloseClicked = () => {
        this.setState({ show: false });
    }

    handleOnExited = () => {
        this.props.onExited!(undefined);
    }

    render() {

        var caseActivityStats = this.props.caseActivityStats;
        return <Modal bsSize="lg" onHide={this.handleCloseClicked} show={this.state.show} onExited={this.handleOnExited}>

            <Modal.Header closeButton={true}>
                <h4 className="modal-title">
                    {caseActivityStats.first().WorkflowActivity.toStr} ({caseActivityStats.length} {caseActivityStats.length == 1 ? CaseActivityEntity.niceName() : CaseActivityEntity.nicePluralName()})
                </h4>
            </Modal.Header>

            <Modal.Body>
                {
                    <div>
                        {caseActivityStats.length == 1 ? <CaseActivityStatsComponent stats={caseActivityStats.first()} caseEntity={this.props.case} /> :
                            <Tabs id="statsTabs">
                                {
                                    caseActivityStats.map(a =>
                                        <Tab key={a.CaseActivity.id} eventKey={a.CaseActivity.id} title={
                                            a.DoneDate == null ? CaseActivityMessage.Pending.niceToString() :
                                                <span>{a.DoneBy.toStr} {DoneType.niceToString(a.DoneType!)} <mark>({moment(a.DoneDate).fromNow()})</mark></span> as any}>
                                            <CaseActivityStatsComponent stats={a} caseEntity={this.props.case} />
                                        </Tab>)
                                }
                            </Tabs>
                        }
                    </div>
                }

            </Modal.Body>
            <Modal.Footer>
                <button className="btn btn-primary sf-entity-button sf-ok-button" onClick={this.handleCloseClicked}>
                    {JavascriptMessage.ok.niceToString()}
                </button>
            </Modal.Footer>
        </Modal>;
    }

    static show(caseEntity: CaseEntity, caseActivityStats: CaseActivityStats[]): Promise<any> {
        return openModal<any>(<CaseActivityStatsModal case={caseEntity} caseActivityStats={caseActivityStats} />);
    }
}

interface CaseActivityStatsComponentProps {
    caseEntity: CaseEntity;
    stats: CaseActivityStats;
}

export class CaseActivityStatsComponent extends React.Component<CaseActivityStatsComponentProps> {
    render() {

        var ctx = new StyleContext(undefined, { labelColumns: 3 });
        var stats = this.props.stats;
        
        return (
            <div className="form-horizontal" >
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.niceName()}> <EntityLink lite={stats.CaseActivity} /></FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.doneBy)}>{stats.DoneBy && <EntityLink lite={stats.DoneBy} />}</FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.startDate)}>{formatDate(stats.StartDate)}</FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.doneDate)}>{formatDate(stats.DoneDate)}</FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.doneType)}>{DoneType.niceToString(stats.DoneType!)}</FormGroup>
                <FormGroup ctx={ctx} labelText={WorkflowActivityEntity.nicePropertyName(a => a.estimatedDuration)}>{formatDuration(stats.EstimatedDuration)}</FormGroup>
                <FormGroup ctx={ctx} labelText={WorkflowActivityMessage.AverageDuration.niceToString()}>{formatDuration(stats.AverageDuration)}</FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.duration)}>{formatDuration(stats.Duration)}</FormGroup>
                <FormGroup ctx={ctx} labelText={WorkflowActivityType.niceName()}>{WorkflowActivityType.niceToString(stats.WorkflowActivityType)}</FormGroup>
                {
                    stats.WorkflowActivityType == "Task" || stats.WorkflowActivityType == "Decision" ? this.renderTaskExtra() :
                        stats.WorkflowActivityType == "Script" ? this.renderScriptTaskExtra() :
                            stats.WorkflowActivityType == "CallWorkflow" || stats.WorkflowActivityType == "DecompositionWorkflow" ? this.renderSubWorkflowExtra(ctx) :
                                undefined

                }
            </div>
        );
    }

    renderTaskExtra() {
        var stats = this.props.stats;

        return (
            <div>
                <h3>{CaseNotificationEntity.nicePluralName()}</h3>
                <SearchControl findOptions={{ queryName: CaseNotificationEntity, parentColumn: "CaseActivity", parentValue: stats.CaseActivity }} />
            </div>
        );
    }

    renderScriptTaskExtra() {
        var stats = this.props.stats;

        return (
            <div>
                <h3>{OperationLogEntity.nicePluralName()}</h3>
                <SearchControl findOptions={{ queryName: OperationLogEntity, parentColumn: "Target", parentValue: stats.CaseActivity }} />
            </div>
        );
    }

    handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
        e.preventDefault();
        Finder.fetchEntitiesWithFilters(CaseEntity, [
            { columnName: "Entity.DecompositionSurrogateActivity", value: this.props.stats.CaseActivity }
        ], [], 2)
            .then(cases => Navigator.navigate(cases.single()))
            .done();
    }

    renderSubWorkflowExtra(ctx: StyleContext) {
        var stats = this.props.stats;

        return (
            <FormGroup ctx={ctx}>
                <button className="btn btn-default" onClick={this.handleClick}>
                    <i className="fa fa-random" style={{ color: "green" }} /> {WorkflowActivityMessage.CaseFlow.niceToString()}
                </button>
            </FormGroup>
        );
    }
}

function formatDate(date: string | undefined) {
    return <span>{moment(date).format("L LT")} <mark>({moment(date).fromNow()})</mark></span>
}

function formatDuration(duration: number | undefined) {
    if (duration == undefined)
        return undefined;

    var unit = CaseActivityEntity.memberInfo(a => a.duration).unit;

    return <span>{numbro(duration).format("0.00")} {unit} <mark>({moment.duration(duration, "minutes").format("d[d] h[h] m[m] s[s]")})</mark></span>
}



<commit_msg>fix CaseFlow button click for decomposition workflows<commit_after>﻿import * as moment from 'moment'
import * as numbro from 'numbro'
import * as React from 'react'
import { Modal, ModalProps, ModalClass, ButtonToolbar, Tabs, Tab } from 'react-bootstrap'
import { openModal, IModalProps } from '../../../../Framework/Signum.React/Scripts/Modals';
import * as Finder from '../../../../Framework/Signum.React/Scripts/Finder';
import * as Navigator from '../../../../Framework/Signum.React/Scripts/Navigator';
import { Dic } from '../../../../Framework/Signum.React/Scripts/Globals';
import { SelectorMessage, JavascriptMessage } from '../../../../Framework/Signum.React/Scripts/Signum.Entities'
import { TypeInfo, TypeReference, Binding } from '../../../../Framework/Signum.React/Scripts/Reflection'
import { FormGroupStyle, TypeContext } from '../../../../Framework/Signum.React/Scripts/TypeContext'
import { ValueLineType, ValueLine } from '../../../../Framework/Signum.React/Scripts/Lines/ValueLine'
import { CaseActivityStats } from "../WorkflowClient";
import { FormGroup, StyleContext } from "../../../../Framework/Signum.React/Scripts/Lines";
import { CaseActivityEntity, WorkflowActivityEntity, WorkflowActivityMessage, DoneType, CaseNotificationEntity, CaseActivityMessage, WorkflowActivityType, CaseEntity } from "../Signum.Entities.Workflow";
import { EntityLink, SearchControl } from "../../../../Framework/Signum.React/Scripts/Search";
import { OperationLogEntity } from "../../../../Framework/Signum.React/Scripts/Signum.Entities.Basics";
import * as SelectorModal from "../../../../Framework/Signum.React/Scripts/SelectorModal";


interface CaseActivityStatsModalProps extends React.Props<CaseActivityStatsModal>, IModalProps {
    case: CaseEntity;
    caseActivityStats: CaseActivityStats[];
}

export default class CaseActivityStatsModal extends React.Component<CaseActivityStatsModalProps, { show: boolean }>  {

    constructor(props: CaseActivityStatsModalProps) {
        super(props);

        this.state = {
            show: true,
        };
    }

    handleCloseClicked = () => {
        this.setState({ show: false });
    }

    handleOnExited = () => {
        this.props.onExited!(undefined);
    }

    render() {

        var caseActivityStats = this.props.caseActivityStats;
        return <Modal bsSize="lg" onHide={this.handleCloseClicked} show={this.state.show} onExited={this.handleOnExited}>

            <Modal.Header closeButton={true}>
                <h4 className="modal-title">
                    {caseActivityStats.first().WorkflowActivity.toStr} ({caseActivityStats.length} {caseActivityStats.length == 1 ? CaseActivityEntity.niceName() : CaseActivityEntity.nicePluralName()})
                </h4>
            </Modal.Header>

            <Modal.Body>
                {
                    <div>
                        {caseActivityStats.length == 1 ? <CaseActivityStatsComponent stats={caseActivityStats.first()} caseEntity={this.props.case} /> :
                            <Tabs id="statsTabs">
                                {
                                    caseActivityStats.map(a =>
                                        <Tab key={a.CaseActivity.id} eventKey={a.CaseActivity.id} title={
                                            a.DoneDate == null ? CaseActivityMessage.Pending.niceToString() :
                                                <span>{a.DoneBy.toStr} {DoneType.niceToString(a.DoneType!)} <mark>({moment(a.DoneDate).fromNow()})</mark></span> as any}>
                                            <CaseActivityStatsComponent stats={a} caseEntity={this.props.case} />
                                        </Tab>)
                                }
                            </Tabs>
                        }
                    </div>
                }

            </Modal.Body>
            <Modal.Footer>
                <button className="btn btn-primary sf-entity-button sf-ok-button" onClick={this.handleCloseClicked}>
                    {JavascriptMessage.ok.niceToString()}
                </button>
            </Modal.Footer>
        </Modal>;
    }

    static show(caseEntity: CaseEntity, caseActivityStats: CaseActivityStats[]): Promise<any> {
        return openModal<any>(<CaseActivityStatsModal case={caseEntity} caseActivityStats={caseActivityStats} />);
    }
}

interface CaseActivityStatsComponentProps {
    caseEntity: CaseEntity;
    stats: CaseActivityStats;
}

export class CaseActivityStatsComponent extends React.Component<CaseActivityStatsComponentProps> {
    render() {

        var ctx = new StyleContext(undefined, { labelColumns: 3 });
        var stats = this.props.stats;
        
        return (
            <div className="form-horizontal" >
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.niceName()}> <EntityLink lite={stats.CaseActivity} /></FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.doneBy)}>{stats.DoneBy && <EntityLink lite={stats.DoneBy} />}</FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.startDate)}>{formatDate(stats.StartDate)}</FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.doneDate)}>{formatDate(stats.DoneDate)}</FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.doneType)}>{stats.DoneType && DoneType.niceToString(stats.DoneType)}</FormGroup>
                <FormGroup ctx={ctx} labelText={WorkflowActivityEntity.nicePropertyName(a => a.estimatedDuration)}>{formatDuration(stats.EstimatedDuration)}</FormGroup>
                <FormGroup ctx={ctx} labelText={WorkflowActivityMessage.AverageDuration.niceToString()}>{formatDuration(stats.AverageDuration)}</FormGroup>
                <FormGroup ctx={ctx} labelText={CaseActivityEntity.nicePropertyName(a => a.duration)}>{formatDuration(stats.Duration)}</FormGroup>
                <FormGroup ctx={ctx} labelText={WorkflowActivityType.niceName()}>{WorkflowActivityType.niceToString(stats.WorkflowActivityType)}</FormGroup>
                {
                    stats.WorkflowActivityType == "Task" || stats.WorkflowActivityType == "Decision" ? this.renderTaskExtra() :
                        stats.WorkflowActivityType == "Script" ? this.renderScriptTaskExtra() :
                            stats.WorkflowActivityType == "CallWorkflow" || stats.WorkflowActivityType == "DecompositionWorkflow" ? this.renderSubWorkflowExtra(ctx) :
                                undefined

                }
            </div>
        );
    }

    renderTaskExtra() {
        var stats = this.props.stats;

        return (
            <div>
                <h3>{CaseNotificationEntity.nicePluralName()}</h3>
                <SearchControl findOptions={{ queryName: CaseNotificationEntity, parentColumn: "CaseActivity", parentValue: stats.CaseActivity }} />
            </div>
        );
    }

    renderScriptTaskExtra() {
        var stats = this.props.stats;

        return (
            <div>
                <h3>{OperationLogEntity.nicePluralName()}</h3>
                <SearchControl findOptions={{ queryName: OperationLogEntity, parentColumn: "Target", parentValue: stats.CaseActivity }} />
            </div>
        );
    }

    handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
        e.preventDefault();
        Finder.fetchEntitiesWithFilters(CaseEntity, [
            { columnName: "Entity.DecompositionSurrogateActivity", value: this.props.stats.CaseActivity }
        ], [], 2)
            .then(cases => {

                if (cases.length == 1)
                    Navigator.navigate(cases.single());
                else
                    Finder.find<CaseEntity>({
                        queryName: CaseEntity,
                        filterOptions: [{ columnName: "Entity.DecompositionSurrogateActivity", value: this.props.stats.CaseActivity, frozen: true }]
                    })
                        .then(c => c && Navigator.navigate(c));
            })
            .done();
    }

    renderSubWorkflowExtra(ctx: StyleContext) {
        var stats = this.props.stats;

        return (
            <FormGroup ctx={ctx}>
                <button className="btn btn-default" onClick={this.handleClick}>
                    <i className="fa fa-random" style={{ color: "green" }} /> {WorkflowActivityMessage.CaseFlow.niceToString()}
                </button>
            </FormGroup>
        );
    }
}

function formatDate(date: string | undefined) {
    if (date == undefined)
        return undefined;

    return <span>{moment(date).format("L LT")} <mark>({moment(date).fromNow()})</mark></span>
}

function formatDuration(duration: number | undefined) {
    if (duration == undefined)
        return undefined;

    var unit = CaseActivityEntity.memberInfo(a => a.duration).unit;

    return <span>{numbro(duration).format("0.00")} {unit} <mark>({moment.duration(duration, "minutes").format("d[d] h[h] m[m] s[s]")})</mark></span>
}




{'fraction_non_alphanumeric': 0.1376303641648145, 'fraction_numerical': 0.001538724568302274, 'mean_word_length': 2.410689990281827, 'pattern_counts': {'":': 0, '<': 156, '<?xml version=': 0, '>': 181, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '417190', 'n_tokens_mistral': 4640, 'n_tokens_neox': 4549, 'n_words': 768}