public render()

in src/FeatureTimeline/react/Components/FeatureTimelineGrid.tsx [170:527]


    public render(): JSX.Element {

        const {
            uiState,
            rawState,
            settingsState
        } = this.props;
        if (!rawState || uiState === UIStatus.Loading) {
            return (
                <Spinner size={SpinnerSize.large} className="loading-indicator" label="Loading..." />
            );
        }

        if (rawState.error) {
            return (
                <MessageBar
                    messageBarType={MessageBarType.error}
                    isMultiline={false}
                >
                    {rawState.error}
                </MessageBar>
            );
        }

        if (uiState === UIStatus.NoTeamIterations) {
            return (
                <MessageBar
                    messageBarType={MessageBarType.error}
                    isMultiline={false}
                >
                    {"The team does not have any iteration selected, please visit team admin page and select team iterations."}
                </MessageBar>
            );
        }

        if (uiState === UIStatus.NoWorkItems) {
            return (<MessageBar
                messageBarType={MessageBarType.info}
                isMultiline={false}
            >
                {"No in-progress Features for the timeline."}
            </MessageBar>);
        }

        const {
            emptyHeaderRow,
            iterationHeader,
            iterationShadow,
            workItems,
            separators,
            shadowForWorkItemId,
            iterationDisplayOptions,
            isSubGrid,
            teamIterations
        } = this.props.gridView;

        const columnHeading = iterationHeader.map((iteration, index) => {
            const style = getRowColumnStyle(iteration.dimension);
            return (
                <div className="columnheading" style={style}>
                    <IterationRenderer teamIterations={teamIterations} iteration={iteration.teamIteration} />
                </div>
            );

        });

        const shadows = iterationShadow.map((shadow, index) => {
            return (
                <IterationDropTarget
                    {...shadow}
                    isOverrideIterationInProgress={!!rawState.workItemOverrideIteration}
                    onOverrideIterationOver={this.props.dragHoverOverIteration.bind(this)}
                    changeIteration={this.props.changeIteration.bind(this)}
                    markInProgress={this.props.markInProgress.bind(this)}
                >
                    &nbsp;
                </IterationDropTarget>
            );
        });

        let workItemShadowCell = null;
        if (shadowForWorkItemId) {
            const workItem = workItems.filter(w => w.workItem.id === shadowForWorkItemId)[0];
            workItemShadowCell = (
                <WorkItemShadow dimension={workItem.dimension} twoRows={workItem.settingsState.showWorkItemDetails} />
            );
        }

        const workItemCells = workItems.filter(w => w.workItem.id).map(w => {
            return (
                <DraggableWorkItemRenderer
                    id={w.workItem.id}
                    title={w.workItem.title}
                    color={w.workItem.color}
                    isRoot={w.workItem.isRoot}
                    assignedTo={w.workItem.workItem.fields["System.AssignedTo"]}
                    iterationDuration={w.workItem.iterationDuration}
                    dimension={w.dimension}
                    onClick={id => this.props.launchWorkItemForm(id)}
                    showDetails={id => this.props.showDetails(id)}
                    overrideIterationStart={payload => this.props.overrideIterationStart(payload)}
                    overrideIterationEnd={() => this.props.overrideIterationEnd()}
                    allowOverrideIteration={w.allowOverrideIteration}
                    isSubGrid={this.props.gridView.isSubGrid}
                    progressIndicator={w.progressIndicator}
                    crop={w.crop}
                    workItemStateColor={w.workItem.workItemStateColor}
                    settingsState={w.settingsState}
                    efforts={w.workItem.efforts}
                    childrernWithNoEfforts={w.workItem.childrenWithNoEfforts}
                    isComplete={w.workItem.isComplete}
                    successors={w.workItem.successors}
                    predecessors={w.workItem.predecessors}
                    highlightPredecessorIcon={w.workItem.highlightPredecessorIcon}
                    highlighteSuccessorIcon={w.workItem.highlighteSuccessorIcon}
                    onHighlightDependencies={() => {}}
                    onDismissDependencies={() => {}}
                    teamFieldName={"System.AreaPath"}
                />
            );
        });

        const workItemSeparators = separators.map(d => {
            return (
                <ChildRowsSeparator {...d} />
            );
        });


        const extraColumns = this.props.gridView.hideParents ? [] : ['300px'];
        let min = '200px';
        if (isSubGrid) {
            min = '150px';
        }
        const gridStyle = getTemplateColumns(extraColumns, shadows.length, `minmax(${min}, 300px)`);

        let childDialog = null;
        if (this.props.childItems.length > 0) {
            const props = { ...this.props, id: this.props.childItems[0] };
            childDialog = <FeatureTimelineDialog {...props} />
        }

        let leftButton = <span className="non-button"></span>;
        if (iterationDisplayOptions && iterationDisplayOptions.startIndex > 0) {
            leftButton = (
                <IconButton
                    className="button"
                    onClick={() => this.props.shiftDisplayIterationLeft(teamIterations.length)}
                    iconProps={
                        {
                            iconName: "ChevronLeftSmall"
                        }
                    }
                >
                </IconButton>
            );
        }

        let rightButton = <span className="non-button"></span>;
        if (iterationDisplayOptions && iterationDisplayOptions.endIndex < (iterationDisplayOptions.totalIterations - 1)) {
            rightButton = (
                <IconButton
                    className="button"
                    onClick={() => this.props.shiftDisplayIterationRight(teamIterations.length)}
                    iconProps={
                        {
                            iconName: "ChevronRightSmall"
                        }
                    }
                >
                </IconButton>
            );
        }

        let displayOptions = null;
        let commandHeading = [];

        if (!isSubGrid && (iterationDisplayOptions || columnHeading.length > 3)) {
            let displayIterationCount = 0;
            if (iterationDisplayOptions) {
                displayIterationCount = iterationDisplayOptions.count;
            } else {
                displayIterationCount = teamIterations.length;
            }
            displayOptions = (
                <div className="iteration-options">
                    <div className="iteration-options-label">View Sprints: </div>
                    <InputNum
                        value={displayIterationCount}
                        min={1}
                        max={teamIterations.length}
                        step={1}
                        onChange={this._onViewChanged}
                    >
                    </InputNum>
                </div>
            );

            if (emptyHeaderRow.length === 1) {
                // Special case only one column
                let rowColumnStyle = getRowColumnStyle(emptyHeaderRow[0]);
                const commands = (
                    <div style={rowColumnStyle} className="single-column-commands">
                        <div className="command-left-section">
                            {leftButton}
                        </div>
                        <div className="command-right-section">
                            {rightButton}
                        </div>
                    </div>
                );

                commandHeading.push(commands);

            } else {
                // Add left button to first empty heading cell
                let rowColumnStyle = getRowColumnStyle(emptyHeaderRow[0]);
                const firstHeaderColumnCommand = (
                    <div style={rowColumnStyle} className="first-header-column-command">
                        {leftButton}
                    </div>
                );
                commandHeading.push(firstHeaderColumnCommand);

                // Add display options and right button on last empty heading cell
                rowColumnStyle = getRowColumnStyle(emptyHeaderRow[emptyHeaderRow.length - 1]);
                const lastHeaderColumnCommand = (
                    <div style={rowColumnStyle} className="last-header-column-command">
                        {rightButton}
                    </div>
                );
                commandHeading.push(lastHeaderColumnCommand);
            }
        }
        let progressTrackingCriteriaElement = null;
        const {
            showWorkItemDetails,
            progressTrackingCriteria,
            showClosedSinceDays
        } = settingsState;
        if (showWorkItemDetails) {
            const selectedKey = progressTrackingCriteria === ProgressTrackingCriteria.ChildWorkItems ? "child" : "efforts";
            progressTrackingCriteriaElement = (
                <div className="progress-options">
                    <div className="progress-options-label">Track Progress Using: </div>
                    <ComboBox
                        className="progress-options-dropdown"
                        selectedKey={selectedKey}
                        allowFreeform={false}
                        autoComplete='off'
                        options={
                            [
                                { key: 'child', text: 'Completed Stories' },
                                { key: 'efforts', text: 'Completed Efforts' }
                            ]
                        }
                        onChanged={this._onProgressTrackingCriteriaChanged}
                    >
                    </ComboBox>
                </div>
            );
        }

        const selectedKey = (showClosedSinceDays || '0').toString();

        const showClosedSinceDaysElement = (
            <div className="closed-since-options">
                <div className="show-closed-since-label">Closed Features: </div>
                <ComboBox
                    className="show-closed-since-dropdown"
                    selectedKey={selectedKey}
                    allowFreeform={false}
                    autoComplete='off'
                    options={
                        [
                            { key: '0', text: 'Do not show' },
                            { key: '30', text: 'Last 30 days' },
                            { key: '60', text: 'Last 60 days' },
                            { key: '90', text: 'Last 90 days' },
                            { key: '120', text: 'Last 120 days' },
                            { key: '180', text: 'Last 180 days' },
                            { key: '365', text: 'Last 1 year' },
                            { key: '9999', text: 'Forever (Slow)'}
                        ]
                    }
                    onChanged={this._onShowClosedSinceChanged}
                >
                </ComboBox>
            </div>
        );
        const commands = !isSubGrid && (
            <div className="header-commands">
                {displayOptions}

                <Checkbox
                    className="plan-feature-checkbox"
                    label={"Plan Features"}
                    onChange={this._onShowPlanFeaturesChanged}
                    checked={this.props.planFeaturesState.show} />

                <Checkbox
                    className="show-work-item-details-checkbox"
                    label={"Show Details"}
                    onChange={this._onShowWorkItemDetailsChanged}
                    checked={this.props.settingsState.showWorkItemDetails} />

                {progressTrackingCriteriaElement}
                {showClosedSinceDaysElement}

            </div>
        );

        const grid = (
            <div className="feature-timeline-main-container">
                <div className="container" style={gridStyle}>
                    {commandHeading}
                    {columnHeading}
                    {shadows}
                    {workItemShadowCell}
                    {workItemCells}
                    {workItemSeparators}
                    {childDialog}
                </div>
            </div>
        );

        let contents = grid;
        if (!isSubGrid && this.props.planFeaturesState.show) {
            let paneWidth = this.props.planFeaturesState.paneWidth;
            if (paneWidth > 25) {
                paneWidth = 25;
            }
            contents = (
                <SplitterLayout
                    customClassName={"timeline-splitter"}
                    secondaryInitialSize={paneWidth}
                    onSecondaryPaneSizeChange={this._onPaneWidthChanged}
                    percentage={true}
                    primaryMinSize="75"
                >
                    {grid}
                    <ConnectedWorkItemsList />

                </SplitterLayout>
            );
        }

        return (
            <div className="root-container">
                {!this.props.settingsState.dismissedPortfolioPlansBanner && 
                <PromotePortfolioPlansBanner onDismiss={this.props.dismissPortfolioPlansBanner}/>}
                {commands}
                {<div className="header-gap"></div>}
                {contents}
            </div>

        );
    }