import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CssHelper } from '~/app/shared/classes/css-helper';
import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
import { DimlessPipe } from '~/app/shared/pipes/dimless.pipe';
import { FormatterService } from '~/app/shared/services/formatter.service';
configureTestBed({
schemas: [NO_ERRORS_SCHEMA],
declarations: [HealthPieComponent],
- providers: [DimlessBinaryPipe, DimlessPipe, FormatterService]
+ providers: [DimlessBinaryPipe, DimlessPipe, FormatterService, CssHelper]
});
beforeEach(() => {
import _ from 'lodash';
import { PluginServiceGlobalRegistrationAndOptions } from 'ng2-charts';
+import { CssHelper } from '~/app/shared/classes/css-helper';
import { ChartTooltip } from '~/app/shared/models/chart-tooltip';
import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
import { DimlessPipe } from '~/app/shared/pipes/dimless.pipe';
-import styles from '~/styles.scss';
@Component({
selector: 'cd-health-pie',
colors: [
{
backgroundColor: [
- styles.chartHealthColorGreen,
- styles.chartHealthColorYellow,
- styles.chartHealthColorOrange,
- styles.chartHealthColorRed,
- styles.chartHealthColorBlue
+ this.cssHelper.propertyValue('chart-color-green'),
+ this.cssHelper.propertyValue('chart-color-yellow'),
+ this.cssHelper.propertyValue('chart-color-orange'),
+ this.cssHelper.propertyValue('chart-color-red'),
+ this.cssHelper.propertyValue('chart-color-blue')
]
}
],
tooltips: {
enabled: true,
displayColors: false,
- backgroundColor: styles.chartHealthTootlipBgColor,
+ backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
cornerRadius: 0,
bodyFontSize: 14,
bodyFontStyle: '600',
{
id: 'center_text',
beforeDraw(chart: Chart) {
+ const cssHelper = new CssHelper();
const defaultFontFamily = 'Helvetica Neue, Helvetica, Arial, sans-serif';
Chart.defaults.global.defaultFontFamily = defaultFontFamily;
const ctx = chart.ctx;
ctx.textBaseline = 'middle';
ctx.font = `24px ${defaultFontFamily}`;
- ctx.fillStyle = styles.chartHealthCenterTextColor;
+ ctx.fillStyle = cssHelper.propertyValue('chart-color-center-text');
ctx.fillText(label[0], centerX, centerY - 10);
if (label.length > 1) {
ctx.font = `14px ${defaultFontFamily}`;
- ctx.fillStyle = styles.chartHealthCenterTextDescriptionColor;
+ ctx.fillStyle = cssHelper.propertyValue('chart-color-center-text-description');
ctx.fillText(label[1], centerX, centerY + 10);
}
ctx.restore();
}
];
- constructor(private dimlessBinary: DimlessBinaryPipe, private dimless: DimlessPipe) {}
+ constructor(
+ private dimlessBinary: DimlessBinaryPipe,
+ private dimless: DimlessPipe,
+ private cssHelper: CssHelper
+ ) {}
ngOnInit() {
const getStyleTop = (tooltip: any, positionY: number) => {
import { PgCategoryService } from '~/app/ceph/shared/pg-category.service';
import { HealthService } from '~/app/shared/api/health.service';
+import { CssHelper } from '~/app/shared/classes/css-helper';
import { Permissions } from '~/app/shared/models/permissions';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
import { FeatureTogglesService } from '~/app/shared/services/feature-toggles.service';
providers: [
{ provide: AuthStorageService, useValue: fakeAuthStorageService },
PgCategoryService,
- RefreshIntervalService
+ RefreshIntervalService,
+ CssHelper
]
});
import { PgCategoryService } from '~/app/ceph/shared/pg-category.service';
import { HealthService } from '~/app/shared/api/health.service';
+import { CssHelper } from '~/app/shared/classes/css-helper';
import { Icons } from '~/app/shared/enum/icons.enum';
import { Permissions } from '~/app/shared/models/permissions';
import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
FeatureTogglesService
} from '~/app/shared/services/feature-toggles.service';
import { RefreshIntervalService } from '~/app/shared/services/refresh-interval.service';
-import styles from '~/styles.scss';
@Component({
selector: 'cd-health',
clientStatsConfig = {
colors: [
{
- backgroundColor: [styles.chartHealthColorCyan, styles.chartHealthColorPurple]
+ backgroundColor: [
+ this.cssHelper.propertyValue('chart-color-cyan'),
+ this.cssHelper.propertyValue('chart-color-purple')
+ ]
}
]
};
rawCapacityChartConfig = {
colors: [
{
- backgroundColor: [styles.chartHealthColorBlue, styles.chartHealthColorGray]
+ backgroundColor: [
+ this.cssHelper.propertyValue('chart-color-blue'),
+ this.cssHelper.propertyValue('chart-color-gray')
+ ]
}
]
};
private featureToggles: FeatureTogglesService,
private refreshIntervalService: RefreshIntervalService,
private dimlessBinary: DimlessBinaryPipe,
- private dimless: DimlessPipe
+ private dimless: DimlessPipe,
+ private cssHelper: CssHelper
) {
this.permissions = this.authStorageService.getPermissions();
this.enabledFeature$ = this.featureToggles.get();
import { Component, NgZone, OnInit, TemplateRef, ViewChild } from '@angular/core';
-import * as _ from 'lodash';
+import _ from 'lodash';
import { forkJoin as observableForkJoin, Observable, Subscriber } from 'rxjs';
import { RgwUserService } from '~/app/shared/api/rgw-user.service';
import { ToastrModule } from 'ngx-toastr';
import { RbdService } from '~/app/shared/api/rbd.service';
+import { CssHelper } from '~/app/shared/classes/css-helper';
import { PipesModule } from '~/app/shared/pipes/pipes.module';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
import { configureTestBed } from '~/testing/unit-test-helper';
imports: [RouterTestingModule, ToastrModule.forRoot(), PipesModule, HttpClientTestingModule],
declarations: [WorkbenchLayoutComponent],
schemas: [NO_ERRORS_SCHEMA],
- providers: [AuthStorageService, RbdService]
+ providers: [AuthStorageService, CssHelper, RbdService]
});
beforeEach(() => {
-import * as _ from 'lodash';
+import _ from 'lodash';
export class CdHelperClass {
/**
--- /dev/null
+export class CssHelper {
+ propertyValue(propertyName: string): string {
+ return getComputedStyle(document.body).getPropertyValue(`--${propertyName}`);
+ }
+}
+++ /dev/null
-import styles from '~/styles.scss';
-
-export class Color {
- // HEALTH
- static HEALTH_ERR = styles.healthColorError;
- static HEALTH_WARN = styles.healthColorWarning;
- static HEALTH_OK = styles.healthColorHealthy;
-}
--- /dev/null
+export enum HealthColor {
+ HEALTH_ERR = 'health-color-error',
+ HEALTH_WARN = 'health-color-warning',
+ HEALTH_OK = 'health-color-healthy'
+}
-import styles from '~/styles.scss';
-import { HealthColorPipe } from './health-color.pipe';
+import { CssHelper } from '~/app/shared/classes/css-helper';
+import { HealthColorPipe } from '~/app/shared/pipes/health-color.pipe';
+
+class CssHelperStub extends CssHelper {
+ propertyValue(propertyName: string) {
+ if (propertyName === 'health-color-healthy') {
+ return 'fakeGreen';
+ }
+ if (propertyName === 'health-color-warning') {
+ return 'fakeOrange';
+ }
+ if (propertyName === 'health-color-error') {
+ return 'fakeRed';
+ }
+ return '';
+ }
+}
describe('HealthColorPipe', () => {
- const pipe = new HealthColorPipe();
+ const pipe = new HealthColorPipe(new CssHelperStub());
it('create an instance', () => {
expect(pipe).toBeTruthy();
});
it('transforms "HEALTH_OK"', () => {
- expect(pipe.transform('HEALTH_OK')).toEqual({ color: styles.healthColorHealthy });
+ expect(pipe.transform('HEALTH_OK')).toEqual({
+ color: 'fakeGreen'
+ });
});
it('transforms "HEALTH_WARN"', () => {
- expect(pipe.transform('HEALTH_WARN')).toEqual({ color: styles.healthColorWarning });
+ expect(pipe.transform('HEALTH_WARN')).toEqual({
+ color: 'fakeOrange'
+ });
});
it('transforms "HEALTH_ERR"', () => {
- expect(pipe.transform('HEALTH_ERR')).toEqual({ color: styles.healthColorError });
+ expect(pipe.transform('HEALTH_ERR')).toEqual({
+ color: 'fakeRed'
+ });
});
it('transforms others', () => {
import { Pipe, PipeTransform } from '@angular/core';
-import { Color } from '../enum/color.enum';
+import { CssHelper } from '~/app/shared/classes/css-helper';
+import { HealthColor } from '~/app/shared/enum/health-color.enum';
@Pipe({
name: 'healthColor'
})
export class HealthColorPipe implements PipeTransform {
+ constructor(private cssHelper: CssHelper) {}
+
transform(value: any): any {
- return Color[value] ? { color: Color[value] } : null;
+ return Object.keys(HealthColor).includes(value as HealthColor)
+ ? { color: this.cssHelper.propertyValue(HealthColor[value]) }
+ : null;
}
}
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
+import { CssHelper } from '~/app/shared/classes/css-helper';
import { configureTestBed } from '~/testing/unit-test-helper';
import { FaviconService } from './favicon.service';
configureTestBed({
imports: [HttpClientTestingModule],
- providers: [FaviconService]
+ providers: [FaviconService, CssHelper]
});
beforeEach(() => {
import { Subscription } from 'rxjs';
-import { Color } from '../enum/color.enum';
+import { CssHelper } from '~/app/shared/classes/css-helper';
+import { HealthColor } from '~/app/shared/enum/health-color.enum';
import { SummaryService } from './summary.service';
@Injectable()
constructor(
@Inject(DOCUMENT) private document: HTMLDocument,
- private summaryService: SummaryService
+ private summaryService: SummaryService,
+ private cssHelper: CssHelper
) {}
init() {
// Draw Original Favicon as Background
context.drawImage(img, 0, 0, faviconSize, faviconSize);
- if (Color[status]) {
+ if (Object.keys(HealthColor).includes(status as HealthColor)) {
// Cut notification circle area
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(canvas.width - radius, radius, radius, 0, 2 * Math.PI);
- context.fillStyle = Color[status];
+ context.fillStyle = this.cssHelper.propertyValue(HealthColor[status]);
context.fill();
}
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
+import { CssHelper } from '~/app/shared/classes/css-helper';
import { ComponentsModule } from './components/components.module';
import { DataTableModule } from './datatable/datatable.module';
import { DirectivesModule } from './directives/directives.module';
imports: [CommonModule, PipesModule, ComponentsModule, DataTableModule, DirectivesModule],
declarations: [],
exports: [ComponentsModule, PipesModule, DataTableModule, DirectivesModule],
- providers: [AuthStorageService, AuthGuardService, FormatterService]
+ providers: [AuthStorageService, AuthGuardService, FormatterService, CssHelper]
})
export class SharedModule {}
import 'jest-preset-angular';
import './jestGlobalMocks';
+
+process.on('unhandledRejection', (error) => {
+ const stack = error['stack'] || '';
+ // Avoid potential hang on test failure when running tests in parallel.
+ throw `WARNING: unhandled rejection: ${error} ${stack}`;
+});
a {
cursor: pointer;
}
-
-:export {
- chartHealthCenterTextColor: #151515;
- chartHealthCenterTextDescriptionColor: #72767b;
- chartHealthColorBlue: #06c;
- chartHealthColorCyan: #73c5c5;
- chartHealthColorGray: #ededed;
- chartHealthColorGreen: #7cc674;
- chartHealthColorLightBlue: #519de9;
- chartHealthColorLightYellow: #f9e0a2;
- chartHealthColorMagenta: #009596;
- chartHealthColorOrange: #ef9234;
- chartHealthColorPurple: #3c3d99;
- chartHealthColorRed: #c9190b;
- chartHealthColorYellow: #f6d173;
- chartHealthTootlipBgColor: #000;
-
- healthColorError: #f00;
- healthColorHealthy: #0b0;
- healthColorWarning: #ffa500;
-}
+++ /dev/null
-export interface Styles {
- chartHealthColorRed: string;
- chartHealthColorBlue: string;
- chartHealthColorOrange: string;
- chartHealthColorYellow: string;
- chartHealthColorMagenta: string;
- chartHealthColorGreen: string;
- chartHealthColorGray: string;
- chartHealthColorLightBlue: string;
- chartHealthColorLightYellow: string;
- chartHealthColorCyan: string;
- chartHealthColorPurple: string;
-
- chartHealthCenterTextColor: string;
- chartHealthCenterTextDescriptionColor: string;
- chartHealthTootlipBgColor: string;
-
- healthColorError: string;
- healthColorWarning: string;
- healthColorHealthy: string;
-}
-
-export const styles: Styles;
-
-export default styles;
) !default;
// Body
-
$body-color-bright: $light !default;
$body-bg: $white !default;
$body-color: $gray-900 !default;
$body-bg-alt: $gray-200 !default;
+// Health colors.
+$health-color-error: #f00 !default;
+$health-color-healthy: $green !default;
+$health-color-warning: #ffa500 !default;
+
+// Chart colors.
+$chart-color-red: #c9190b !default;
+$chart-color-blue: #06c !default;
+$chart-color-orange: #ef9234 !default;
+$chart-color-yellow: #f6d173 !default;
+$chart-color-green: #7cc674 !default;
+$chart-color-gray: #ededed !default;
+$chart-color-cyan: #73c5c5 !default;
+$chart-color-purple: #3c3d99 !default;
+$chart-color-center-text: #151515 !default;
+$chart-color-center-text-description: #72767b !default;
+$chart-color-tooltip-background: $black !default;
+
// Typography
$font-family-sans-serif: 'Helvetica Neue', Helvetica, Arial, 'Noto Sans', sans-serif,
@forward 'style-overrides';
@forward 'variables';
+
+@use 'sass:meta';
+@use 'variables';
+
+@function custom-property-name($name) {
+ @return '--' + $name;
+}
+
+@mixin define-custom-property($name, $value) {
+ #{custom-property-name($name)}: meta.inspect($value);
+}
+
+:root {
+ // Make vendor variables accessible to JS/TS code via CSS custom property definition.
+ @each $key_name, $value in meta.module-variables('variables') {
+ @if type-of($value) != 'map' {
+ @include define-custom-property($key_name, $value);
+ }
+ }
+}