Skip to content

Commit

Permalink
feat(netflix): move app fast properties to tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
anotherchrisberry committed May 9, 2017
1 parent bc24c00 commit 6f769a0
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 205 deletions.
36 changes: 35 additions & 1 deletion app/scripts/modules/netflix/fastProperties/fastProperties.less
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
}

.fast-property-wrapper {
margin-left: 22px;
}

.scrollable-columns .nav-content.global-properties-container {
Expand All @@ -18,6 +17,40 @@
}

.fast-properties {
.nav.nav-tabs {
width: 100%;
padding: 0;
border: 1px solid @light_grey;
overflow-x: visible;
background-color: transparent;
box-shadow: 0 5px 4px -4px @mid_lighter_grey;
h4 {
margin-top: 0;
}
a {
border-radius: 0;
border: none;
color: @default_link_hover;
.badge {
margin: -2px 0 0 3px;
padding: 2px 5px;
}
}
li.active {
a {
background-color: @spinnaker-link-color;
color: #ffffff;
&:hover, &:active {
border: 0;
color: #ffffff;
}
.badge {
color: @default_link_hover;
background-color: #ffffff;
}
}
}
}
.header {
margin-bottom: 10px;
h3 {
Expand Down Expand Up @@ -52,6 +85,7 @@
margin-top: 5px;
}
.properties-container {
padding-top: 10px;
overflow-y: auto;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ module(FAST_PROPERTY_STATES, [
dynamic: true,
value: null,
};
filterParams.tab = {
dynamic: true,
};

const detailsView = {
templateUrl: require('./view/details/fastPropertyDetails.html'),
Expand Down Expand Up @@ -77,7 +80,7 @@ module(FAST_PROPERTY_STATES, [
*/
const applicationFastProperties: INestedState = {
name: 'properties',
url: `/properties?propertyId&sortBy&${stateConfigProvider.paramsToQuery(filterParamsConfig)}`,
url: `/properties?propertyId&sortBy&tab&${stateConfigProvider.paramsToQuery(filterParamsConfig)}`,
views: {
'master': {
template: '<application-fast-properties application="app" class="flex-fill"></application-fast-properties>',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,10 @@ export class FastPropertyReaderService {
)
}

public waitForPromotionPipelineToAppear(application: Application, executionId: string): IPromise<IExecution> {
public waitForPromotionPipelineToAppear(application: Application, executionId: string, matcher?: (e: IExecution) => boolean): IPromise<IExecution> {
matcher = matcher || (() => true);
return this.getPromotionsForApplication(application.name, ['RUNNING', 'SUCCEEDED', 'TERMINAL']).then((executions: IExecution[]) => {
const match = executions.find(e => e.id === executionId);
const match = executions.find(e => e.id === executionId && matcher(e));
const deferred = this.$q.defer<IExecution>();
if (match) {
if (!application.global) {
Expand All @@ -139,7 +140,7 @@ export class FastPropertyReaderService {
return deferred.promise;
} else {
return this.$timeout(() => {
return this.waitForPromotionPipelineToAppear(application, executionId);
return this.waitForPromotionPipelineToAppear(application, executionId, matcher);
}, 2000);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import { NetflixSettings } from 'netflix/netflix.settings';
import { ApplicationDataSource } from 'core/application/service/applicationDataSource';
import { FastPropertyRollouts } from './rollouts/FastPropertyRollouts';
import { FastPropertiesList } from './FastPropertiesList';
import { StickyContainer } from 'core/utils/stickyHeader/StickyContainer';
import { FastPropertyFilterSearch } from './filter/FastPropertyFilterSearch';
import { IFilterTag, FilterTags } from 'core/filterModel/FilterTags';
import { modalService } from 'core/modal.service';
import { $stateParams } from 'core/uirouter';
import { $stateParams, $state } from 'core/uirouter';
import { stateEvents } from 'core/state.events';
import { sortProperties } from '../global/GlobalPropertiesList';

Expand All @@ -30,7 +29,9 @@ interface IState {
filters: IFilterTag[];
filteredProperties: Property[];
allProperties?: Property[];
runningPromotionsCount: number;
sortBy: string;
activeSection: string;
}

@autoBindMethods
Expand All @@ -39,32 +40,54 @@ export class ApplicationProperties extends React.Component<IProps, IState> {
private filtersUpdatedStream: Subject<IFilterTag[]> = new Subject<IFilterTag[]>();
private dataSourceUnsubscribe: () => any;
private dataSource: ApplicationDataSource;
private runningDataSource: ApplicationDataSource;
private runningDataSourceUnsubscribe: () => any;
private stateChangeListener: Subscription;

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

this.runningDataSource = this.props.application.getDataSource('runningPropertyPromotions');

this.state = {
enabled: NetflixSettings.feature.fastProperty,
loading: true,
filters: [],
filteredProperties: [],
sortBy: $stateParams.sortBy || 'key'
allProperties: [],
sortBy: $stateParams.sortBy || 'key',
activeSection: $stateParams.tab || 'properties',
runningPromotionsCount: this.runningDataSource.data.length,
};
this.dataSource = this.props.application.getDataSource('properties');
}

public componentDidMount() {
this.dataSource.activate();
this.dataSource.ready().then(() => this.dataUpdated());
this.dataSourceUnsubscribe = this.dataSource.onRefresh(null,
() => this.dataUpdated(),
() => this.dataLoadError(),
);

this.runningDataSourceUnsubscribe = this.runningDataSource.onRefresh(null,
() => this.setState({runningPromotionsCount: this.runningDataSource.data.length})
);
this.filtersUpdatedStream.subscribe((newTags) => this.applyFilters(newTags));
this.stateChangeListener = stateEvents.stateChangeSuccess.subscribe(() => this.applyFilters(this.state.filters));
this.stateChangeListener = stateEvents.stateChangeSuccess.subscribe(
() => {
const activeSection = $stateParams.tab || 'properties';
this.setState({activeSection});
this.applyFilters(this.state.filters);
}
);
}

public componentWillUnmount() {
this.filtersUpdatedStream = null;
this.stateChangeListener.unsubscribe();
this.dataSourceUnsubscribe();
this.runningDataSourceUnsubscribe();
this.dataSource.deactivate();
}

Expand Down Expand Up @@ -108,40 +131,66 @@ export class ApplicationProperties extends React.Component<IProps, IState> {
});
}

private handleSelect(event: React.MouseEvent<HTMLElement>): void {
const activeSection = (event.currentTarget as HTMLElement).getAttribute('data-section');
$state.go('.', {tab: activeSection});
}

public render() {
if (this.state.loading) {
return <h3 className="text-center"><span className="fa fa-cog fa-spin"/></h3>;
}

const { application } = this.props;
const { filters, allProperties, filteredProperties } = this.state;

const runningCount = this.state.runningPromotionsCount;

return (
<div className="flex-fill">
{this.state.loading && (<h3 className="text-center"><span className="fa fa-cog fa-spin"/></h3>)}
{!this.state.loading && (
<div className="fast-properties flex-fill">
<div className="form form-inline header">
<div className="form-group">
<h3>Properties</h3>
<FastPropertyFilterSearch properties={this.state.allProperties} filtersUpdatedStream={this.filtersUpdatedStream}/>
</div>
<div className="form-group pull-right">
<button className="btn btn-sm btn-default" onClick={this.createFastProperty} style={{margin: '3px'}}>
<span className="glyphicon glyphicon-plus-sign visible-lg-inline"/>
<Tooltip value="Create Fast Property" id="createFastProperty">
<span className="glyphicon glyphicon-plus-sign visible-md-inline visible-sm-inline"/>
</Tooltip>
<span className="visible-lg-inline"> Create Fast Property</span>
</button>
</div>

<div className="fast-property-filter-tags">
<FilterTags tags={filters} clearFilters={this.clearFilters}/>
</div>
</div>
<StickyContainer className="flex-fill properties-container">
<FastPropertyRollouts application={application} filters={filters} filtersUpdatedStream={this.filtersUpdatedStream}/>
<FastPropertiesList groupedBy="none" application={application} allProperties={allProperties} filteredProperties={filteredProperties}/>
</StickyContainer>
<div className="fast-properties flex-fill">
<div className="form form-inline header">
<div className="form-group">
<h3>Properties</h3>
<FastPropertyFilterSearch properties={this.state.allProperties} filtersUpdatedStream={this.filtersUpdatedStream}/>
</div>
<div className="form-group pull-right">
<button className="btn btn-sm btn-default" onClick={this.createFastProperty} style={{margin: '3px'}}>
<span className="glyphicon glyphicon-plus-sign visible-lg-inline"/>
<Tooltip value="Create Fast Property" id="createFastProperty">
<span className="glyphicon glyphicon-plus-sign visible-md-inline visible-sm-inline"/>
</Tooltip>
<span className="visible-lg-inline"> Create Fast Property</span>
</button>
</div>

<div className="fast-property-filter-tags">
<FilterTags tags={filters} clearFilters={this.clearFilters}/>
</div>
)}
</div>
<ul className="nav nav-tabs clickable">
<li className={this.state.activeSection === 'properties' ? 'active' : ''}>
<a data-section="properties" onClick={this.handleSelect}>
<h4>
Properties
</h4>
</a>
</li>
<li className={this.state.activeSection === 'rollouts' ? 'active' : ''}>
<a data-section="rollouts" onClick={this.handleSelect}>
<h4>
Rollouts {runningCount > 0 && (<span className="badge badge-running-count">{runningCount}</span>)}
</h4>
</a>
</li>
</ul>
<div className="flex-fill properties-container">
{this.state.activeSection === 'rollouts' && (
<FastPropertyRollouts application={application} filters={filters} filtersUpdatedStream={this.filtersUpdatedStream}/>
)}
{this.state.activeSection === 'properties' && (
<FastPropertiesList groupedBy="none" application={application} allProperties={allProperties} filteredProperties={filteredProperties}/>
)}
</div>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import * as React from 'react';
import autoBindMethods from 'class-autobind-decorator';

import { FastPropertyPods } from './FastPropertyPods';
import { Property } from '../domain/property.domain';
import { Application } from 'core/application/application.model';
import { collapsibleSectionStateCache } from 'core/cache/collapsibleSectionStateCache';
import { Sticky } from 'core/utils/stickyHeader/Sticky';
import { IGroupedProperties } from '../global/GlobalPropertiesList';

interface IProps {
Expand All @@ -17,61 +14,29 @@ interface IProps {
}

interface IState {
open: boolean,
}

export const MAX_PROPERTIES_TO_DISPLAY = 500;

@autoBindMethods
export class FastPropertiesList extends React.Component<IProps, IState> {

private sectionCacheKey = ['#global', 'fastProperty', 'properties'].join('#');

constructor(props: IProps) {
super(props);
this.sectionCacheKey = [this.props.application.name, 'fastProperty', 'properties'].join('#');
this.state = {
open: this.props.application.global || collapsibleSectionStateCache.isSet(this.sectionCacheKey) || collapsibleSectionStateCache.isExpanded(this.sectionCacheKey)
};
}

public toggleProperties(): void {
const open = !this.state.open;
this.setState({open});
collapsibleSectionStateCache.setExpanded(this.sectionCacheKey, open);
}

public render() {
const chevronClass = `small glyphicon toggle glyphicon-chevron-${this.state.open ? 'down' : 'right'}`;
const { filteredProperties, groupedProperties, groupedBy, application } = this.props;
const { filteredProperties, groupedProperties, groupedBy } = this.props;
const properties = groupedProperties || filteredProperties;
const isFiltered = filteredProperties.length < this.props.allProperties.length;
return (
<div>
{!application.global && (<Sticky className="clickable rollup-title sticky-header" onClick={this.toggleProperties}>
<span className={chevronClass}/>
<h4 className="shadowed">
Application Properties (
{isFiltered && (<span>{this.props.filteredProperties.length} of {this.props.allProperties.length}</span>)}
{!isFiltered && (<span>{this.props.allProperties.length}</span>)}
)
</h4>
</Sticky>)}
{this.state.open && (
<div className="fast-property-wrapper">
{this.props.filteredProperties.length > MAX_PROPERTIES_TO_DISPLAY && (
<div className="text-center">
<strong>Only showing the first {MAX_PROPERTIES_TO_DISPLAY} properties.</strong>
<div>Use the filters above to narrow down the list.</div>
</div>
)}
{this.props.filteredProperties.length > 0 && (
<div>
<FastPropertyPods properties={properties} groupedBy={groupedBy}/>
</div>
)}
</div>
)}
<div className="fast-property-wrapper">
{this.props.filteredProperties.length > MAX_PROPERTIES_TO_DISPLAY && (
<div className="text-center">
<strong>Only showing the first {MAX_PROPERTIES_TO_DISPLAY} properties.</strong>
<div>Use the filters above to narrow down the list.</div>
</div>
)}
{this.props.filteredProperties.length > 0 && (
<div>
<FastPropertyPods properties={properties} groupedBy={groupedBy}/>
</div>
)}
</div>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@import "~core/presentation/less/imports/commonImports.less";

.fast-properties {
&.global-rollouts {
.fast-property-promotions .executions {
Expand All @@ -13,7 +11,7 @@
}
}
.executions {
margin: 10px 20px 20px 40px;
margin: 10px 20px 20px 20px;
.trigger-type .execution-type {
display: none;
}
Expand Down
Loading

0 comments on commit 6f769a0

Please sign in to comment.