提交 523a2552 编写于 作者: P Piotr Bryk

Merge branch 'master' into hyperkube

......@@ -80,17 +80,28 @@ func getReplicaSetPods(pods []api.Pod, limit int) *ReplicaSetPods {
for _, pod := range pods {
totalRestartCount := 0
replicaSetPodWithContainers := ReplicaSetPodWithContainers{
Name: pod.Name,
StartTime: pod.Status.StartTime,
Name: pod.Name,
StartTime: pod.Status.StartTime,
PodContainers: make([]PodContainer, 0),
}
for _, containerStatus := range pod.Status.ContainerStatuses {
podContainer := PodContainer{
Name: containerStatus.Name,
RestartCount: containerStatus.RestartCount,
}
podContainersByName := make(map[string]*PodContainer)
for _, container := range pod.Spec.Containers {
podContainer := PodContainer{Name: container.Name}
replicaSetPodWithContainers.PodContainers =
append(replicaSetPodWithContainers.PodContainers, podContainer)
totalRestartCount += containerStatus.RestartCount
podContainersByName[container.Name] = &(replicaSetPodWithContainers.
PodContainers[len(replicaSetPodWithContainers.PodContainers)-1])
}
for _, containerStatus := range pod.Status.ContainerStatuses {
podContainer, ok := podContainersByName[containerStatus.Name]
if ok {
podContainer.RestartCount = containerStatus.RestartCount
totalRestartCount += containerStatus.RestartCount
}
}
replicaSetPodWithContainers.TotalRestartCount = totalRestartCount
replicaSetPods.Pods = append(replicaSetPods.Pods, replicaSetPodWithContainers)
......@@ -103,5 +114,6 @@ func getReplicaSetPods(pods []api.Pod, limit int) *ReplicaSetPods {
}
replicaSetPods.Pods = replicaSetPods.Pods[0:limit]
}
return replicaSetPods
}
......@@ -19,9 +19,13 @@
@return $multiplier * $font-size;
}
$headline-font-size-base: rem(2.4) !default;
$subhead-font-size-base: rem(1.6) !default;
$body-font-size-base: rem(1.4) !default;
$caption-font-size-base: rem(1.2) !default;
$primary: #326de6;
$warning: #ffa500;
$delicate: #aaa;
$muted: #888;
$hover-primary: #1254df;
......@@ -30,6 +34,11 @@ $emphasis: #000;
$content-background: #fff;
// TODO(bryk): Get those variables from Angular Material scss files.
$foreground-1: rgba(0, 0, 0, .87);
$foreground-2: rgba(0, 0, 0, .54);
$regular-font-weight: 400;
$layout-breakpoint-lg: 1280px;
$whiteframe-shadow-1dp: 0 1px 3px 0 rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .14), 0 2px 1px -1px rgba(0, 0, 0, .12);
$baseline-grid: 8px;
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import middleEllipsisFilter from './middleellipsis_filter';
import relativeTimeFilter from './relativetime_filter';
/**
* Module containing common filters for the application.
*/
export default angular.module(
'kubernetesDashboard.common.flters',
[
'ngMaterial',
])
.filter('middleEllipsis', middleEllipsisFilter)
.filter('relativeTime', relativeTimeFilter);
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* Unit name constants (singular and plural form), that will be used by the filter.
* @enum {!Array<string>}
*/
const Units = {
SECOND: ['a second', 'seconds'],
MINUTE: ['a minute', 'minutes'],
HOUR: ['an hour', 'hours'],
DAY: ['a day', 'days'],
MONTH: ['a month', 'months'],
YEAR: ['a year', 'years'],
};
/**
* Unit conversion constants.
* @enum {number}
*/
const UnitConversions = {
MILLISECONDS_PER_SECOND: 1000,
SECONDS_PER_MINUTE: 60,
MINUTES_PER_HOUR: 60,
HOURS_PER_DAY: 24,
DAYS_PER_MONTH: 30,
DAYS_PER_YEAR: 365,
MONTHS_PER_YEAR: 12,
};
/**
* Time constants.
* @enum {string}
*/
const TimeConstants = {
NOT_YET: `didn't happen yet`,
NOW: `just now`,
};
/**
* Returns filter function to display relative time since given date.
* @return {Function}
*/
export default function relativeTimeFilter() {
/**
* Filter function to display relative time since given date.
* @param {string} value Filtered value.
* @return {string}
*/
let filterFunction = function(value) {
// Current and given times in miliseconds.
let currentTime = (new Date()).getTime(); // TODO(maciaszczykm): Use server time.
let givenTime = (new Date(value)).getTime();
// Time differences between current time and given time in specific units.
let diffInMilliseconds = currentTime - givenTime;
let diffInSeconds = Math.floor(diffInMilliseconds / UnitConversions.MILLISECONDS_PER_SECOND);
let diffInMinutes = Math.floor(diffInSeconds / UnitConversions.SECONDS_PER_MINUTE);
let diffInHours = Math.floor(diffInMinutes / UnitConversions.MINUTES_PER_HOUR);
let diffInDays = Math.floor(diffInHours / UnitConversions.HOURS_PER_DAY);
let diffInMonths = Math.floor(diffInDays / UnitConversions.DAYS_PER_MONTH);
let diffInYears = Math.floor(diffInDays / UnitConversions.DAYS_PER_YEAR);
// Returns relative time value. Only biggest unit will be taken into consideration, so if time
// difference is 2 days and 15 hours, only '2 days' string will be returned.
if (diffInMilliseconds < 0) {
return TimeConstants.NOT_YET;
} else if (diffInSeconds < 1) {
return TimeConstants.NOW;
} else if (diffInMinutes < 1) {
return formatOutputTimeString_(diffInSeconds, Units.SECOND);
} else if (diffInHours < 1) {
return formatOutputTimeString_(diffInMinutes, Units.MINUTE);
} else if (diffInDays < 1) {
return formatOutputTimeString_(diffInHours, Units.HOUR);
} else if (diffInMonths < 1) {
return formatOutputTimeString_(diffInDays, Units.DAY);
} else if (diffInYears < 1) {
return formatOutputTimeString_(diffInMonths, Units.MONTH);
} else {
return formatOutputTimeString_(diffInYears, Units.YEAR);
}
};
return filterFunction;
}
/**
* Formats relative time string. Sample results look following: 'a year', '2 days' or '14 hours'.
* @param {number} timeValue Time value in specified unit.
* @param {!Array<string>} timeUnit Specified unit.
* @return {string} Formatted time string.
* @private
*/
function formatOutputTimeString_(timeValue, timeUnit) {
if (timeValue > 1) {
return `${timeValue} ${timeUnit[1]}`;
} else {
return timeUnit[0];
}
}
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import stateConfig from './deploy_state';
import stateConfig from './deploy_stateconfig';
import deployFromSettingsDirective from './deployfromsettings_directive';
import deployLabelDirective from './deploylabel_directive';
import deployFromFileDirective from './deployfromfile_directive';
......
......@@ -12,37 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import DeployController from './deploy_controller';
/** Name of the state. Can be used in, e.g., $state.go method. */
export const stateName = 'deploy';
/**
* Configures states for the deploy view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
$stateProvider.state(stateName, {
controller: DeployController,
controllerAs: 'ctrl',
url: '/deploy',
resolve: {
'namespaces': resolveNamespaces,
},
templateUrl: 'deploy/deploy.html',
});
}
/**
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveNamespaces($resource) {
/** @type {!angular.Resource<!backendApi.NamespaceList>} */
let resource = $resource('/api/namespaces');
return resource.get().$promise;
}
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import DeployController from './deploy_controller';
import {stateName} from './deploy_state';
/**
* Configures states for the deploy view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
$stateProvider.state(stateName, {
controller: DeployController,
controllerAs: 'ctrl',
url: '/deploy',
resolve: {
'namespaces': resolveNamespaces,
},
templateUrl: 'deploy/deploy.html',
});
}
/**
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveNamespaces($resource) {
/** @type {!angular.Resource<!backendApi.NamespaceList>} */
let resource = $resource('/api/namespaces');
return resource.get().$promise;
}
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import stateConfig from './logs_state';
import stateConfig from './logs_stateconfig';
import {LogColorInversionService} from './logs_service';
/**
......
......@@ -12,10 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import {LogsController} from './logs_controller';
import LogsToolbarController from './logstoolbar/logstoolbar_controller';
import {toolbarViewName} from '../chrome/chrome_state';
/** Name of the state. Can be used in, e.g., $state.go method. */
export const stateName = 'logs';
......@@ -46,59 +42,3 @@ export class StateParams {
this.container = container;
}
}
/**
* Configures states for the logs view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
let views = {
'': {
templateUrl: 'logs/logs.html',
controller: LogsController,
controllerAs: 'ctrl',
},
[toolbarViewName]: {
templateUrl: 'logs/logstoolbar/logstoolbar.html',
controller: LogsToolbarController,
controllerAs: 'ctrl',
},
};
$stateProvider.state(stateName, {
url: '/logs/:namespace/:replicaSet/:podId/:container',
resolve: {
'replicaSetPods': resolveReplicaSetPods,
'podLogs': resolvePodLogs,
},
views: views,
});
}
/**
* @param {!StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSetPods($stateParams, $resource) {
/** @type {!angular.Resource<!backendApi.ReplicaSetPods>} */
let resource = $resource('/api/replicasets/pods/:namespace/:replicaSet', $stateParams);
return resource.get().$promise;
}
/**
* @param {!StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolvePodLogs($stateParams, $resource) {
/** @type {!angular.Resource<!backendApi.Logs>} */
let resource = $resource('/api/logs/:namespace/:podId/:container', $stateParams);
return resource.get().$promise;
}
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {LogsController} from './logs_controller';
import {stateName} from './logs_state';
import LogsToolbarController from './logstoolbar/logstoolbar_controller';
import {toolbarViewName} from '../chrome/chrome_state';
/**
* Configures states for the logs view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
let views = {
'': {
templateUrl: 'logs/logs.html',
controller: LogsController,
controllerAs: 'ctrl',
},
[toolbarViewName]: {
templateUrl: 'logs/logstoolbar/logstoolbar.html',
controller: LogsToolbarController,
controllerAs: 'ctrl',
},
};
$stateProvider.state(stateName, {
url: '/logs/:namespace/:replicaSet/:podId/:container',
resolve: {
'replicaSetPods': resolveReplicaSetPods,
'podLogs': resolvePodLogs,
},
views: views,
});
}
/**
* @param {!./logs_state.StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSetPods($stateParams, $resource) {
/** @type {!angular.Resource<!backendApi.ReplicaSetPods>} */
let resource = $resource('/api/replicasets/pods/:namespace/:replicaSet', $stateParams);
return resource.get().$promise;
}
/**
* @param {!./logs_state.StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolvePodLogs($stateParams, $resource) {
/** @type {!angular.Resource<!backendApi.Logs>} */
let resource = $resource('/api/logs/:namespace/:podId/:container', $stateParams);
return resource.get().$promise;
}
......@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import {StateParams, stateName as logs} from './../logs_state';
/**
* Controller for the logs view.
* @final
......@@ -19,17 +21,17 @@
export default class LogsToolbarController {
/**
* @param {!ui.router.$state} $state
* @param {!StateParams} $stateParams
* @param {!backendApi.ReplicaSetPods} replicaSetPods
* @param {!../logs_service.LogColorInversionService} logsColorInversionService
* @ngInject
*/
constructor($state, replicaSetPods, logsColorInversionService) {
constructor($state, $stateParams, replicaSetPods, logsColorInversionService) {
/** @private {!ui.router.$state} */
this.state_ = $state;
// TODO(zreigz): should be StateParam but can not be import from logstoolbar_state. Issue 153.
/** @private {!Object.<string, string, string, string>|null} */
this.params = this.state_.params;
/** @private {!StateParams} */
this.params = $stateParams;
/**
* Service to notify logs controller if any changes on toolbar.
......@@ -86,13 +88,8 @@ export default class LogsToolbarController {
* @export
*/
onPodChange(podId) {
// TODO(zreigz): state name and StateParam can not be import from logstoolbar_state. Issue 153.
return this.state_.transitionTo("logs", {
namespace: this.namespace,
replicaSet: this.replicaSetName,
podId: podId,
container: this.container.name,
});
return this.state_.transitionTo(
logs, new StateParams(this.namespace, this.replicaSetName, podId, this.container.name));
}
/**
......@@ -102,13 +99,8 @@ export default class LogsToolbarController {
* @export
*/
onContainerChange(container) {
// TODO(zreigz): state name and StateParam can not be import from logstoolbar_state. Issue 153.
return this.state_.transitionTo("logs", {
namespace: this.namespace,
replicaSet: this.replicaSetName,
podId: this.pod.name,
container: container,
});
return this.state_.transitionTo(
logs, new StateParams(this.namespace, this.replicaSetName, this.pod.name, container));
}
/**
......
......@@ -20,7 +20,7 @@ limitations under the License.
<a flex-offset="10" ui-sref="replicasets">
<i class="material-icons kd-replicasetdetail-sidebar-header-icon">keyboard_backspace</i>
</a>
<span flex-offset="5" flex class="md-title">
<span flex-offset="5" flex class="md-title kd-replicasetdetail-app-name">
{{ctrl.replicaSetDetail.name}}
</span>
</div>
......@@ -165,7 +165,8 @@ limitations under the License.
{{pod.restartCount}}<!-- TODO(maciaszczykm): Add info about last restart date. -->
</td>
<td class="kd-replicasetdetail-table-cell">
{{pod.startTime | date:'short'}}<!-- TODO(maciaszczykm): Format data. -->
{{pod.startTime | relativeTime}}
<md-tooltip>{{pod.startTime | date:'short'}}</md-tooltip>
</td>
<td class="kd-replicasetdetail-table-cell">
0.4 CPU<!-- TODO(maciaszczykm): Fill with data and plot. -->
......@@ -176,7 +177,7 @@ limitations under the License.
<td class="kd-replicasetdetail-table-cell">{{pod.podIP}}</td>
<td class="kd-replicasetdetail-table-cell">{{pod.nodeName}}</td>
<td class="kd-replicasetdetail-table-cell">
Logs <i class="material-icons kd-replicasetdetail-logs-icon">arrow_drop_down</i>
Logs <i class="material-icons kd-replicasetdetail-table-icon">arrow_drop_down</i>
<!-- TODO(maciaszczykm): Handle it. -->
</td>
<td class="kd-replicasetdetail-table-cell">
......@@ -265,13 +266,13 @@ limitations under the License.
</thead>
<tbody>
<tr ng-repeat="event in ctrl.events | orderBy:ctrl.sortEventsBy:ctrl.eventsOrder">
<td class="kd-replicasetdetail-table-cell kd-replicasetdetail-table-message">
<td class="kd-replicasetdetail-table-message">
<i ng-if="ctrl.isEventWarning(event)"
class="material-icons kd-replicasetdetail-warning-icon">warning</i>
{{event.message}}
</td>
<td class="kd-replicasetdetail-table-cell">
{&lt;!&gt;{{event.sourceComponent}} {{event.sourceHost}}&lt;!&gt;}
{{event.sourceComponent}} {{event.sourceHost}}
</td>
<td class="kd-replicasetdetail-table-cell">{{event.object}}</td>
<td class="kd-replicasetdetail-table-cell">{{event.count}}</td>
......
......@@ -18,7 +18,11 @@ $replicasetdetails-sidebar-bg: #fafafa;
$replicasetdetails-border: #ddd;
$replicasetdetails-table-message: #000;
$replicasetdetails-table-cell: #777;
$replicasetdetails-warning: #ffa500;
.kd-replicasetdetail-app-name {
color: $foreground-2;
font-weight: $regular-font-weight;
}
.kd-replicasetdetail-sidebar {
background-color: $replicasetdetails-sidebar-bg;
......@@ -37,33 +41,41 @@ $replicasetdetails-warning: #ffa500;
}
.kd-replicasetdetail-sidebar-header-icon {
font-size: 1.7em;
color: $muted;
font-size: $headline-font-size-base;
font-weight: $regular-font-weight;
margin-right: 6px;
vertical-align: middle;
}
.kd-replicasetdetail-table-message {
border-bottom: 1px solid $replicasetdetails-border;
color: $replicasetdetails-table-message;
font-size: $caption-font-size-base;
font-weight: $regular-font-weight;
height: 40px;
overflow: hidden;
padding: 5px 5px 5px 15px;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
}
.kd-replicasetdetail-sidebar-title {
font-size: 15px;
font-size: $subhead-font-size-base;
padding-bottom: 10px;
padding-top: 10px;
}
.kd-replicasetdetail-sidebar-line {
color: $delicate;
font-size: 11px;
font-size: $caption-font-size-base;
padding-bottom: 6px;
}
.kd-replicasetdetail-sidebar-subline {
color: $muted;
font-size: 13px;
font-size: $caption-font-size-base;
padding-bottom: 8px;
}
......@@ -75,7 +87,7 @@ $replicasetdetails-warning: #ffa500;
}
.kd-replicasetdetail-warning-icon {
color: $replicasetdetails-warning;
color: $warning;
font-size: 24px;
padding: 0 5px;
vertical-align: middle;
......@@ -83,7 +95,7 @@ $replicasetdetails-warning: #ffa500;
.kd-replicasetdetail-sidebar-service-icon {
color: $muted;
font-size: 14px;
font-size: $body-font-size-base;
padding: 0 3px;
vertical-align: top;
}
......@@ -119,8 +131,8 @@ $replicasetdetails-warning: #ffa500;
.kd-replicasetdetail-table-header {
border-bottom: 1px solid $replicasetdetails-border;
color: $replicasetdetails-table-cell;
font-size: 14px;
font-weight: 500;
font-size: $body-font-size-base;
font-weight: $regular-font-weight;
padding: 15px 10px 15px 15px;
text-align: left;
}
......@@ -132,13 +144,13 @@ $replicasetdetails-warning: #ffa500;
.kd-replicasetdetail-table-cell {
border-bottom: 1px solid $replicasetdetails-border;
color: $replicasetdetails-table-cell;
font-size: 13px;
font-size: $caption-font-size-base;
height: 40px;
padding: 5px 5px 5px 15px;
}
.kd-replicasetdetail-table-icon {
font-size: 14px;
font-size: $body-font-size-base;
padding: 0 3px;
vertical-align: top;
}
......@@ -146,7 +158,7 @@ $replicasetdetails-warning: #ffa500;
.kd-replicasetdetail-help-icon {
color: $muted;
cursor: help;
font-size: 14px;
font-size: $body-font-size-base;
padding: 0 3px;
vertical-align: middle;
}
......@@ -15,6 +15,7 @@
import showDeleteReplicaSetDialog from 'replicasetdetail/deletereplicaset_dialog';
import showUpdateReplicasDialog from 'replicasetdetail/updatereplicas_dialog';
import {UPWARDS, DOWNWARDS} from 'replicasetdetail/sortedheader_controller';
import {stateName as replicasets} from 'replicasetlist/replicasetlist_state';
// Filter type and source values for events.
const EVENT_ALL = 'All';
......@@ -226,8 +227,7 @@ export default class ReplicaSetDetailController {
*/
onReplicaSetDeleteSuccess_() {
this.log_.info('Replica set successfully deleted.');
// State name can not be imported. Related issue: #153
this.state_.go('replicasets');
this.state_.go(replicasets);
}
/**
......
......@@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import filtersModule from 'common/filters/filters_module';
import serviceEndpointDirective from './serviceendpoint_directive';
import stateConfig from './replicasetdetail_state';
import stateConfig from './replicasetdetail_stateconfig';
import sortedHeaderDirective from './sortedheader_directive';
/**
......@@ -27,6 +28,7 @@ export default angular.module(
'ngMaterial',
'ngResource',
'ui.router',
filtersModule.name,
])
.config(stateConfig)
.directive('kdServiceEndpoint', serviceEndpointDirective)
......
......@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import ReplicaSetDetailController from './replicasetdetail_controller';
/** Name of the state. Can be used in, e.g., $state.go method. */
export const stateName = 'replicasetdetail';
......@@ -36,66 +34,3 @@ export class StateParams {
this.replicaSet = replicaSet;
}
}
/**
* Configures states for the service view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
$stateProvider.state(stateName, {
controller: ReplicaSetDetailController,
controllerAs: 'ctrl',
url: '/replicasets/:namespace/:replicaSet',
templateUrl: 'replicasetdetail/replicasetdetail.html',
resolve: {
'replicaSetSpecPodsResource': getReplicaSetSpecPodsResource,
'replicaSetDetailResource': getReplicaSetDetailsResource,
'replicaSetDetail': resolveReplicaSetDetails,
'replicaSetEvents': resolveReplicaSetEvents,
},
});
}
/**
* @param {!StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.Resource<!backendApi.ReplicaSetDetail>}
* @ngInject
*/
function getReplicaSetDetailsResource($stateParams, $resource) {
return $resource('/api/replicasets/:namespace/:replicaSet', $stateParams);
}
/**
* @param {!StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.Resource<!backendApi.ReplicaSetSpec>}
* @ngInject
*/
function getReplicaSetSpecPodsResource($stateParams, $resource) {
return $resource('/api/replicasets/:namespace/:replicaSet/update/pods', $stateParams);
}
/**
* @param {!angular.Resource<!backendApi.ReplicaSetDetail>} replicaSetDetailResource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSetDetails(replicaSetDetailResource) {
return replicaSetDetailResource.get().$promise;
}
/**
* @param {!StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSetEvents($stateParams, $resource) {
/** @type {!angular.Resource<!backendApi.Events>} */
let resource = $resource('/api/events/:namespace/:replicaSet', $stateParams);
return resource.get().$promise;
}
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import ReplicaSetDetailController from './replicasetdetail_controller';
import {stateName} from './replicasetdetail_state';
/**
* Configures states for the service view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
$stateProvider.state(stateName, {
controller: ReplicaSetDetailController,
controllerAs: 'ctrl',
url: '/replicasets/:namespace/:replicaSet',
templateUrl: 'replicasetdetail/replicasetdetail.html',
resolve: {
'replicaSetSpecPodsResource': getReplicaSetSpecPodsResource,
'replicaSetDetailResource': getReplicaSetDetailsResource,
'replicaSetDetail': resolveReplicaSetDetails,
'replicaSetEvents': resolveReplicaSetEvents,
},
});
}
/**
* @param {!./replicasetdetail_state.StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.Resource<!backendApi.ReplicaSetDetail>}
* @ngInject
*/
function getReplicaSetDetailsResource($stateParams, $resource) {
return $resource('/api/replicasets/:namespace/:replicaSet', $stateParams);
}
/**
* @param {!./replicasetdetail_state.StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.Resource<!backendApi.ReplicaSetSpec>}
* @ngInject
*/
function getReplicaSetSpecPodsResource($stateParams, $resource) {
return $resource('/api/replicasets/:namespace/:replicaSet/update/pods', $stateParams);
}
/**
* @param {!angular.Resource<!backendApi.ReplicaSetDetail>} replicaSetDetailResource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSetDetails(replicaSetDetailResource) {
return replicaSetDetailResource.get().$promise;
}
/**
* @param {!./replicasetdetail_state.StateParams} $stateParams
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSetEvents($stateParams, $resource) {
/** @type {!angular.Resource<!backendApi.Events>} */
let resource = $resource('/api/events/:namespace/:replicaSet', $stateParams);
return resource.get().$promise;
}
......@@ -15,34 +15,33 @@ limitations under the License.
-->
<md-menu>
<md-button ng-click="ctrl.openMenu($mdOpenMenu, $event)" class="kd-replicaset-card-logs">Logs</md-button>
<md-menu-content width="6">
<md-button ng-click="ctrl.openMenu($mdOpenMenu, $event)" class="kd-replicaset-card-logs-button">Logs</md-button>
<md-menu-content>
<md-menu-item class="kd-menu-logs-md-menu-item">
<div flex="33">Logs</div>
<div>Logs</div>
</md-menu-item>
<md-menu-item class="kd-menu-logs-md-menu-item">
<div flex class="kd-menu-logs-item-header">Pod</div>
<div flex="50" class="kd-menu-logs-item-header">Running since</div>
<div flex class="kd-menu-logs-item-header">Prior restart</div>
<div class="kd-menu-logs-item-header kd-menu-logs-item-pods">Pod</div>
<div class="kd-menu-logs-item-header kd-menu-logs-item-since">Running since</div>
<div class="kd-menu-logs-item-header kd-menu-logs-item-prior">Prior restart</div>
</md-menu-item>
<md-menu-item ng-repeat="pod in ctrl.replicaSetPodsList" class="kd-menu-logs-md-menu-item">
<div flex class="kd-menu-logs-item">{{pod.name | middleEllipsis:10}}</div>
<div flex="50" class="kd-menu-logs-item" ng-if="ctrl.podContainerExists(pod)">
<a ng-href="{{::ctrl.getLogsHref(pod.name, pod.podContainers[0].name)}}">
{{pod.startTime}}<i
<md-menu-item ng-repeat="pod in ::ctrl.replicaSetPodsList" class="kd-menu-logs-md-menu-item">
<div class="kd-menu-logs-item kd-menu-logs-item-pods">
{{::(pod.name | middleEllipsis:10)}}
</div>
<div class="kd-menu-logs-item kd-menu-logs-item-since">
<a ng-href="{{::ctrl.getLogsHref(pod.name, pod.podContainers[0].name)}}"
ng-if="::ctrl.podContainerExists(pod)">
{{pod.startTime | date:"short"}}<i
class="material-icons kd-menu-logs-link-icon">open_in_new</i>
</a>
<span ng-if="::!ctrl.podContainerExists(pod)">-</span>
</div>
<div flex="50" class="kd-menu-logs-item" ng-if="!ctrl.podContainerExists(pod)">
-
</div>
<div flex class="kd-menu-logs-item" ng-if="ctrl.podContainersRestarted(pod)">
<a>
<div class="kd-menu-logs-item kd-menu-logs-item-prior">
<a ng-if="::ctrl.podContainersRestarted(pod)">
Logs<i class="material-icons kd-menu-logs-link-icon">open_in_new</i>
</a>
</div>
<div flex class="kd-menu-logs-item" ng-if="!ctrl.podContainersRestarted(pod)">
-
<span ng-if="::!ctrl.podContainersRestarted(pod)">-</span>
</div>
</md-menu-item>
</md-menu-content>
......
......@@ -16,24 +16,28 @@ limitations under the License.
<md-card class="kd-replicaset-card">
<md-card-content>
<div layout="row" layout-align="space-between center">
<div flex layout="column">
<a ng-href="{{::ctrl.getReplicaSetDetailHref()}}" flex>
{{::ctrl.replicaSet.name}}
</a>
<div flex class="md-caption">
<span ng-repeat="(label, value) in ::ctrl.replicaSet.labels"
class="kd-replicaset-card-label">
{{::label}}:{{::value}}
</span>
</div>
<div layout="column">
<div flex layout="row" layout-align="space-between center"
class="kd-replicaset-card-title-row">
<h3 class="md-title kd-replicaset-card-title">
<a ng-href="{{::ctrl.getReplicaSetDetailHref()}}" class="kd-replicaset-card-name" flex>
{{::ctrl.replicaSet.name}}
</a>
</h3>
<md-button class="md-icon-button kd-replicaset-card-menu-button">
<md-icon md-font-library="material-icons">more_vert</md-icon>
</md-button>
</div>
<div flex class="md-caption">
<span ng-repeat="(label, value) in ::ctrl.replicaSet.labels"
class="kd-replicaset-card-label">
{{::label}}:{{::value}}
</span>
</div>
<md-button class="md-icon-button">
<md-icon md-font-library="material-icons">more_vert</md-icon>
</md-button>
</div>
<div class="md-caption">
<div layout="row">
<div layout="row" layout-align="center end">
<span flex="60">
{{::ctrl.replicaSet.podsRunning}} pods running, {{::ctrl.replicaSet.podsPending}} pending
</span>
......@@ -41,33 +45,39 @@ limitations under the License.
replica-set-name="::ctrl.replicaSet.name">
</logs-menu>
</div>
<hr class="kd-replicaset-card-divider"></hr>
<md-divider class="kd-replicaset-card-divider"></md-divider>
<div layout="row" layout-wrap>
<div ng-if="::ctrl.replicaSet.description" flex="100" layout="column"
class="kd-replicaset-card-section">
<span flex>Description</span>
<span flex class="kd-replicaset-card-section-title">Description</span>
<div flex>
{{::ctrl.replicaSet.description}}
</div>
</div>
<div flex="60" layout="column" class="kd-replicaset-card-section">
<span flex>Image</span>
<span flex class="kd-replicaset-card-section-title">Image</span>
<div flex>
<div ng-repeat="image in ::ctrl.replicaSet.containerImages track by $index"
class="kd-replicaset-card-section-image">
{{::image}}
<md-tooltip>{{::image}}</md-tooltip>
{{::(image | middleEllipsis:32)}}
</div>
</div>
</div>
<div flex="40" layout="column" class="kd-replicaset-card-section">
<span flex="initial">Creation time</span>
<span flex>{{::ctrl.replicaSet.creationTime}}</span>
<span flex="initial" class="kd-replicaset-card-section-title">Age</span>
<span flex>
{{::ctrl.replicaSet.creationTime | relativeTime}}
<md-tooltip>
{{::ctrl.replicaSet.creationTime | date:'short'}}
</md-tooltip>
</span>
</div>
<div flex="60" layout="column" class="kd-replicaset-card-section">
<span flex="initial">Internal Endpoint</span>
<span flex="initial" class="kd-replicaset-card-section-title">Internal Endpoint</span>
<div flex>
<div ng-repeat="endpoint in ::ctrl.replicaSet.internalEndpoints track by $index">
<kd-service-endpoint endpoint="::endpoint"></kd-service-endpoint>
......@@ -79,7 +89,7 @@ limitations under the License.
</div>
<div flex="40" layout="column" class="kd-replicaset-card-section">
<span flex="initial">External Endpoint</span>
<span flex="initial" class="kd-replicaset-card-section-title">External Endpoint</span>
<div flex>
<div ng-repeat="endpoint in ::ctrl.replicaSet.externalEndpoints track by $index">
<kd-service-endpoint endpoint="::endpoint"></kd-service-endpoint>
......
......@@ -19,37 +19,53 @@
width: ($layout-breakpoint-lg - (2 * $baseline-grid) * 2) / 3;
}
// This override button style to make it look like a link.
.kd-replicaset-card-logs {
border-radius: inherit;
.kd-replicaset-card-name {
color: inherit;
font-size: inherit;
font-weight: inherit;
line-height: 0;
margin: inherit;
min-height: inherit;
min-width: inherit;
padding: inherit;
display: inline-block;
font-weight: $regular-font-weight;
text-decoration: none;
text-transform: inherit;
}
&:after {
content: '\25BC';
}
.kd-replicaset-card-title {
margin: 0;
}
.kd-replicaset-card-title-row {
margin-top: -$baseline-grid - 2px;
}
.kd-replicaset-card-divider {
border: 0;
border-top: 1px solid;
margin-top: $baseline-grid;
}
// This override button style to make it look like a link.
.md-button {
&.kd-replicaset-card-logs-button {
font-size: inherit;
font-weight: inherit;
line-height: 0;
margin: 0;
min-height: inherit;
min-width: inherit;
padding: $baseline-grid 0;
text-decoration: none;
text-transform: inherit;
&:after {
content: ' \25BE';
}
}
}
.kd-replicaset-card-section {
margin-top: 2 * $baseline-grid;
}
.kd-replicaset-card-section-title {
color: $foreground-2;
}
.kd-replicaset-card-section-image {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
......@@ -57,24 +73,32 @@
margin-right: 2 * $baseline-grid;
}
.kd-menu-logs-md-menu-item {
height: 30px;
min-height: 30px;
}
.kd-menu-logs-item-header {
color: $muted;
font-size: .8em;
box-sizing: inherit;
color: $foreground-2;
font-size: $body-font-size-base;
white-space: nowrap;
}
.kd-menu-logs-item {
font-size: .8em;
overflow: hidden;
box-sizing: inherit;
font-size: $body-font-size-base;
white-space: nowrap;
}
.kd-menu-logs-item-pods {
width: 10 * $baseline-grid;
}
.kd-menu-logs-item-prior {
width: 10 * $baseline-grid;
}
.kd-menu-logs-item-since {
width: 15 * $baseline-grid;
}
.kd-menu-logs-link-icon {
font-size: 1em;
font-size: $subhead-font-size-base;
margin-left: $baseline-grid;
}
......@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import {stateName as deploy} from 'deploy/deploy_state';
/**
* Controller for the replica set list view.
*
......@@ -32,8 +34,7 @@ export default class ReplicaSetListController {
}
/**
* TODO(floreks): Should be changed to state variable. Related issue #153.
* @export
*/
redirectToDeployPage() { this.state_.go('deploy'); }
redirectToDeployPage() { this.state_.go(deploy); }
}
......@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import stateConfig from './replicasetlist_state';
import stateConfig from './replicasetlist_stateconfig';
import logsMenuDirective from './logsmenu_directive';
import middleEllipsisFilter from 'common/filters/middleellipsis_filter';
import filtersModule from 'common/filters/filters_module';
import replicaSetCardDirective from './replicasetcard_directive';
import replicaSetDetailModule from 'replicasetdetail/replicasetdetail_module';
import replicaSetListContainer from './replicasetlistcontainer_directive';
......@@ -31,9 +31,9 @@ export default angular.module(
'ngResource',
'ui.router',
replicaSetDetailModule.name,
filtersModule.name,
])
.config(stateConfig)
.filter('middleEllipsis', middleEllipsisFilter)
.directive('logsMenu', logsMenuDirective)
.directive('kdReplicaSetListContainer', replicaSetListContainer)
.directive('kdReplicaSetCard', replicaSetCardDirective);
......@@ -12,58 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import {stateName as zerostate} from 'zerostate/zerostate_state';
import ReplicaSetListController from './replicasetlist_controller';
/** Name of the state. Can be used in, e.g., $state.go method. */
export const stateName = 'replicasets';
/** Absolute URL of the state. */
export const stateUrl = '/replicasets';
/**
* Configures states for the service view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
$stateProvider.state(stateName, {
controller: ReplicaSetListController,
controllerAs: 'ctrl',
url: stateUrl,
resolve: {
'replicaSets': resolveReplicaSets,
},
templateUrl: 'replicasetlist/replicasetlist.html',
onEnter: redirectIfNeeded,
});
}
/**
* Avoids entering replica set list page when there are no replica sets.
* Used f.e. when last replica set gets deleted.
* Transition to: zerostate
* @param {!ui.router.$state} $state
* @param {!angular.$timeout} $timeout
* @param {!backendApi.ReplicaSetList} replicaSets
* @ngInject
*/
function redirectIfNeeded($state, $timeout, replicaSets) {
if (replicaSets.replicaSets.length === 0) {
// allow original state change to finish before redirecting to new state to avoid error
$timeout(() => { $state.go(zerostate); });
}
}
/**
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSets($resource) {
/** @type {!angular.Resource<!backendApi.ReplicaSetList>} */
let resource = $resource('/api/replicasets');
return resource.get().$promise;
}
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {stateName as zerostate} from 'zerostate/zerostate_state';
import {stateName as replicasets} from './replicasetlist_state';
import {stateUrl as replicasetsUrl} from './replicasetlist_state';
import ReplicaSetListController from './replicasetlist_controller';
/**
* Configures states for the service view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
$stateProvider.state(replicasets, {
controller: ReplicaSetListController,
controllerAs: 'ctrl',
url: replicasetsUrl,
resolve: {
'replicaSets': resolveReplicaSets,
},
templateUrl: 'replicasetlist/replicasetlist.html',
onEnter: redirectIfNeeded,
});
}
/**
* Avoids entering replica set list page when there are no replica sets.
* Used f.e. when last replica set gets deleted.
* Transition to: zerostate
* @param {!ui.router.$state} $state
* @param {!angular.$timeout} $timeout
* @param {!backendApi.ReplicaSetList} replicaSets
* @ngInject
*/
function redirectIfNeeded($state, $timeout, replicaSets) {
if (replicaSets.replicaSets.length === 0) {
// allow original state change to finish before redirecting to new state to avoid error
$timeout(() => { $state.go(zerostate); });
}
}
/**
* @param {!angular.$resource} $resource
* @return {!angular.$q.Promise}
* @ngInject
*/
function resolveReplicaSets($resource) {
/** @type {!angular.Resource<!backendApi.ReplicaSetList>} */
let resource = $resource('/api/replicasets');
return resource.get().$promise;
}
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import stateConfig from './zerostate_state';
import stateConfig from './zerostate_stateconfig';
/**
* Angular module for the zero state view.
......
......@@ -12,22 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import ZeroStateController from './zerostate_controller';
/** Name of the state. Can be used in, e.g., $state.go method. */
export const stateName = 'zero';
/**
* Configures states for the zero state view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
$stateProvider.state(stateName, {
controller: ZeroStateController,
controllerAs: 'ctrl',
url: '/zerostate',
templateUrl: 'zerostate/zerostate.html',
});
}
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import ZeroStateController from './zerostate_controller';
import {stateName} from './zerostate_state';
/**
* Configures states for the zero state view.
*
* @param {!ui.router.$stateProvider} $stateProvider
* @ngInject
*/
export default function stateConfig($stateProvider) {
$stateProvider.state(stateName, {
controller: ZeroStateController,
controllerAs: 'ctrl',
url: '/zerostate',
templateUrl: 'zerostate/zerostate.html',
});
}
......@@ -27,6 +27,12 @@ func TestGetReplicaSetPods(t *testing.T) {
ObjectMeta: api.ObjectMeta{
Name: "pod-1",
},
Spec: api.PodSpec{
Containers: []api.Container{
{Name: "container-1"},
{Name: "container-2"},
},
},
Status: api.PodStatus{
ContainerStatuses: []api.ContainerStatus{
{
......@@ -44,6 +50,11 @@ func TestGetReplicaSetPods(t *testing.T) {
ObjectMeta: api.ObjectMeta{
Name: "pod-2",
},
Spec: api.PodSpec{
Containers: []api.Container{
{Name: "container-3"},
},
},
Status: api.PodStatus{
ContainerStatuses: []api.ContainerStatus{
{
......
......@@ -15,7 +15,6 @@
package main
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
"k8s.io/kubernetes/pkg/runtime"
......@@ -57,7 +56,6 @@ func TestValidateName(t *testing.T) {
for _, c := range cases {
testClient := testclient.NewSimpleFake(c.objects...)
validity, _ := ValidateAppName(c.spec, testClient)
fmt.Printf("%#v\n", validity)
if validity.Valid != c.expected {
t.Errorf("Expected %#v validity to be %#v for objects %#v, but was %#v\n",
c.spec, c.expected, c.objects, validity)
......
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import replicasetlistModule from 'replicasetlist/replicasetlist_module';
describe('Relative time filter', () => {
let currentTime = new Date(
2015, // year
11, // month
29, // day
23, // hour
59, // minute
59 // second
);
beforeEach(function() {
jasmine.clock().mockDate(currentTime);
angular.mock.module(replicasetlistModule.name);
});
it(`should return 'didn't happen yet' string if given time is (a year ahead) in the future`,
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setYear(givenTime.getFullYear() + 1);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual(`didn't happen yet`);
}));
it("should return 'just now' string if given time is the same as current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('just now');
}));
it("should return 'a second' string if given time is a second before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setSeconds(givenTime.getSeconds() - 1);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('a second');
}));
it("should return '15 seconds' string if given time is 15 seconds before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setSeconds(givenTime.getSeconds() - 15);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('15 seconds');
}));
it("should return 'a minute' string if given time is a minute before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setMinutes(givenTime.getMinutes() - 1);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('a minute');
}));
it("should return '30 minutes' string if given time is 30 minutes before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setMinutes(givenTime.getMinutes() - 30);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('30 minutes');
}));
it("should return 'an hour' string if given time is an hour before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setHours(givenTime.getHours() - 1);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('an hour');
}));
it("should return '3 hours' string if given time is 3 hours before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setHours(givenTime.getHours() - 3);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('3 hours');
}));
it("should return 'a day' string if given time is a day before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setDate(givenTime.getDate() - 1);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('a day');
}));
it("should return '8 days' string if given time is 8 days before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setDate(givenTime.getDate() - 8);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('8 days');
}));
it("should return 'a month' string if given time is a month before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setMonth(givenTime.getMonth() - 1);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('a month');
}));
it("should return '11 months' string if given time is 11 months before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setMonth(givenTime.getMonth() - 11);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('11 months');
}));
it("should return 'a year' string if given time is a year before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setYear(givenTime.getFullYear() - 1);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('a year');
}));
it("should return '134 years' string if given time is 134 years before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setYear(givenTime.getFullYear() - 134);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('134 years');
}));
it("should return '11 months' string if given time is 11 months, 7 days, 5 hours and 3 minutes" +
" before current time",
angular.mock.inject(function(relativeTimeFilter) {
// given
let givenTime = new Date(currentTime);
givenTime.setMonth(givenTime.getMonth() - 11);
givenTime.setDate(givenTime.getDate() - 7);
givenTime.setHours(givenTime.getHours() - 5);
givenTime.setMinutes(givenTime.getMinutes() - 3);
// when
let relativeTime = relativeTimeFilter(givenTime);
// then
expect(relativeTime).toEqual('11 months');
}));
});
......@@ -65,8 +65,9 @@ describe('Logs toolbar controller', () => {
angular.mock.inject(($controller, $state) => {
state = $state;
state.params = stateParams;
ctrl = $controller(LogsToolbarController, {replicaSetPods: replicaSetPods}, $state);
ctrl = $controller(
LogsToolbarController, {replicaSetPods: replicaSetPods, $stateParams: stateParams},
$state);
});
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册