From 7df9b65e1f6c384dedf8059d1b5932bae3c9a950 Mon Sep 17 00:00:00 2001 From: Messias Junior Date: Wed, 12 May 2021 22:30:44 +0100 Subject: [PATCH 1/5] feat: synchronization interface on core --- core/interface/InterfaceChannel.js | 4 ++++ core/interface/index.js | 1 + .../SynchronizationInterface.js | 21 +++++++++++++++++++ .../synchronization/SynchornizationService.js | 9 +++++++- 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 core/interface/synchronization/SynchronizationInterface.js diff --git a/core/interface/InterfaceChannel.js b/core/interface/InterfaceChannel.js index 3b7adc2..ac11201 100644 --- a/core/interface/InterfaceChannel.js +++ b/core/interface/InterfaceChannel.js @@ -14,4 +14,8 @@ module.exports = { setTheme: 'settings.setTheme', getLastSynchronizationDate: 'settings.getLastSynchronizationDate', }, + synchronization: { + isRunning: 'synchronization.isRunning', + isRunningSync: 'synchronization.isRunning.sync', + }, }; diff --git a/core/interface/index.js b/core/interface/index.js index 3e3f3cc..86fc7dc 100644 --- a/core/interface/index.js +++ b/core/interface/index.js @@ -1,2 +1,3 @@ require('./application/ApplicationInterface'); require('./settings/SettingsInterface'); +require('./synchronization/SynchronizationInterface'); diff --git a/core/interface/synchronization/SynchronizationInterface.js b/core/interface/synchronization/SynchronizationInterface.js new file mode 100644 index 0000000..3e7c778 --- /dev/null +++ b/core/interface/synchronization/SynchronizationInterface.js @@ -0,0 +1,21 @@ +const synchronizationService = require('../../service/synchronization/SynchornizationService'); +const { ipcMain } = require('electron'); +const InterfaceChannel = require('../InterfaceChannel'); + +let isSynchronizingCache = false; + +synchronizationService + .getSynchronizationStatus() + .subscribe((isSynchronizing) => { + if (isSynchronizing) { + isSynchronizingCache = isSynchronizing; + } + ipcMain.emit( + InterfaceChannel.synchronization.isRunning, + isSynchronizing, + ); + }); + +ipcMain?.handle(InterfaceChannel.synchronization.isRunningSync, () => { + return isSynchronizingCache; +}); diff --git a/core/service/synchronization/SynchornizationService.js b/core/service/synchronization/SynchornizationService.js index 169ae47..12be4f9 100644 --- a/core/service/synchronization/SynchornizationService.js +++ b/core/service/synchronization/SynchornizationService.js @@ -1,4 +1,4 @@ -const { forkJoin } = require('rxjs'); +const { forkJoin, Subject } = require('rxjs'); const flathubSynchronizer = require('./synchronizer/FlathubSynchronizer'); const appImageHubSynchronizer = require('./synchronizer/AppImageHubSynchronizer'); @@ -7,6 +7,9 @@ const settingsService = require('../settings/SettingsService'); const DAY_IN_MILLIS = 1000 * 60 * 60 * 24 * 7; +const isSynchronizationRunning = new Subject(); +isSynchronizationRunning.next(false); + async function shouldSynchronize() { const now = new Date(); const lastSync = await settingsService.getLastSynchronizationDate(); @@ -28,6 +31,7 @@ async function startSynchronization() { } function synchronize() { + isSynchronizationRunning.next(true); forkJoin([ flathubSynchronizer.startSynchronization(), appImageHubSynchronizer.startSynchronization(), @@ -36,13 +40,16 @@ function synchronize() { () => { console.log('Synchronization succeeded'); settingsService.setLastSynchronizationDate(new Date()); + isSynchronizationRunning.next(false); }, (error) => { console.error(error); + isSynchronizationRunning.next(false); }, ); } module.exports = { startSynchronization, + getSynchronizationStatus: () => isSynchronizationRunning, }; From e082cdc750302859dab8b99ff613e694779faf81 Mon Sep 17 00:00:00 2001 From: Messias Junior Date: Tue, 18 May 2021 20:47:06 +0100 Subject: [PATCH 2/5] feat: create synchronization message --- src/app/ui/pages/main/main.component.html | 4 ++++ src/app/ui/pages/main/main.component.scss | 8 ++++++++ src/app/ui/pages/main/main.component.ts | 8 +++++++- src/app/ui/pages/main/main.module.ts | 13 ++++++++++++- src/assets/i18n/en.json | 3 ++- 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/app/ui/pages/main/main.component.html b/src/app/ui/pages/main/main.component.html index c55debb..8cfa9df 100644 --- a/src/app/ui/pages/main/main.component.html +++ b/src/app/ui/pages/main/main.component.html @@ -11,5 +11,9 @@ + + {{ 'PAGES.MAIN.SYNCHRONIZATION_MESSAGE' | translate}} + diff --git a/src/app/ui/pages/main/main.component.scss b/src/app/ui/pages/main/main.component.scss index d8f9e2e..350e259 100644 --- a/src/app/ui/pages/main/main.component.scss +++ b/src/app/ui/pages/main/main.component.scss @@ -16,3 +16,11 @@ nb-layout-column { app-main-menu { padding-bottom: 15rem; } + +.synchronization-message { + position: sticky; + bottom: 0.5rem; + margin-left: 10rem; + margin-right: 10rem; + z-index: 1; +} diff --git a/src/app/ui/pages/main/main.component.ts b/src/app/ui/pages/main/main.component.ts index c6dcc4d..fd4c235 100644 --- a/src/app/ui/pages/main/main.component.ts +++ b/src/app/ui/pages/main/main.component.ts @@ -5,4 +5,10 @@ import { Component } from '@angular/core'; templateUrl: './main.component.html', styleUrls: ['./main.component.scss'], }) -export class MainComponent {} +export class MainComponent { + shouldShowSynchronizationMessage = true; + + closeSynchronizationMessage(): void { + this.shouldShowSynchronizationMessage = false; + } +} diff --git a/src/app/ui/pages/main/main.module.ts b/src/app/ui/pages/main/main.module.ts index 7b3f50d..d810983 100644 --- a/src/app/ui/pages/main/main.module.ts +++ b/src/app/ui/pages/main/main.module.ts @@ -3,10 +3,16 @@ import { CommonModule } from '@angular/common'; import { RouterModule, Routes } from '@angular/router'; import { MainComponent } from './main.component'; -import { NbLayoutModule, NbSidebarModule } from '@nebular/theme'; +import { + NbAlertModule, + NbCardModule, + NbLayoutModule, + NbSidebarModule, +} from '@nebular/theme'; import { NbEvaIconsModule } from '@nebular/eva-icons'; import { MainMenuModule } from '../../components/main-menu/main-menu.module'; import { ToolbarModule } from '../../components/toolbar/toolbar.module'; +import { TranslateModule } from '@ngx-translate/core'; /* eslint-disable @typescript-eslint/explicit-function-return-type */ const routes: Routes = [ @@ -81,6 +87,11 @@ const routes: Routes = [ NbLayoutModule, NbEvaIconsModule, NbSidebarModule.forRoot(), + NbCardModule, + NbAlertModule, + + // Other + TranslateModule.forChild(), ], }) export class MainModule {} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 1f27982..135eddd 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -66,7 +66,8 @@ "INTERNET": "Internet and Communication", "UTILITY": "Utility and Productivity", "MISC": "Miscellaneous" - } + }, + "SYNCHRONIZATION_MESSAGE": "App Outlet is synchronizing its database. It can affect the search performance. When synchronization ends, it will back to normal" }, "SEARCH": { "NO_RESULTS_FOUND": "No results found", From 2ce262d73b232c278e3f42c05e5577f4985e4b25 Mon Sep 17 00:00:00 2001 From: Messias Junior Date: Tue, 18 May 2021 21:04:16 +0100 Subject: [PATCH 3/5] feat: synchronization status update --- .../synchronization.service.spec.ts | 16 ++++++++ .../synchronization.service.ts | 14 +++++++ src/app/ui/pages/main/main.component.html | 11 ++++-- src/app/ui/pages/main/main.component.ts | 37 ++++++++++++++++++- src/app/ui/pages/main/main.module.ts | 2 + 5 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 src/app/service/synchronization/synchronization.service.spec.ts create mode 100644 src/app/service/synchronization/synchronization.service.ts diff --git a/src/app/service/synchronization/synchronization.service.spec.ts b/src/app/service/synchronization/synchronization.service.spec.ts new file mode 100644 index 0000000..4810408 --- /dev/null +++ b/src/app/service/synchronization/synchronization.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { SynchronizationService } from './synchronization.service'; + +describe('SynchronizationService', () => { + let service: SynchronizationService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(SynchronizationService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/service/synchronization/synchronization.service.ts b/src/app/service/synchronization/synchronization.service.ts new file mode 100644 index 0000000..92fd4ad --- /dev/null +++ b/src/app/service/synchronization/synchronization.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { CoreService } from '../core/core.service'; +import * as InterfaceChannel from '../../../../core/interface/InterfaceChannel'; + +@Injectable() +export class SynchronizationService { + constructor(private coreService: CoreService) {} + + getCurrentSynchronizationStatus(): Promise { + return this.coreService.invoke( + InterfaceChannel.synchronization.isRunningSync, + ); + } +} diff --git a/src/app/ui/pages/main/main.component.html b/src/app/ui/pages/main/main.component.html index 8cfa9df..4d24c12 100644 --- a/src/app/ui/pages/main/main.component.html +++ b/src/app/ui/pages/main/main.component.html @@ -11,9 +11,14 @@ - - {{ 'PAGES.MAIN.SYNCHRONIZATION_MESSAGE' | translate}} + + {{ 'PAGES.MAIN.SYNCHRONIZATION_MESSAGE' | translate }} diff --git a/src/app/ui/pages/main/main.component.ts b/src/app/ui/pages/main/main.component.ts index fd4c235..30f8fd2 100644 --- a/src/app/ui/pages/main/main.component.ts +++ b/src/app/ui/pages/main/main.component.ts @@ -1,12 +1,45 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { SynchronizationService } from '../../../service/synchronization/synchronization.service'; +import { ElectronService } from 'ngx-electron'; +import * as InterfaceChannel from '../../../../../core/interface/InterfaceChannel'; @Component({ selector: 'app-main', templateUrl: './main.component.html', styleUrls: ['./main.component.scss'], }) -export class MainComponent { +export class MainComponent implements OnInit { shouldShowSynchronizationMessage = true; + isSynchronizationRunning = false; + + constructor( + private synchronizationService: SynchronizationService, + private electronService: ElectronService, + ) {} + + ngOnInit(): void { + this.listenToSynchronizationUpdates(); + this.getCurrentSynchronizationStatus(); + } + + private getCurrentSynchronizationStatus(): void { + this.synchronizationService + .getCurrentSynchronizationStatus() + .then((status) => { + debugger; + this.isSynchronizationRunning = status; + }); + } + + private listenToSynchronizationUpdates(): void { + this.electronService.ipcRenderer.addListener( + InterfaceChannel.synchronization.isRunning, + (event, args) => { + debugger; + console.log(args, event); + }, + ); + } closeSynchronizationMessage(): void { this.shouldShowSynchronizationMessage = false; diff --git a/src/app/ui/pages/main/main.module.ts b/src/app/ui/pages/main/main.module.ts index d810983..bcb25f1 100644 --- a/src/app/ui/pages/main/main.module.ts +++ b/src/app/ui/pages/main/main.module.ts @@ -13,6 +13,7 @@ import { NbEvaIconsModule } from '@nebular/eva-icons'; import { MainMenuModule } from '../../components/main-menu/main-menu.module'; import { ToolbarModule } from '../../components/toolbar/toolbar.module'; import { TranslateModule } from '@ngx-translate/core'; +import { SynchronizationService } from '../../../service/synchronization/synchronization.service'; /* eslint-disable @typescript-eslint/explicit-function-return-type */ const routes: Routes = [ @@ -93,5 +94,6 @@ const routes: Routes = [ // Other TranslateModule.forChild(), ], + providers: [SynchronizationService], }) export class MainModule {} From 89b46ac202e5b3900916c7e248c64af9f5769743 Mon Sep 17 00:00:00 2001 From: Messias Junior Date: Tue, 18 May 2021 21:40:32 +0100 Subject: [PATCH 4/5] chore: remove reactive implementation --- src/app/ui/pages/main/main.component.ts | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/app/ui/pages/main/main.component.ts b/src/app/ui/pages/main/main.component.ts index 30f8fd2..e4d788d 100644 --- a/src/app/ui/pages/main/main.component.ts +++ b/src/app/ui/pages/main/main.component.ts @@ -1,7 +1,5 @@ import { Component, OnInit } from '@angular/core'; import { SynchronizationService } from '../../../service/synchronization/synchronization.service'; -import { ElectronService } from 'ngx-electron'; -import * as InterfaceChannel from '../../../../../core/interface/InterfaceChannel'; @Component({ selector: 'app-main', @@ -12,13 +10,9 @@ export class MainComponent implements OnInit { shouldShowSynchronizationMessage = true; isSynchronizationRunning = false; - constructor( - private synchronizationService: SynchronizationService, - private electronService: ElectronService, - ) {} + constructor(private synchronizationService: SynchronizationService) {} ngOnInit(): void { - this.listenToSynchronizationUpdates(); this.getCurrentSynchronizationStatus(); } @@ -26,21 +20,10 @@ export class MainComponent implements OnInit { this.synchronizationService .getCurrentSynchronizationStatus() .then((status) => { - debugger; this.isSynchronizationRunning = status; }); } - private listenToSynchronizationUpdates(): void { - this.electronService.ipcRenderer.addListener( - InterfaceChannel.synchronization.isRunning, - (event, args) => { - debugger; - console.log(args, event); - }, - ); - } - closeSynchronizationMessage(): void { this.shouldShowSynchronizationMessage = false; } From 5ea74c281c99abaa0d6a80ea5ca394fe08b1dc0d Mon Sep 17 00:00:00 2001 From: Messias Junior Date: Tue, 18 May 2021 21:56:48 +0100 Subject: [PATCH 5/5] test: add tests for the new feature --- .../synchronization.service.spec.ts | 16 ++++-- src/app/ui/pages/main/main.component.spec.ts | 51 ++++++++----------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/app/service/synchronization/synchronization.service.spec.ts b/src/app/service/synchronization/synchronization.service.spec.ts index 4810408..e715af6 100644 --- a/src/app/service/synchronization/synchronization.service.spec.ts +++ b/src/app/service/synchronization/synchronization.service.spec.ts @@ -1,16 +1,24 @@ -import { TestBed } from '@angular/core/testing'; - import { SynchronizationService } from './synchronization.service'; describe('SynchronizationService', () => { let service: SynchronizationService; + const mockCoreService = { + invoke: jest.fn(), + }; + beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(SynchronizationService); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + service = new SynchronizationService(mockCoreService); }); it('should be created', () => { expect(service).toBeTruthy(); }); + + it('should get current synchronization status', async () => { + mockCoreService.invoke.mockReturnValue(Promise.resolve(true)); + expect(await service.getCurrentSynchronizationStatus()).toBeTruthy(); + }); }); diff --git a/src/app/ui/pages/main/main.component.spec.ts b/src/app/ui/pages/main/main.component.spec.ts index 938da4d..fe52334 100644 --- a/src/app/ui/pages/main/main.component.spec.ts +++ b/src/app/ui/pages/main/main.component.spec.ts @@ -1,42 +1,35 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - import { MainComponent } from './main.component'; -import { MainMenuModule } from '../../components/main-menu/main-menu.module'; -import { NbLayoutModule, NbSidebarModule, NbThemeModule } from '@nebular/theme'; -import { NbEvaIconsModule } from '@nebular/eva-icons'; -import { RouterModule } from '@angular/router'; -import { APP_BASE_HREF } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { ToolbarModule } from '../../components/toolbar/toolbar.module'; describe('MainComponent', () => { let component: MainComponent; - let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - MainMenuModule, - NbLayoutModule, - NbEvaIconsModule, - NbSidebarModule.forRoot(), - RouterModule.forRoot([]), - NbThemeModule.forRoot(), - TranslateModule.forRoot(), - ToolbarModule, - ], - declarations: [MainComponent], - providers: [{ provide: APP_BASE_HREF, useValue: './' }], - }).compileComponents(); - }); + const mockSynchronizationService = { + getCurrentSynchronizationStatus: jest.fn(), + }; beforeEach(() => { - fixture = TestBed.createComponent(MainComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + component = new MainComponent(mockSynchronizationService); }); it('should create', () => { expect(component).toBeTruthy(); }); + + it('should get current synchronization status', (done) => { + mockSynchronizationService.getCurrentSynchronizationStatus.mockReturnValue( + Promise.resolve(true), + ); + component.ngOnInit(); + setTimeout(() => { + expect(component.isSynchronizationRunning).toBeTruthy(); + done(); + }, 0); + }); + + it('should hide synchronization message', () => { + component.closeSynchronizationMessage(); + expect(component.shouldShowSynchronizationMessage).toBeFalsy(); + }); });