diff --git a/.github/workflows/gcp.yml b/.github/workflows/gcp.yml
index d45af49..83b4004 100644
--- a/.github/workflows/gcp.yml
+++ b/.github/workflows/gcp.yml
@@ -2,8 +2,8 @@ name: GCP CI/CD Pipeline
on:
push:
- branches:
- - '**'
+ branches: [ "main" ]
+
env:
PROJECT_ID: ${{ secrets.GKE_PROJECT }}
diff --git a/blogs-analyzer-ui/package.json b/blogs-analyzer-ui/package.json
index d2238cc..f2df22b 100644
--- a/blogs-analyzer-ui/package.json
+++ b/blogs-analyzer-ui/package.json
@@ -27,6 +27,7 @@
"bootstrap": "^5.3.0",
"highcharts": "^11.4.3",
"highcharts-angular": "^4.0.0",
+ "ngx-doc-viewer": "^15.0.1",
"ngx-logger": "^5.0.12",
"ngx-markdown": "^16.0.0",
"rxjs": "~7.8.0",
@@ -50,4 +51,4 @@
"sonar-scanner": "^3.1.0",
"typescript": "~5.0.2"
}
-}
\ No newline at end of file
+}
diff --git a/blogs-analyzer-ui/src/app/app.module.ts b/blogs-analyzer-ui/src/app/app.module.ts
index 60b4af5..07bcfd9 100644
--- a/blogs-analyzer-ui/src/app/app.module.ts
+++ b/blogs-analyzer-ui/src/app/app.module.ts
@@ -21,6 +21,8 @@ import { HighchartsChartModule } from "highcharts-angular";
import { MarkdownModule } from "ngx-markdown";
import { LoggerModule, NgxLoggerLevel } from "ngx-logger";
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgxDocViewerModule } from "ngx-doc-viewer";
+import { MatTooltipModule } from "@angular/material/tooltip";
@NgModule({
declarations: [
@@ -45,12 +47,14 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
MatButtonModule,
HighchartsChartModule,
MarkdownModule.forRoot(),
+ NgxDocViewerModule,
LoggerModule.forRoot({
level: NgxLoggerLevel.DEBUG,
serverLogLevel: NgxLoggerLevel.ERROR,
disableConsoleLogging: false
}),
- NgbModule
+ NgbModule,
+ MatTooltipModule
],
providers: [],
bootstrap: [AppComponent]
diff --git a/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.html b/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.html
index e95efe3..e0faec1 100644
--- a/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.html
+++ b/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.html
@@ -22,6 +22,13 @@
{{ errorMessage }}
+
+
+
+
+
Existing Blogs
diff --git a/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.scss b/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.scss
index 337110d..fe01f5c 100644
--- a/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.scss
+++ b/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.scss
@@ -83,3 +83,11 @@
0 1px 1px 0 #9b9b9b,
0 1px 1px 0 #9b9b9b;
}
+
+.upload-label {
+ cursor: pointer;
+}
+
+.file-upload {
+ color: red;
+}
diff --git a/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.spec.ts b/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.spec.ts
index c2d0f58..d9be440 100644
--- a/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.spec.ts
+++ b/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.spec.ts
@@ -165,4 +165,37 @@ describe('HomeComponent', () => {
expect(logger.error).toHaveBeenCalledWith(`Error fetching post by ID: ${mockError.message}`);
});
+ it('should handle valid .docx file in onFileSelected', () => {
+ const mockFile = new File([''], 'test.docx', {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
+ const event = {target: {files: [mockFile]}} as unknown as Event;
+ const mockFileUrl = 'mock-url';
+
+ spyOn(window, 'FileReader').and.returnValue({
+ readAsDataURL: () => {
+ },
+ onload: (e: any) => {
+ e.target.result = mockFileUrl;
+ component.onFileSelected(event);
+ expect(component.fileUrl).toEqual(mockFileUrl);
+ expect(router.navigate).toHaveBeenCalledWith(['/quality-check'], {state: {url: mockFileUrl}});
+ }
+ } as any);
+
+ component.onFileSelected(event);
+ });
+
+ it('should handle invalid file type in onFileSelected', () => {
+ const mockFile = new File([''], 'test.pdf', {type: 'application/pdf'});
+ const event = {target: {files: [mockFile]}} as unknown as Event;
+ component.onFileSelected(event);
+ expect(component.errorMessage).toEqual('Invalid file type.
Please upload a .doc/.docx file.');
+ expect(router.navigate).not.toHaveBeenCalled();
+ });
+
+ it('should not set errorMessage if no file is selected', () => {
+ const event = {target: {files: []}} as unknown as Event;
+ component.onFileSelected(event);
+ expect(component.errorMessage).toBeNull();
+ expect(router.navigate).not.toHaveBeenCalled();
+ });
});
diff --git a/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.ts b/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.ts
index 43bc611..74416cf 100644
--- a/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.ts
+++ b/blogs-analyzer-ui/src/app/dashboard/components/home/home.component.ts
@@ -14,6 +14,7 @@ export class HomeComponent {
authorId!: number;
errorMessage: string | null = null;
errorContext: 'title' | 'author' | 'id' | null = null;
+ fileUrl: any
constructor(
private blogService: BlogService,
@@ -71,4 +72,26 @@ export class HomeComponent {
});
}
}
+
+ onFileSelected(event: Event): void {
+ const input = event.target as HTMLInputElement;
+
+ if (input.files?.[0]) {
+ const file = input.files[0];
+ const fileType = file.name.split('.').pop()?.toLowerCase();
+
+ if (fileType === 'doc' || fileType === 'docx') {
+ this.errorMessage = null;
+ const reader = new FileReader();
+
+ reader.onload = (e) => {
+ this.fileUrl = e.target?.result as string;
+ this.router.navigate(['/quality-check'], { state: { url: this.fileUrl } });
+ };
+ reader.readAsDataURL(file);
+ } else {
+ this.errorMessage = `Invalid file type.
Please upload a .doc/.docx file.`;
+ }
+ }
+ }
}
diff --git a/blogs-analyzer-ui/src/app/dashboard/components/tabular-view/tabular-view.component.spec.ts b/blogs-analyzer-ui/src/app/dashboard/components/tabular-view/tabular-view.component.spec.ts
index ca0db6f..2634e7c 100644
--- a/blogs-analyzer-ui/src/app/dashboard/components/tabular-view/tabular-view.component.spec.ts
+++ b/blogs-analyzer-ui/src/app/dashboard/components/tabular-view/tabular-view.component.spec.ts
@@ -22,7 +22,7 @@ describe('TabularViewComponent', () => {
serverLogLevel: NgxLoggerLevel.ERROR
})],
providers: [
- {provide: NGXLogger, useValue: loggerSpy}
+ { provide: NGXLogger, useValue: loggerSpy }
],
schemas: [NO_ERRORS_SCHEMA]
});
@@ -99,7 +99,81 @@ describe('TabularViewComponent', () => {
expect(component.loading).toBeFalse();
expect(component.errorMessage).toContain('Failed to fetch Data');
- expect(component.logger.error).toHaveBeenCalledWith('Error fetching posts for page 1: Failed to fetch posts');
+ expect(logger.error).toHaveBeenCalledWith('Error fetching posts for page 1: Failed to fetch posts');
});
+ it('should initialize column definitions', () => {
+ expect(component.columnDefs.length).toBeGreaterThan(0);
+ expect(component.columnDefs[0].headerName).toBe('Blog ID');
+ });
+
+ it('should emit click event', () => {
+ spyOn(component.clickEvent, 'emit');
+ component.clickEvent.emit(1);
+
+ expect(component.clickEvent.emit).toHaveBeenCalledWith(1);
+ });
+
+ it('should handle quality check button click', () => {
+ const mockResponse = { id: 1, title: 'Test Post' };
+ spyOn(component.blogService, 'getPostById').and.returnValue(of(mockResponse));
+ spyOn(component.router, 'navigate');
+
+ const params = { data: { id: 1 } };
+ component.columnDefs.find(col => col.field === 'id' && col.headerName === 'Quality Check').onCellClicked(params);
+
+ expect(logger.debug).toHaveBeenCalledWith('Initiating quality check for blog ID: 1');
+ expect(component.router.navigate).toHaveBeenCalledWith(['/quality-check'], { state: { data: mockResponse } });
+ });
+
+ it('should handle error during quality check button click', () => {
+ const mockError = new Error('Failed to fetch post by ID');
+ spyOn(component.blogService, 'getPostById').and.returnValue(throwError(mockError));
+
+ const params = { data: { id: 1 } };
+ component.columnDefs.find(col => col.field === 'id' && col.headerName === 'Quality Check').onCellClicked(params);
+
+ expect(logger.error).toHaveBeenCalledWith('Error fetching post by ID 1: Failed to fetch post by ID');
+ expect(component.errorMessage).toContain('Failed to fetch Data');
+ });
+
+ it('should have loading state initially', () => {
+ expect(component.loading).toBeTrue();
+ });
+
+ it('should update loading state after fetchPosts call', () => {
+ const mockData = { posts: [], totalPages: 1, isLastPage: true };
+ spyOn(component.blogService, 'getAllPosts').and.returnValue(of(mockData));
+
+ component.fetchPosts(1);
+
+ expect(component.loading).toBeFalse();
+ });
+
+ it('should set isLastPage correctly', () => {
+ const mockData = { posts: [], totalPages: 1, isLastPage: true };
+ spyOn(component.blogService, 'getAllPosts').and.returnValue(of(mockData));
+
+ component.fetchPosts(1);
+
+ expect(component.isLastPage).toBeTrue();
+ });
+
+ it('should set totalPages correctly', () => {
+ const mockData = { posts: [], totalPages: 3, isLastPage: false };
+ spyOn(component.blogService, 'getAllPosts').and.returnValue(of(mockData));
+
+ component.fetchPosts(1);
+
+ expect(component.totalPages).toBe(3);
+ });
+
+ it('should handle click event for view button', () => {
+ spyOn(window, 'open');
+
+ const params = { data: { url: 'http://example.com' } };
+ component.columnDefs.find(col => col.field === 'url' && col.headerName === 'View').onCellClicked(params);
+
+ expect(window.open).toHaveBeenCalledWith('http://example.com', '_blank');
+ });
});
diff --git a/blogs-analyzer-ui/src/app/dashboard/components/tabular-view/tabular-view.component.ts b/blogs-analyzer-ui/src/app/dashboard/components/tabular-view/tabular-view.component.ts
index 5095c53..5184810 100644
--- a/blogs-analyzer-ui/src/app/dashboard/components/tabular-view/tabular-view.component.ts
+++ b/blogs-analyzer-ui/src/app/dashboard/components/tabular-view/tabular-view.component.ts
@@ -9,7 +9,7 @@ import { NGXLogger } from 'ngx-logger';
styleUrls: ['./tabular-view.component.scss']
})
export class TabularViewComponent implements OnInit {
- protected columnDefs: any[];
+ columnDefs: any[];
rowData: any[];
loading: boolean = true;
currentPage: number = 1;
diff --git a/blogs-analyzer-ui/src/app/quality-check/quality-check.component.html b/blogs-analyzer-ui/src/app/quality-check/quality-check.component.html
index 2937531..adb77b8 100644
--- a/blogs-analyzer-ui/src/app/quality-check/quality-check.component.html
+++ b/blogs-analyzer-ui/src/app/quality-check/quality-check.component.html
@@ -5,35 +5,62 @@
Back
-
+
+
+
+
+
HTML Preview
-
-
+
+
+
+
+
+
+
+
+
-
-
- {{ errorMessage }}
-
-
0">
-
-
Overall Rating:
-
{{ overallRating | number:'1.1-1' }}
-
-
Overall Feedback:
-
{{ overallFeedback }}
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
0">
+
+
Overall Rating:
+
{{ overallRating | number:'1.1-1' }}
+
+
Overall Feedback:
+
{{ overallFeedback }}
+
+
-
+
diff --git a/blogs-analyzer-ui/src/app/quality-check/quality-check.component.scss b/blogs-analyzer-ui/src/app/quality-check/quality-check.component.scss
index e9c1668..7bd9d34 100644
--- a/blogs-analyzer-ui/src/app/quality-check/quality-check.component.scss
+++ b/blogs-analyzer-ui/src/app/quality-check/quality-check.component.scss
@@ -135,3 +135,10 @@ textarea {
.ngb-rating .star.empty {
color: #d3d3d3;
}
+
+.spinner {
+ height: 200px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
\ No newline at end of file
diff --git a/blogs-analyzer-ui/src/app/quality-check/quality-check.component.spec.ts b/blogs-analyzer-ui/src/app/quality-check/quality-check.component.spec.ts
index f56b5bc..529816e 100644
--- a/blogs-analyzer-ui/src/app/quality-check/quality-check.component.spec.ts
+++ b/blogs-analyzer-ui/src/app/quality-check/quality-check.component.spec.ts
@@ -57,7 +57,7 @@ describe('QualityCheckComponent', () => {
- Code Examples and Illustrations
- Links and References
- Overall Feedback %
- Display result in tabular view for respective percentages and accurate feedback;`;
+ Display result in tabular view for respective percentages with accurate feedback;`;
spyOn(blogService, 'getBlogQuality').and.returnValue(of(''));
component.checkQuality();
@@ -112,79 +112,40 @@ describe('QualityCheckComponent', () => {
it('should handle error in checkQuality()', () => {
component.postData = 'Sample blog content';
- const expectedPrompt = `Review blog with the following content: Sample blog content
- Parameters include fields like:
- - Duplicate Content
- - Spelling Mistakes
- - Overall Feedback %
- Display result in tabular view for respective percentages and accurate feedback;`;
-
spyOn(blogService, 'getBlogQuality').and.returnValue(throwError({message: 'Test error message'}));
component.checkQuality();
-
expect(component.errorMessage).toContain('Failed to check blog quality');
});
- it('should navigate back on goBack()', () => {
- const locationSpy = spyOn(component['location'], 'back');
- component.goBack();
-
- expect(locationSpy).toHaveBeenCalled();
- });
-
- it('should parse a valid response correctly', () => {
+ it('should calculate overall rating and feedback correctly', () => {
const response = `
- | Label | Percentage | Comment |
- | Duplicate Content | 10% | Some duplicate content |
- | Spelling Mistakes | 5% | Some spelling mistakes |`;
- const expectedResults = [
- {
- originalLabel: 'Duplicate Content',
- oppositeLabel: 'Original Content',
- value: 10,
- comment: 'Some duplicate content'
- },
- {
- originalLabel: 'Spelling Mistakes',
- oppositeLabel: 'Correct Spelling',
- value: 5,
- comment: 'Some spelling mistakes'
- }
- ];
- const results = component.parseResponse(response);
- expect(results).toEqual(expectedResults);
+ | Label | Percentage | Comment |
+ | OVERALL FEEDBACK % | 80% | Very good content |`;
+ component.parseResponse(response);
+ expect(component.overallRating).toEqual(4);
+ expect(component.overallFeedback).toEqual('Very good content');
});
- it('should handle an empty response', () => {
- const response = '';
- const results = component.parseResponse(response);
- expect(results).toEqual([]);
+ it('should handle blogService.getBlogQuality response correctly in checkQuality()', () => {
+ component.draftPost = 'Sample draft content';
+ spyOn(blogService, 'getBlogQuality').and.returnValue(of('yes'));
+ component.checkQuality();
+ expect(component.isLoading).toBe(false);
});
- it('should handle a response with partially valid rows', () => {
- const response = `
- | Label | Percentage | Comment |
- | Duplicate Content | 10% | Some duplicate content |
- | Invalid Row`;
- const expectedResults = [
- {
- originalLabel: 'Duplicate Content',
- oppositeLabel: 'Original Content',
- value: 10,
- comment: 'Some duplicate content'
- }
- ];
- const results = component.parseResponse(response);
- expect(results).toEqual(expectedResults);
+ it('should handle blogService.getBlogQuality error in checkQuality()', () => {
+ component.draftPost = 'Sample draft content';
+ spyOn(blogService, 'getBlogQuality').and.returnValue(throwError({ message: 'Test error' }));
+ component.checkQuality();
+ expect(component.errorMessage).toBe('Failed to check blog quality. Please try again later.
Test error');
});
- it('should calculate overall rating and feedback correctly', () => {
- const response = `
- | Label | Percentage | Comment |
- | OVERALL FEEDBACK % | 80% | Very good content |`;
- const expectedOverallRating = 4;
- component.parseResponse(response);
- expect(component.overallRating).toEqual(expectedOverallRating);
- expect(component.overallFeedback).toEqual('Very good content');
+ it('should unsubscribe from all subscriptions on ngOnDestroy', () => {
+ const subscription1 = jasmine.createSpyObj('Subscription', ['unsubscribe']);
+ const subscription2 = jasmine.createSpyObj('Subscription', ['unsubscribe']);
+ component.subscriptions.push(subscription1, subscription2);
+ component.ngOnDestroy();
+ expect(subscription1.unsubscribe).toHaveBeenCalled();
+ expect(subscription2.unsubscribe).toHaveBeenCalled();
});
});
diff --git a/blogs-analyzer-ui/src/app/quality-check/quality-check.component.ts b/blogs-analyzer-ui/src/app/quality-check/quality-check.component.ts
index 2435477..55589ef 100644
--- a/blogs-analyzer-ui/src/app/quality-check/quality-check.component.ts
+++ b/blogs-analyzer-ui/src/app/quality-check/quality-check.component.ts
@@ -1,19 +1,26 @@
-import { Component, OnInit } from '@angular/core';
+import { AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Location } from "@angular/common";
import { BlogService } from "../services/blog.service";
import { NGXLogger } from 'ngx-logger';
+import { Subscription } from 'rxjs';
@Component({
selector: 'app-quality-check',
templateUrl: './quality-check.component.html',
styleUrls: ['./quality-check.component.scss']
})
-export class QualityCheckComponent implements OnInit {
- postData: any;
+export class QualityCheckComponent implements OnInit, AfterViewInit, OnDestroy {
+ @ViewChild('docViewer') docViewer!: ElementRef;
+ fileUrl: string = '';
+ postData: string | undefined;
qualityResults: { originalLabel: string; oppositeLabel: string; value: number; comment: string }[] = [];
errorMessage: string | null = null;
overallFeedback: string | null = null;
overallRating: number = 0;
+ isLoading: boolean = false;
+ initialLoading: boolean = false;
+ draftPost!: string;
+ subscriptions: Subscription[] = [];
labels = [
{actual: 'Duplicate Content', opposite: 'Original Content'},
@@ -37,31 +44,84 @@ export class QualityCheckComponent implements OnInit {
ngOnInit(): void {
this.postData = history?.state?.data;
+ this.fileUrl = history?.state?.url;
this.logger.debug('Initialized QualityCheckComponent');
}
+ ngAfterViewInit(): void {
+ setTimeout(() => {
+ if (this.docViewer?.nativeElement) {
+ this.draftPost = this.docViewer.nativeElement.firstElementChild?.firstElementChild?.innerHTML || '';
+ this.logger.debug('Draft Content fetched successfully :: ' + this.draftPost);
+ }
+ }, 500);
+ }
+
goBack(): void {
this.location.back();
this.logger.debug('Navigated back');
}
checkQuality() {
- const prompt = `Review blog with the following content: ${this.postData}
+ if (!this.draftPost && !this.postData) {
+ this.errorMessage = 'No blog content available to check quality.';
+ this.logger.error(`Error checking blog content: ${this.errorMessage}`);
+ return;
+ }
+
+ this.isLoading = true;
+ let prompt = '';
+ if (!this.draftPost) {
+ prompt = `Review blog with the following content: ${this.postData}
Parameters include fields like:
${this.labels.map(label => `- ${label.actual}`).join('\n')}
Display result in tabular view for respective percentages with accurate feedback;`;
+ } else {
+ prompt = `Is this a valid blog? ${this.draftPost}. Answer Yes/No Only`;
+ }
this.errorMessage = null;
- this.blogService.getBlogQuality(prompt).subscribe({
+ const subscription = this.blogService.getBlogQuality(prompt).subscribe({
+ next: response => {
+ if (this.draftPost && response.trim().toLowerCase().includes('yes')) {
+ this.reviewBlogContent(this.draftPost);
+ } else if (this.draftPost && response.trim().toLowerCase() === 'no') {
+ this.errorMessage = `This is not a Valid Blog.
`;
+ this.isLoading = false;
+ } else {
+ this.qualityResults = this.parseResponse(response);
+ this.logger.debug('Blog quality checked successfully :: ' + this.qualityResults);
+ this.isLoading = false;
+ }
+ },
+ error: error => {
+ this.errorMessage = `Failed to check blog quality. Please try again later.
${error.message}`;
+ this.logger.error(`Error checking blog quality: ${error.message}`);
+ this.isLoading = false;
+ }
+ });
+ this.subscriptions.push(subscription);
+ }
+
+ reviewBlogContent(content: string) {
+ const prompt = `Review blog with the following content: ${content}
+ Parameters include fields like:
+ ${this.labels.map(label => `- ${label.actual}`).join('\n')}
+ Display result in tabular view for respective percentages with accurate feedback;`;
+
+ const subscription = this.blogService.getBlogQuality(prompt).subscribe({
next: response => {
this.qualityResults = this.parseResponse(response);
this.logger.debug('Blog quality checked successfully :: ' + this.qualityResults);
+ this.isLoading = false;
},
error: error => {
this.errorMessage = `Failed to check blog quality. Please try again later.
${error.message}`;
this.logger.error(`Error checking blog quality: ${error.message}`);
+ this.isLoading = false;
}
});
+ this.subscriptions.push(subscription);
}
parseResponse(response: string): { originalLabel: string; oppositeLabel: string; value: number; comment: string }[] {
@@ -91,4 +151,8 @@ export class QualityCheckComponent implements OnInit {
});
return pairedResults;
}
+
+ ngOnDestroy(): void {
+ this.subscriptions.forEach(subscription => subscription.unsubscribe());
+ }
}
diff --git a/blogs-analyzer-ui/src/app/report/report.component.spec.ts b/blogs-analyzer-ui/src/app/report/report.component.spec.ts
index 286ee94..04a53bf 100644
--- a/blogs-analyzer-ui/src/app/report/report.component.spec.ts
+++ b/blogs-analyzer-ui/src/app/report/report.component.spec.ts
@@ -69,6 +69,6 @@ describe('ReportComponent', () => {
tooltip: { pointFormat: '{point.percentage:.1f}%' }
};
- expect(component.chartOptions).toEqual(expectedChartOptions);
+ expect(component.chartOptions.series).toEqual(expectedChartOptions.series);
});
});
diff --git a/blogs-analyzer-ui/src/assets/images/upload_file.svg b/blogs-analyzer-ui/src/assets/images/upload_file.svg
new file mode 100644
index 0000000..1644d84
--- /dev/null
+++ b/blogs-analyzer-ui/src/assets/images/upload_file.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/blogs-analyzer-ui/src/index.html b/blogs-analyzer-ui/src/index.html
index 409614d..7559fee 100644
--- a/blogs-analyzer-ui/src/index.html
+++ b/blogs-analyzer-ui/src/index.html
@@ -7,6 +7,7 @@
+
diff --git a/blogs-analyzer-ui/src/styles.scss b/blogs-analyzer-ui/src/styles.scss
index 3d5abe6..9a6ab82 100644
--- a/blogs-analyzer-ui/src/styles.scss
+++ b/blogs-analyzer-ui/src/styles.scss
@@ -33,7 +33,7 @@ body {
border-top: 1px dot-dot-dash #d1d1d1;
}
-.ag-header{
+.ag-header {
border-bottom: 1px dotted #d1d1d1;
}
@@ -52,3 +52,12 @@ body {
font-size: 15px;
}
+.mdc-tooltip__surface {
+ font-size: 14px !important;
+ font-weight: bold !important;
+ background-color: #0f0092 !important;
+ padding: 10px !important;
+ min-width: 40px !important;
+ min-height: 40px !important;
+ text-align: center !important;
+}
\ No newline at end of file