This is an automated email from the ASF dual-hosted git repository.
tobiasistvan pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push:
new 544b07e [AMBARI-24631] [Log Search UI] styles and layout fixes (#2339)
544b07e is described below
commit 544b07e74938584571c51ac0a109b2e6d4c33d78
Author: Istvan Tobias <[email protected]>
AuthorDate: Wed Sep 19 14:06:44 2018 +0200
[AMBARI-24631] [Log Search UI] styles and layout fixes (#2339)
* [AMBARI-24631] [Log Search UI] styles and layout fixes - autorefresh
styling
* [AMBARI-24631] [Log Search UI] styles and layout fixes
Change-Id: I6d233019638464cf39c7af038b1b350d242279e8
* [AMBARI-24631] [Log Search UI] styles and layout fixes - PR change
requests
Change-Id: Id3434b605929fc9e0129eeea341cab25a3bf1180
---
ambari-logsearch/ambari-logsearch-web/package.json | 2 +-
.../classes/components/graph/graph.component.ts | 3 +
.../components/graph/time-graph.component.less | 2 +-
.../action-menu/action-menu.component.less | 6 +
.../action-menu/action-menu.component.ts | 4 +
.../collapsible-panel.component.html | 1 +
.../collapsible-panel.component.less | 2 +
.../log-index-filter.component.less | 3 +
.../log-message/log-message.component.html | 4 +-
.../log-message/log-message.component.spec.ts | 7 +-
.../log-message/log-message.component.ts | 41 ++---
.../logs-container/logs-container.component.html | 41 +++--
.../logs-container/logs-container.component.less | 43 ++++-
.../logs-container.component.spec.ts | 4 +-
.../logs-container/logs-container.component.ts | 24 ++-
.../service-logs-table.component.html | 17 +-
.../service-logs-table.component.less | 13 ++
.../service-logs-table.component.ts | 192 +++++++++++++--------
.../time-histogram/time-histogram.component.html | 3 +
.../time-histogram/time-histogram.component.less | 3 +
.../time-range-picker.component.html | 2 +-
.../circle-progress-bar.component.html} | 24 ++-
.../circle-progress-bar.component.less} | 45 ++---
.../circle-progress-bar.component.spec.ts} | 47 +++--
.../circle-progress-bar.component.ts | 86 +++++++++
.../modal-dialog/modal-dialog.component.less | 13 +-
.../modal-dialog/modal-dialog.component.ts | 4 +-
.../src/app/modules/shared/shared.module.ts | 7 +-
.../src/app/modules/shared/variables.less | 16 +-
.../src/app/services/logs-container.service.ts | 32 ++--
.../ambari-logsearch-web/src/assets/i18n/en.json | 6 +
ambari-logsearch/ambari-logsearch-web/yarn.lock | 6 +-
32 files changed, 499 insertions(+), 204 deletions(-)
diff --git a/ambari-logsearch/ambari-logsearch-web/package.json
b/ambari-logsearch/ambari-logsearch-web/package.json
index fb09f00..3639b54 100644
--- a/ambari-logsearch/ambari-logsearch-web/package.json
+++ b/ambari-logsearch/ambari-logsearch-web/package.json
@@ -39,7 +39,7 @@
"jquery": "^1.12.4",
"moment": "^2.18.1",
"moment-timezone": "^0.5.13",
- "ngx-bootstrap": "^1.9.3",
+ "ngx-bootstrap": "^2.0.5",
"rxjs": "^5.4.3",
"zone.js": "^0.8.4"
},
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/graph.component.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/graph.component.ts
index 7a0729a..af6a9db 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/graph.component.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/graph.component.ts
@@ -63,6 +63,9 @@ export class GraphComponent implements AfterViewInit,
OnChanges, OnInit, OnDestr
@Input()
labels: HomogeneousObject<string> = {};
+ @Input()
+ chartLabel: string;
+
/**
* Indicates whether the graph represents dependency on time
* @type {boolean}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/time-graph.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/time-graph.component.less
index 73f1870..bfafd40 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/time-graph.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/time-graph.component.less
@@ -24,7 +24,7 @@
cursor: crosshair;
}
- .time-gap {
+ .chart-label, .time-gap {
color: @base-font-color;
font-size: 1.2rem;
text-align: center;
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less
index c1f3014..a8c6e05 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.less
@@ -111,4 +111,10 @@
padding-right: 0;
}
}
+ /deep/ modal-dialog.log-index-filter .modal-header {
+ min-height: 4rem;
+ header {
+ margin-left: auto;
+ }
+ }
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
index fcf3587..a293e95 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/action-menu/action-menu.component.ts
@@ -164,4 +164,8 @@ export class ActionMenuComponent implements OnInit,
OnDestroy {
this.logsContainer.stopCaptureTimer();
}
+ cancelCapture(): void {
+ this.logsContainer.cancelCapture();
+ }
+
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.html
b/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.html
index a671946..ce1e872 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.html
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.html
@@ -20,6 +20,7 @@
<i [ngClass]="{'fa': true, 'fa-caret-down': !isCollapsed,
'fa-caret-right': isCollapsed}"></i>
{{((isCollapsed ? collapsedTitle : openTitle) || commonTitle) |
translate}}
</a>
+ <ng-content select="header"></ng-content>
</div>
<div class="panel-body" [attr.aria-collapsed]="isCollapsed">
<ng-content></ng-content>
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
index 571e6a2..79d25f3 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
@@ -24,6 +24,8 @@
background-color: @panel-heading;
border: 0 none;
color: @base-font-color;
+ display: flex;
+ flex-direction: row;
font-size: 1.25rem;
a, a:hover, a:visited {
color: @base-font-color;
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
index a7f48bc..a5c3957 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-index-filter/log-index-filter.component.less
@@ -27,6 +27,9 @@
position: sticky;
top: -1px;
z-index: 10;
+ th {
+ padding: 8px 0;
+ }
}
.component-column {
width: 25%;
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.html
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.html
index 9e05397..70c7ed7 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.html
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.html
@@ -14,11 +14,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<div [ngClass]="{
+<div #wrapper [ngClass]="{
'log-message-container': true,
'log-message-container-collapsible': addCaret,
'log-message-container-open': isOpen
}">
<button *ngIf="addCaret" (click)="onCaretClick($event)"><i
class="caret"></i></button>
- <div #content class="log-message-content">{{isOpen ? message : (message |
replace: multiLineTestRegexp : ' ')}}</div>
+ <div #content class="log-message-content">{{ message }}</div>
</div>
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.spec.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.spec.ts
index d2339c9..eafb1aa 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.spec.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.spec.ts
@@ -48,7 +48,7 @@ describe('LogMessageComponent', () => {
});
it('event handler should call the toggleOpen method', () => {
- let mockEvent: MouseEvent = document.createEvent('MouseEvent');
+ const mockEvent: MouseEvent = document.createEvent('MouseEvent');
mockEvent.initEvent('click', true, true);
spyOn(component,'toggleOpen');
component.onCaretClick(mockEvent);
@@ -56,7 +56,7 @@ describe('LogMessageComponent', () => {
});
it('event handler should prevent the default behaviour of the action', () =>
{
- let mockEvent: MouseEvent = document.createEvent('MouseEvent');
+ const mockEvent: MouseEvent = document.createEvent('MouseEvent');
mockEvent.initEvent('click', true, true);
spyOn(mockEvent,'preventDefault');
component.onCaretClick(mockEvent);
@@ -64,13 +64,14 @@ describe('LogMessageComponent', () => {
});
it('calling the toggleOpen method should negate the isOpen property', () => {
- let currentState = component.isOpen;
+ const currentState = component.isOpen;
component.toggleOpen();
expect(component.isOpen).toEqual(!currentState);
});
it('should set the addCaret prop to TRUE if the message prop has new line
character.', () => {
component.message = messages.withNewLine;
+ component.reCalculateOnChange();
component.checkAddCaret();
expect(component['addCaret']).toEqual(true);
});
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.ts
index ac4fb31..10d1cca 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.ts
@@ -24,12 +24,11 @@ import {
OnInit,
OnDestroy,
SimpleChanges,
- HostListener,
ChangeDetectorRef
} from '@angular/core';
-import {Observable} from 'rxjs/Observable';
+import {Subject} from 'rxjs/Subject';
import {Subscription} from 'rxjs/Subscription';
-import 'rxjs/add/operator/debounceTime';
+import 'rxjs/add/operator/auditTime';
/**
* This is a simple UI component to display the log message. The goal is to be
able to show one line and be collapsile
@@ -63,7 +62,7 @@ export class LogMessageComponent implements AfterViewInit,
OnChanges, OnInit, On
* LogMessageComponent should check if the caret should be visible or not.
*/
@Input()
- listenChangesOn: any;
+ refreshOn$: Subject<any>;
/**
* This will be shown as log message in the component
@@ -76,7 +75,9 @@ export class LogMessageComponent implements AfterViewInit,
OnChanges, OnInit, On
* the content container element. Handled by the @checkAddCaret method
* @type {boolean}
*/
- private addCaret = false;
+ addCaret = false;
+
+ private scrollWidth: number;
/**
* This is a regexp tester to check if the log message is multiline text or
single line. Doing by checking the new
@@ -90,9 +91,7 @@ export class LogMessageComponent implements AfterViewInit,
OnChanges, OnInit, On
* caret to give a possibility to the user to see the message as it is
(pre-wrapped).
* @type {boolean}
*/
- private get isMultiLineMessage(): boolean {
- return this.multiLineTestRegexp.test(this.message);
- }
+ isMultiLineMessage = false;
/**
* The array to collect all the subscriptions created by the instance in
order to unsubscribe when the component
@@ -109,15 +108,17 @@ export class LogMessageComponent implements
AfterViewInit, OnChanges, OnInit, On
* @param {SimpleChanges} changes
*/
ngOnChanges(changes: SimpleChanges): void {
- if (changes.listenChangesOn !== undefined) {
+ if (changes.message !== undefined) {
+ this.message = this.message.trim();
+ this.reCalculateOnChange();
this.checkAddCaret();
}
}
ngOnInit() {
- this.subscriptions.push(
- Observable.fromEvent(window,
'resize').debounceTime(100).subscribe(this.onWindowResize)
- );
+ if (this.refreshOn$) {
+ this.subscriptions.push(this.refreshOn$.subscribe(this.checkAddCaret));
+ }
}
ngOnDestroy() {
@@ -128,16 +129,13 @@ export class LogMessageComponent implements
AfterViewInit, OnChanges, OnInit, On
* The goal is to perform a initial caret display check when the component
has been initialized.
*/
ngAfterViewInit(): void {
+ this.reCalculateOnChange();
this.checkAddCaret();
}
- /**
- * Since the size of the column is depends on the window size we have to
listen the resize event and show/hide the
- * caret corresponding the new size of the content container element.
- * Using the arrow function will keep the instance scope.
- */
- onWindowResize = (): void => {
- this.checkAddCaret();
+ reCalculateOnChange() {
+ this.isMultiLineMessage = this.multiLineTestRegexp.test(this.message);
+ this.scrollWidth = this.content.nativeElement.scrollWidth;
}
/**
@@ -145,10 +143,9 @@ export class LogMessageComponent implements AfterViewInit,
OnChanges, OnInit, On
* scrollHeight and the clientHeight.
*/
checkAddCaret = (): void => {
- const el = this.content.nativeElement;
- this.addCaret = this.isMultiLineMessage || (el.scrollHeight >
el.clientHeight) || (el.scrollWidth > el.clientWidth);
+ this.addCaret = this.isMultiLineMessage || (this.scrollWidth >
this.content.nativeElement.clientWidth);
this.cdRef.detectChanges();
- };
+ }
/**
* This is the click event handler of the caret button element. It will only
toggle the isOpen property so that the
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
index 7d0bb62..c319ca9 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.html
@@ -29,22 +29,20 @@
[ngClass]="{'container-fluid': true, 'logs-container': true,
'fixed-filterbar': isFilterPanelFixedPostioned}">
<filters-panel class="row" [filtersForm]="filtersForm"
#filtersPanel></filters-panel>
<div class="row events-count">
- <div *ngIf="autoRefreshRemainingSeconds" class="col-md-12">
- <div class="auto-refresh-message pull-right">
- {{'filter.capture.triggeringRefresh' | translate:
autoRefreshMessageParams}}
- </div>
+ <div *ngIf="captureTimeRangeCache" class="panel panel-default
panel-capture-view col-md-2 col-md-offset-5">
+ <i class="fa fa-play"></i>
+ {{'filter.youAreInSnapshotView' | translate}}
+ <button type="button" class="close" [attr.aria-label]="'modal.close' |
translate" (click)="clearCaptureTimeRangeCache()"
+ tooltip="{{'filter.closeSnapshotView' | translate}}" placement="right">
+ <span aria-hidden="true">×</span>
+ </button>
</div>
-
- <!-- TODO use plugin for singular/plural -->
- <div *ngIf="logsType === 'serviceLogs'" class="logs-header col-md-12">{{
- (!totalEventsFoundMessageParams.totalCount ? 'logs.noEventFound' :
- (totalEventsFoundMessageParams.totalCount === 1 ? 'logs.oneEventFound'
: 'logs.totalEventFound'))
- | translate: totalEventsFoundMessageParams
- }}</div>
</div>
<ng-container [ngSwitch]="logsType">
<ng-container *ngSwitchCase="'serviceLogs'">
- <collapsible-panel [class.hide]="isServiceLogsFileView$ | async"
openTitle="logs.hideGraph" collapsedTitle="logs.showGraph">
+ <collapsible-panel [class.hide]="isServiceLogsFileView$ | async"
openTitle="logs.hideGraph" collapsedTitle="logs.showGraph"
class="service-logs-histogram">
+ <header>{{(!totalEventsFoundMessageParams.totalCount ?
'logs.noEventFound' :
+ (totalEventsFoundMessageParams.totalCount === 1 ?
'logs.oneEventFound' : 'logs.totalEventFound')) | translate:
totalEventsFoundMessageParams}}</header>
<time-histogram (selectArea)="setCustomTimeRange($event[0],
$event[1])" [data]="serviceLogsHistogramData"
[colors]="serviceLogsHistogramColors"
[allowFractionalYTicks]="false"
svgId="service-logs-histogram"></time-histogram>
@@ -65,3 +63,22 @@
<log-context *ngIf="isServiceLogContextView" [id]="activeLog.id"
[hostName]="activeLog.host_name"
[componentName]="activeLog.component_name"></log-context>
</div>
+<modal-dialog
+ title="{{'filter.capture' | translate}}"
+ class="capture-dialog"
+ [visible]="autoRefreshRemainingSeconds"
+ (onCloseRequest)="cancelCapture()">
+ <span class="info">{{'filter.refreshingLogListIn' | translate}}</span>
+ <circle-progress-bar radius="50" strokeWidth="5" strokeColor="black"
+ [percent]="(autoRefreshRemainingSeconds / (autoRefreshInterval / 1000)) *
100">
+ <span>
+ <span class="remaining-seconds">
+ {{autoRefreshRemainingSeconds}}
+ <span class="unit">{{'filter.capture.sec' | translate}}</span>
+ </span>
+ </span>
+ </circle-progress-bar>
+ <footer>
+ <button class="btn btn-secondary"
(click)="cancelCapture()">{{'modal.cancel' | translate}}</button>
+ </footer>
+</modal-dialog>
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.less
index 5056003..ef61abe 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.less
@@ -17,6 +17,7 @@
*/
@import '../../modules/shared/mixins';
+@import '../../modules/shared/variables';
:host {
display: block;
@@ -40,7 +41,7 @@
.fixed-filterbar {
filters-panel {
- background-color: fadeout(@filters-panel-background-color, 10%);
+ background-color: fadeout(@filters-panel-background-color, 5%);
box-shadow: 0 2px 2px rgba(0,0,0,.1);
left: 0;
margin: 0;
@@ -55,4 +56,44 @@
margin-top: @block-margin-top;
}
+ /deep/ collapsible-panel.service-logs-histogram {
+ .panel-heading {
+ header {
+ margin-left: auto;
+ }
+ }
+ }
+
+ /deep/ modal-dialog.capture-dialog {
+ .modal-dialog {
+ max-width: 350px;
+ }
+ .modal-body {
+ display: flex;
+ flex-direction: column;
+ /deep/ circle-progress-bar {
+ display: inline-block;
+ align-self: center;
+ label {
+ font-size: 3rem;
+ font-weight: normal;
+ .unit {
+ color: @fluid-gray-2;
+ font-size: 1.2rem;
+ }
+ }
+ }
+ }
+ }
+
+ .panel-capture-view {
+ padding: 1rem;
+ i {
+ color: @fluid-gray-1;
+ &.fa-play {
+ padding-right: 1rem;
+ }
+ }
+ }
+
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.spec.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.spec.ts
index 015273c..78245e4 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.spec.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.spec.ts
@@ -19,6 +19,7 @@
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {StoreModule} from '@ngrx/store';
+import {TooltipModule} from 'ngx-bootstrap';
import {MockHttpRequestModules, TranslationModules} from
'@app/test-config.spec';
import {AppSettingsService, appSettings} from
'@app/services/storage/app-settings.service';
import {AppStateService, appState} from
'@app/services/storage/app-state.service';
@@ -75,7 +76,8 @@ describe('LogsContainerComponent', () => {
hosts,
serviceLogsTruncated
}),
- ...TranslationModules
+ ...TranslationModules,
+ TooltipModule.forRoot(),
],
providers: [
...MockHttpRequestModules,
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
index e8d2ee0..6b983fc 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/logs-container/logs-container.component.ts
@@ -58,7 +58,7 @@ export class LogsContainerComponent implements OnInit,
OnDestroy {
});
});
- private logsType: LogsType;
+ logsType: LogsType;
serviceLogsHistogramData: HomogeneousObject<HomogeneousObject<number>>;
@@ -87,7 +87,7 @@ export class LogsContainerComponent implements OnInit,
OnDestroy {
private subscriptions: Subscription[] = [];
private paramsSyncInProgress: BehaviorSubject<boolean> = new
BehaviorSubject<boolean>(false);
- private isServiceLogsFileView$: Observable<boolean> =
this.appState.getParameter('isServiceLogsFileView');
+ isServiceLogsFileView$: Observable<boolean> =
this.appState.getParameter('isServiceLogsFileView');
constructor(
private appState: AppStateService,
@@ -176,6 +176,12 @@ export class LogsContainerComponent implements OnInit,
OnDestroy {
get autoRefreshRemainingSeconds(): number {
return this.logsContainerService.autoRefreshRemainingSeconds;
}
+ get autoRefreshInterval(): number {
+ return this.logsContainerService.autoRefreshInterval;
+ }
+ get captureTimeRangeCache(): ListItem {
+ return this.logsContainerService.captureTimeRangeCache;
+ }
get autoRefreshMessageParams(): object {
return {
@@ -361,4 +367,18 @@ export class LogsContainerComponent implements OnInit,
OnDestroy {
this.router.navigate(['/logs',
...this.logsFilteringUtilsService.getNavigationForTab(newActiveTab)]);
}
}
+ //
+ // CAPTURE FEATURES
+ //
+ cancelCapture(): void {
+ this.logsContainerService.cancelCapture();
+ }
+
+ clearCaptureTimeRangeCache(): void {
+ if (this.captureTimeRangeCache) {
+ this.filtersForm.controls.timeRange.setValue(this.captureTimeRangeCache);
+ this.logsContainerService.captureTimeRangeCache = null;
+ }
+ }
+
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.html
b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.html
index fb8a9b4..31375ed 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.html
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.html
@@ -18,6 +18,11 @@
<div class="panel panel-default">
<div [ngClass]="{'panel-body': true, 'layout-flex': layout==='FLEX',
'layout-table': layout==='TABLE'}">
<div class="service-logs-table-controls">
+ <div class="total-event-info">
+ <ng-container
*ngIf="!totalEventsFoundMessageParams.totalCount">{{'logs.noEventFound' |
translate}}</ng-container>
+ <ng-container *ngIf="totalEventsFoundMessageParams.totalCount ===
1">{{'logs.oneEventFound' | translate}}</ng-container>
+ <ng-container *ngIf="totalEventsFoundMessageParams.totalCount >
1">{{'logs.totalEventFound' | translate:
totalEventsFoundMessageParams}}</ng-container>
+ </div>
<div *ngIf="tooManyColumnsSelected" class="list-layout-warning">
<i class="fa fa-warning"></i>
{{'logs.brokenListLayoutMessage' | translate}}
@@ -103,9 +108,9 @@
<td *ngIf="isColumnDisplayed('path')" [ngClass]="'log-path'">
{{log.path}}
</td>
- <td *ngIf="isColumnDisplayed('log_message')"
[ngClass]="'log-message'" width="*"
+ <td *ngIf="isColumnDisplayed('log_message')" class="log-message"
width="*"
(contextmenu)="openMessageContextMenu($event)">
- <log-message [listenChangesOn]="displayedColumns"
[message]="log.log_message"></log-message>
+ <log-message [refreshOn$]="tableRefresh$"
[message]="log.log_message"></log-message>
</td>
</tr>
</ng-container>
@@ -113,9 +118,9 @@
<tfoot>
<tr>
<td attr.colspan="{{displayedColumns.length + 1}}">
- <pagination class="col-md-12" *ngIf="logs && logs.length"
[totalCount]="totalCount"
- [filtersForm]="filtersForm"
[filterInstance]="filters.pageSize"
- [currentCount]="logs.length"></pagination>
+ <pagination *ngIf="logs && logs.length" [totalCount]="totalCount"
+ [filtersForm]="filtersForm" [filterInstance]="filters.pageSize"
+ [currentCount]="logs.length"></pagination>
</td>
</tr>
</tfoot>
@@ -158,7 +163,7 @@
</div>
</div>
<div *ngIf="isColumnDisplayed('log_message')" class="log-message"
(contextmenu)="openMessageContextMenu($event)">
- <log-message [listenChangesOn]="displayedColumns"
[message]="log.log_message"></log-message>
+ <log-message [refreshOn$]="tableRefresh$"
[message]="log.log_message"></log-message>
</div>
</div>
</ng-container>
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
index 5d13bac..0ff490b 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.less
@@ -20,9 +20,16 @@
:host {
.service-logs-table-controls {
+ align-items: center;
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
+ .total-event-info {
+ margin-right: auto;
+ }
+ pagination {
+ margin-right: auto;
+ }
.layout-btn-group {
display: flex;
align-items: center;
@@ -145,6 +152,12 @@
}
&.log-message {
width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ &.log-message-open {
+ white-space: pre-wrap;
+ }
}
&.log-event_count {
width: 3em;
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
index 7dfb9af..757b4a0 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/service-logs-table/service-logs-table.component.ts
@@ -16,7 +16,22 @@
* limitations under the License.
*/
-import {Component, AfterViewChecked, ViewChild, ElementRef, Input,
ChangeDetectorRef} from '@angular/core';
+import {
+ Component,
+ OnInit,
+ OnDestroy,
+ AfterViewChecked,
+ ViewChild,
+ ElementRef,
+ Input,
+ ChangeDetectorRef,
+ SimpleChanges
+} from '@angular/core';
+
+import { Subject } from 'rxjs/Subject';
+import { Subscription } from 'rxjs/Subscription';
+import { Observable } from 'rxjs/Observable';
+import { auditTime } from 'rxjs/operator/auditTime';
import {ListItem} from '@app/classes/list-item';
import {LogsTableComponent} from
'@app/classes/components/logs-table/logs-table-component';
@@ -35,21 +50,7 @@ export enum ListLayout {
templateUrl: './service-logs-table.component.html',
styleUrls: ['./service-logs-table.component.less']
})
-export class ServiceLogsTableComponent extends LogsTableComponent implements
AfterViewChecked {
-
- constructor(
- private logsContainer: LogsContainerService,
- private utils: UtilsService,
- private cdRef: ChangeDetectorRef,
- private notificationService: NotificationService
- ) {
- super();
- }
-
- ngAfterViewChecked() {
- this.checkListLayout();
- this.cdRef.detectChanges();
- }
+export class ServiceLogsTableComponent extends LogsTableComponent implements
AfterViewChecked, OnInit, OnDestroy {
/**
* The element reference is used to check if the table is broken or not.
@@ -72,21 +73,21 @@ export class ServiceLogsTableComponent extends
LogsTableComponent implements Aft
* @type {boolean}
*/
@Input()
- showLabels: boolean = false;
+ showLabels = false;
/**
* The minimum width for the log message column. It is used when we check if
the layout is broken or not.
* @type {number}
*/
@Input()
- logMessageColumnMinWidth: number = 175;
+ logMessageColumnMinWidth = 175;
/**
* We use this property in the broken table layout check process when the
log message is displayed.
* @type {string}
*/
@Input()
- logMessageColumnCssSelector: string = 'tbody tr td.log-message';
+ logMessageColumnCssSelector = 'tbody tr td.log-message';
/**
* Set the layout for the list.
@@ -99,9 +100,91 @@ export class ServiceLogsTableComponent extends
LogsTableComponent implements Aft
@Input()
layout: ListLayout = ListLayout.Table;
- readonly dateFormat: string = 'dddd, MMMM Do';
+ readonly dateFormat = 'dddd, MMMM Do';
+
+ readonly timeFormat = 'h:mm:ss A';
+
+ readonly customStyledColumns: string[] = ['level', 'type', 'logtime',
'log_message', 'path'];
+
+ private readonly messageFilterParameterName = 'log_message';
+
+ private readonly logsType = 'serviceLogs';
+
+ private selectedText = '';
+
+ /**
+ * This is a private flag to store the table layout check result. It is used
to show user notifications about
+ * non-visible information.
+ * @type {boolean}
+ */
+ tooManyColumnsSelected = false;
+
+ get contextMenuItems(): ListItem[] {
+ return this.logsContainer.queryContextMenuItems;
+ }
+
+ get timeZone(): string {
+ return this.logsContainer.timeZone;
+ }
+
+ get filters(): any {
+ return this.logsContainer.filters;
+ }
+
+ get logsTypeMapObject(): object {
+ return this.logsContainer.logsTypeMap.serviceLogs;
+ }
- readonly timeFormat: string = 'h:mm:ss A';
+ get isContextMenuDisplayed(): boolean {
+ return Boolean(this.selectedText);
+ };
+
+ /**
+ * 'left' CSS property value for context menu dropdown
+ * @type {number}
+ */
+ contextMenuLeft = 0;
+
+ /**
+ * 'top' CSS property value for context menu dropdown
+ * @type {number}
+ */
+ contextMenuTop = 0;
+
+ tableRefresh$ = new Subject();
+
+ subscriptions: Subscription[] = [];
+
+ constructor(
+ private logsContainer: LogsContainerService,
+ private utils: UtilsService,
+ private cdRef: ChangeDetectorRef,
+ private notificationService: NotificationService
+ ) {
+ super();
+ }
+
+ ngOnInit() {
+ this.subscriptions.push(
+ Observable.fromEvent(window,
'resize').auditTime(300).subscribe(this.onWindowResize)
+ );
+ }
+
+ ngAfterViewChecked() {
+ this.checkListLayout();
+ this.cdRef.detectChanges();
+ }
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes.hasOwnProperty('columns')) {
+ this.displayedColumns = this.columns.filter((column: ListItem): boolean
=> column.isChecked);
+ this.tableRefresh$.next(Date.now());
+ }
+ }
+
+ ngOnDestroy() {
+ this.subscriptions.forEach((subscription: Subscription) =>
subscription.unsubscribe());
+ }
private copyLog = (log: ServiceLog): void => {
if (document.queryCommandSupported('copy')) {
@@ -144,15 +227,19 @@ export class ServiceLogsTableComponent extends
LogsTableComponent implements Aft
message: 'logs.copy.notSupported'
});
}
- };
+ }
+
+ private onWindowResize = () => {
+ this.tableRefresh$.next(Date.now());
+ }
private openLog = (log: ServiceLog): void => {
this.logsContainer.openServiceLog(log);
- };
+ }
private openContext = (log: ServiceLog): void => {
this.logsContainer.loadLogContext(log.id, log.host, log.type);
- };
+ }
readonly logActions = [
{
@@ -172,53 +259,6 @@ export class ServiceLogsTableComponent extends
LogsTableComponent implements Aft
}
];
- readonly customStyledColumns: string[] = ['level', 'type', 'logtime',
'log_message', 'path'];
-
- private readonly messageFilterParameterName: string = 'log_message';
-
- private readonly logsType: string = 'serviceLogs';
-
- private selectedText: string = '';
-
- /**
- * This is a private flag to store the table layout check result. It is used
to show user notifications about
- * non-visible information.
- * @type {boolean}
- */
- private tooManyColumnsSelected: boolean = false;
-
- get contextMenuItems(): ListItem[] {
- return this.logsContainer.queryContextMenuItems;
- }
-
- get timeZone(): string {
- return this.logsContainer.timeZone;
- }
-
- get filters(): any {
- return this.logsContainer.filters;
- }
-
- get logsTypeMapObject(): object {
- return this.logsContainer.logsTypeMap.serviceLogs;
- }
-
- get isContextMenuDisplayed(): boolean {
- return Boolean(this.selectedText);
- };
-
- /**
- * 'left' CSS property value for context menu dropdown
- * @type {number}
- */
- contextMenuLeft: number = 0;
-
- /**
- * 'top' CSS property value for context menu dropdown
- * @type {number}
- */
- contextMenuTop: number = 0;
-
isDifferentDates(dateA, dateB): boolean {
return this.utils.isDifferentDates(dateA, dateB, this.timeZone);
}
@@ -319,4 +359,14 @@ export class ServiceLogsTableComponent extends
LogsTableComponent implements Aft
this.logsContainer.updateSelectedColumns(columns, this.logsType);
}
+ /**
+ * The goal is to provide the single source for the parameters of 'xyz
events found' message.
+ * @returns {Object}
+ */
+ get totalEventsFoundMessageParams(): {totalCount: number} {
+ return {
+ totalCount: this.logsContainer.totalCount
+ };
+ }
+
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-histogram/time-histogram.component.html
b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-histogram/time-histogram.component.html
index be68d08..3b66327 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-histogram/time-histogram.component.html
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-histogram/time-histogram.component.html
@@ -24,6 +24,9 @@
<graph-legend [ngClass]="{'col-md-5 text-right': true, 'md-offset-7':
!chartTimeGap}"
[items]="legendItems"></graph-legend>
</div>
+ <div *ngIf="chartLabel" class="row chart-label">
+ <div class="col-md-2 col-md-offset-5">{{ chartLabel }}</div>
+ </div>
</div>
</header>
<div #graphContainer></div>
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-histogram/time-histogram.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-histogram/time-histogram.component.less
index 4859af9..a0b8551 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-histogram/time-histogram.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-histogram/time-histogram.component.less
@@ -22,4 +22,7 @@
header {
padding: @graph-padding;
}
+ .chart-label {
+ text-align: center;
+ }
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
index c3f0b6a..e2393ec 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/components/time-range-picker/time-range-picker.component.html
@@ -26,7 +26,7 @@
<date-picker class="col-md-12 row" [time]="startTime"
(timeChange)="setStartTime($event)"></date-picker>
<div class="col-md-12 row text-uppercase">{{'filter.timeRange.to' |
translate}}</div>
<date-picker class="col-md-12 row" [time]="endTime"
(timeChange)="setEndTime($event)"></date-picker>
- <button class="btn btn-success pull-right" type="button"
(click)="setCustomTimeRange()"
+ <button class="btn btn-success" type="button"
(click)="setCustomTimeRange()"
[disabled]="!startTime || !endTime || startTime >= endTime">
{{'modal.apply' | translate}}
</button>
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.html
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.html
similarity index 62%
copy from
ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.html
copy to
ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.html
index 9e05397..6f83974 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/log-message/log-message.component.html
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.html
@@ -14,11 +14,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<div [ngClass]="{
- 'log-message-container': true,
- 'log-message-container-collapsible': addCaret,
- 'log-message-container-open': isOpen
- }">
- <button *ngIf="addCaret" (click)="onCaretClick($event)"><i
class="caret"></i></button>
- <div #content class="log-message-content">{{isOpen ? message : (message |
replace: multiLineTestRegexp : ' ')}}</div>
-</div>
+<svg [attr.height]="radius * 2" [attr.width]="radius * 2">
+ <circle class="full-circle"
+ [attr.stroke-width]="strokeWidth"
+ [attr.r]="normalizedRadius"
+ [attr.cx]="radius"
+ [attr.cy]="radius"/>
+ <circle #circle
+ [attr.stroke-dasharray]="circumference + ' ' + circumference"
+ [attr.stroke-width]="strokeWidth"
+ [attr.r]="normalizedRadius"
+ [attr.cx]="radius"
+ [attr.cy]="radius"/>
+</svg>
+<label>
+ <ng-content></ng-content>
+</label>
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.less
similarity index 61%
copy from
ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
copy to
ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.less
index 571e6a2..74e8f73 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/components/collapsible-panel/collapsible-panel.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.less
@@ -14,29 +14,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-@import '../../modules/shared/mixins';
-
-.panel-collapsible {
+ @import '../../variables';
+:host {
+ display: inline-block;
position: relative;
- .panel-heading {
- .clickable-item;
- background-color: @panel-heading;
- border: 0 none;
- color: @base-font-color;
- font-size: 1.25rem;
- a, a:hover, a:visited {
- color: @base-font-color;
- text-decoration: none;
- }
- }
- .panel-body {
- padding: 5px;
+ label {
+ align-items: center;
+ align-content: center;
+ background-color: transparent;
+ display: flex;
+ height: 100%;
+ justify-content: center;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
}
- &.panel-collapsed {
- .panel-body {
- height: 0;
- overflow: hidden;
+ svg {
+ circle {
+ fill: transparent;
+ stroke: @blue;
+ transition: stroke-dashoffset 0.35s;
+ transform: rotate(-90deg);
+ transform-origin: 50% 50%;
+ &.full-circle {
+ stroke: @grey;
+ }
}
}
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/time-graph.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.spec.ts
similarity index 53%
copy from
ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/time-graph.component.less
copy to
ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.spec.ts
index 73f1870..b6cf4ca 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/classes/components/graph/time-graph.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.spec.ts
@@ -14,35 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-@import '../../../modules/shared/mixins';
+import { CircleProgressBarComponent } from './circle-progress-bar.component';
-:host {
- background: #FFF; // TODO add style according to actual design
+describe('CircleProgressBarComponent', () => {
+ let component: CircleProgressBarComponent;
+ let fixture: ComponentFixture<CircleProgressBarComponent>;
- /deep/ svg {
- cursor: crosshair;
- }
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CircleProgressBarComponent ]
+ })
+ .compileComponents();
+ }));
- .time-gap {
- color: @base-font-color;
- font-size: 1.2rem;
- text-align: center;
- }
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CircleProgressBarComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
- footer {
- .default-flex;
- font-size: 1.2rem;
- color: @base-font-color;
- padding: 0 1em .5em;
- }
-
- /deep/ rect.drag-area {
- fill: #fff;
- }
-
- /deep/ rect.unselected-drag-area {
- fill: @graph-invert-selection-background;
- opacity: .4;
- }
-}
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.ts
new file mode 100644
index 0000000..c19e4c7
--- /dev/null
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/circle-progress-bar/circle-progress-bar.component.ts
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 {
+ Component,
+ OnInit,
+ OnChanges,
+ Input,
+ ViewChild,
+ ElementRef,
+ SimpleChanges,
+ SimpleChange
+} from '@angular/core';
+
+@Component({
+ selector: 'circle-progress-bar',
+ templateUrl: './circle-progress-bar.component.html',
+ styleUrls: ['./circle-progress-bar.component.less']
+})
+export class CircleProgressBarComponent implements OnInit, OnChanges {
+
+ @Input()
+ radius: number;
+
+ @Input()
+ strokeColor = 'white';
+
+ @Input()
+ strokeWidth: number;
+
+ @Input()
+ fill = 'transparent';
+
+ @Input()
+ percent = 0;
+
+ @Input()
+ label: string;
+
+ @ViewChild('circle')
+ circleRef: ElementRef;
+
+ get normalizedRadius(): number {
+ return this.radius - this.strokeWidth;
+ }
+
+ get circumference(): number {
+ return this.normalizedRadius * 2 * Math.PI;
+ }
+
+ get strokeDashoffset(): number {
+ return this.circumference - (this.percent / 100 * this.circumference);
+ }
+
+ constructor() { }
+
+ ngOnInit() {
+ this.setProgress(this.percent);
+ }
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes.percent) {
+ this.setProgress(this.percent);
+ }
+ }
+
+ setProgress(percent = this.percent) {
+ if (this.circleRef) {
+ this.circleRef.nativeElement.style.strokeDashoffset =
this.strokeDashoffset;
+ }
+ }
+
+}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.less
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.less
index 10f5e1c..dea2c31 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.less
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+ @import '../../variables';
:host {
.modal-backdrop {
opacity: .5;
@@ -29,27 +30,29 @@
flex-direction: column;
max-height: 90vh;
overflow: hidden;
- padding: 1.42rem;
+ padding: @modal-dialog-content-padding;
.modal-header {
- display: block;
+ display: flex;
flex-shrink: 1;
line-height: 1.42rem;
+ padding: @modal-dialog-header-padding;
position: relative;
&> * {
display: inline-block;
}
.close {
- position: absolute;
- top: 0;
- right: 1em;
+ order: 1;
+ margin-left: auto;
}
}
.modal-body {
flex: 1;
overflow: auto;
+ padding: @modal-dialog-body-padding;
}
.modal-footer {
flex-shrink: 1;
+ padding: @modal-dialog-footer-padding;
}
}
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.ts
index 21a4e7e..362f34f 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/components/modal-dialog/modal-dialog.component.ts
@@ -74,7 +74,9 @@ export class ModalDialogComponent implements AfterViewInit {
if (this.showCloseBtn) {
totalBuiltInHeaderElement += 1;
}
- this.showHeader = this.headerElementRef &&
(this.headerElementRef.nativeElement.children.length -
totalBuiltInHeaderElement > 0);
+ this.showHeader = this.showCloseBtn || !!this.title || (
+ this.headerElementRef &&
(this.headerElementRef.nativeElement.children.length -
totalBuiltInHeaderElement > 0)
+ );
this.showFooter = this.footerElementRef &&
this.footerElementRef.nativeElement.children.length;
this.cdRef.detectChanges();
}
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
index 833ef85..8269852 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/shared.module.ts
@@ -40,6 +40,7 @@ import {ModalComponent} from
'./components/modal/modal.component';
import { DataLoadingIndicatorComponent } from
'@app/modules/shared/components/data-loading-indicator/data-loading-indicator.component';
import { ModalDialogComponent } from
'./components/modal-dialog/modal-dialog.component';
import { LoadingIndicatorComponent } from
'./components/loading-indicator/loading-indicator.component';
+import { CircleProgressBarComponent } from
'./components/circle-progress-bar/circle-progress-bar.component';
@NgModule({
imports: [
@@ -64,7 +65,8 @@ import { LoadingIndicatorComponent } from
'./components/loading-indicator/loadin
ModalComponent,
DataLoadingIndicatorComponent,
ModalDialogComponent,
- LoadingIndicatorComponent
+ LoadingIndicatorComponent,
+ CircleProgressBarComponent
],
providers: [
Title,
@@ -80,7 +82,8 @@ import { LoadingIndicatorComponent } from
'./components/loading-indicator/loadin
ModalComponent,
DataLoadingIndicatorComponent,
ModalDialogComponent,
- LoadingIndicatorComponent
+ LoadingIndicatorComponent,
+ CircleProgressBarComponent
]
})
export class SharedModule { }
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/variables.less
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/variables.less
index fb76842..7ffd20c 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/variables.less
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/modules/shared/variables.less
@@ -17,6 +17,14 @@
*/
// Variables
+@blue: #1491C1;
+@grey: #DDD;
+
+@fluid-gray-1: #ccc;
+@fluid-gray-2: #999;
+@fluid-gray-3: #666;
+@fluid-gray-4: #333;
+
@base-font-color: #666;
@navbar-background-color: #323544;
@navbar-logo-background-color: #303d54;
@@ -26,8 +34,8 @@
@input-border: @input-border-width solid #CFD3D7;
@input-group-addon-padding: 6px 12px 6px 0;
@block-margin-top: 20px;
-@link-color: #1491C1;
-@link-hover-color: #23527C;
+@link-color: @blue;
+@link-hover-color: darken(@blue, 10%);
@grey-color: #DDD;
@default-line-height: 1.42857143;
@main-background-color: #ECECEC;
@@ -87,6 +95,10 @@
// Modals
@large-modal-width: 1200px;
+@modal-dialog-content-padding: 2rem;
+@modal-dialog-header-padding: 0 0 1rem 0;
+@modal-dialog-body-padding: 0;
+@modal-dialog-footer-padding: 1rem 0 0 0;
// Notifications
@notification-color: @base-font-color;
diff --git
a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
index efae027..9fba951 100644
---
a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
+++
b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
@@ -59,8 +59,7 @@ import {NodeItem} from '@app/classes/models/node-item';
import {CommonEntry} from '@app/classes/models/common-entry';
import {ClusterSelectionService} from
'@app/services/storage/cluster-selection.service';
import {ActivatedRoute, Router} from '@angular/router';
-import {RoutingUtilsService} from '@app/services/routing-utils.service';
-import {LogsFilteringUtilsService, timeRangeFilterOptions} from
'@app/services/logs-filtering-utils.service';
+import {LogsFilteringUtilsService} from
'@app/services/logs-filtering-utils.service';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {LogsStateService} from '@app/services/storage/logs-state.service';
import {LogLevelComponent} from
'@app/components/log-level/log-level.component';
@@ -244,11 +243,11 @@ export class LogsContainerService {
users: ['userList']
};
- readonly customTimeRangeKey: string = 'filter.timeRange.custom';
+ readonly customTimeRangeKey = 'filter.timeRange.custom';
- readonly topResourcesCount: string = '10';
+ readonly topResourcesCount = '10';
- readonly topUsersCount: string = '6';
+ readonly topUsersCount = '6';
readonly logsTypeMap = {
auditLogs: {
@@ -289,16 +288,16 @@ export class LogsContainerService {
timeZone: string = this.defaultTimeZone;
- totalCount: number = 0;
+ totalCount = 0;
/**
* A configurable property to indicate the maximum capture time in
milliseconds.
* @type {number}
* @default 600000 (10 minutes)
*/
- private readonly maximumCaptureTimeLimit: number = 600000;
+ readonly maximumCaptureTimeLimit = 600000;
- isServiceLogsFileView: boolean = false;
+ isServiceLogsFileView = false;
filtersForm: FormGroup;
@@ -336,16 +335,18 @@ export class LogsContainerService {
private stopAutoRefreshCountdown: Subject<void> = new Subject();
- captureSeconds: number = 0;
+ captureSeconds = 0;
- private readonly autoRefreshInterval: number = 30000;
+ readonly autoRefreshInterval = 30000;
- autoRefreshRemainingSeconds: number = 0;
+ autoRefreshRemainingSeconds = 0;
private startCaptureTime: number;
private stopCaptureTime: number;
+ captureTimeRangeCache: ListItem;
+
topUsersGraphData: HomogeneousObject<HomogeneousObject<number>> = {};
topResourcesGraphData: HomogeneousObject<HomogeneousObject<number>> = {};
@@ -757,16 +758,23 @@ export class LogsContainerService {
this.stopCaptureTime = new Date().valueOf();
this.captureSeconds = 0;
this.stopTimer.next();
- this.setCustomTimeRange(this.startCaptureTime, this.stopCaptureTime);
Observable.timer(0,
1000).takeUntil(this.stopAutoRefreshCountdown).subscribe((seconds: number):
void => {
this.autoRefreshRemainingSeconds = autoRefreshIntervalSeconds - seconds;
if (!this.autoRefreshRemainingSeconds) {
this.stopAutoRefreshCountdown.next();
+ this.captureTimeRangeCache = this.filtersForm.controls.timeRange.value;
this.setCustomTimeRange(this.startCaptureTime, this.stopCaptureTime);
}
});
}
+ cancelCapture(): void {
+ this.stopTimer.next();
+ this.stopAutoRefreshCountdown.next();
+ this.autoRefreshRemainingSeconds = 0;
+ this.captureSeconds = 0;
+ }
+
loadClusters(): void {
}
diff --git a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
index 66b68cb..a0796ac 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
+++ b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
@@ -47,7 +47,13 @@
"filter.users": "Users",
"filter.capture": "Capture",
+ "filter.captureSnapshot": "Snapshot",
+ "filter.refreshingLogListIn": "Refreshing log list in...",
+ "filter.capture.min": "Min",
+ "filter.capture.sec": "Sec",
"filter.capture.triggeringRefresh": "Triggering auto-refresh in
{{remainingSeconds}} sec",
+ "filter.youAreInSnapshotView": "You are in snapshot view",
+ "filter.closeSnapshotView": "Close snapshot view",
"filters.clear": "Clear",
diff --git a/ambari-logsearch/ambari-logsearch-web/yarn.lock
b/ambari-logsearch/ambari-logsearch-web/yarn.lock
index deb8288..ae4bb5a 100644
--- a/ambari-logsearch/ambari-logsearch-web/yarn.lock
+++ b/ambari-logsearch/ambari-logsearch-web/yarn.lock
@@ -4192,9 +4192,9 @@ [email protected]:
version "0.6.1"
resolved
"https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
-ngx-bootstrap@^1.9.3:
- version "1.9.3"
- resolved
"https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-1.9.3.tgz#28e75d14fb1beaee609383d7694de4eb3ba03b26"
+ngx-bootstrap@^2.0.5:
+ version "2.0.5"
+ resolved
"https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-2.0.5.tgz#83aab39d1e4fe811fad2b34f7927f9ce19d68daa"
no-case@^2.2.0:
version "2.3.1"