diff --git a/.grit/patterns/xforge_common_absolute_only.md b/.grit/patterns/xforge_common_absolute_only.md index f84f3bb391f..5694efc4d60 100644 --- a/.grit/patterns/xforge_common_absolute_only.md +++ b/.grit/patterns/xforge_common_absolute_only.md @@ -18,9 +18,9 @@ language js ## Basic example ```ts -import { UICommonModule } from "../../xforge-common/ui-common.module"; +import { UserService } from "../../xforge-common/user.service"; ``` ```ts -import { UICommonModule } from "xforge-common/ui-common.module"; +import { UserService } from "xforge-common/user.service"; ``` diff --git a/src/SIL.XForge.Scripture/ClientApp/.storybook/preview.ts b/src/SIL.XForge.Scripture/ClientApp/.storybook/preview.ts index f8072e27ff4..0ac1f7d3d61 100644 --- a/src/SIL.XForge.Scripture/ClientApp/.storybook/preview.ts +++ b/src/SIL.XForge.Scripture/ClientApp/.storybook/preview.ts @@ -1,15 +1,16 @@ import { OverlayContainer } from '@angular/cdk/overlay'; -import { importProvidersFrom } from '@angular/core'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; import { provideAnimations } from '@angular/platform-browser/animations'; import { setCompodocJson } from '@storybook/addon-docs/angular'; import { applicationConfig } from '@storybook/angular'; -import docJson from '../documentation.json'; -import { I18nStoryDecorator, I18nStoryModule } from 'xforge-common/i18n-story.module'; +import { I18nStoryDecorator, provideI18nStory } from 'xforge-common/i18n-story'; import { I18nService } from 'xforge-common/i18n.service'; import { APP_ROOT_ELEMENT_SELECTOR, InAppRootOverlayContainer } from 'xforge-common/overlay-container'; +import { provideUICommon } from 'xforge-common/ui-common-providers'; import { getI18nLocales } from 'xforge-common/utils'; +import docJson from '../documentation.json'; +import { provideSFTabs } from '../src/app/shared/sf-tab-group'; setCompodocJson(docJson); @@ -42,8 +43,10 @@ export const decorators = [ I18nStoryDecorator, applicationConfig({ providers: [ - importProvidersFrom(I18nStoryModule), + provideI18nStory(), provideAnimations(), + provideUICommon(), + provideSFTabs(), { provide: APP_ROOT_ELEMENT_SELECTOR, useValue: 'storybook-root' }, { provide: OverlayContainer, useClass: InAppRootOverlayContainer } ] diff --git a/src/SIL.XForge.Scripture/ClientApp/.storybook/util/mat-dialog-launch.ts b/src/SIL.XForge.Scripture/ClientApp/.storybook/util/mat-dialog-launch.ts index adfdb76102b..fb63c157839 100644 --- a/src/SIL.XForge.Scripture/ClientApp/.storybook/util/mat-dialog-launch.ts +++ b/src/SIL.XForge.Scripture/ClientApp/.storybook/util/mat-dialog-launch.ts @@ -1,9 +1,7 @@ -import { CommonModule } from '@angular/common'; import { Component, Inject, InjectionToken, Injector, OnInit, Provider } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog'; import { TranslocoModule } from '@ngneat/transloco'; import { StoryFn } from '@storybook/angular'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { hasProp } from '../../src/type-utils'; export function getOverlays(element: HTMLElement): HTMLElement[] { @@ -25,7 +23,6 @@ export interface MatDialogStoryConfig { imports?: any[]; declarations?: any[]; providers?: Provider[]; - standaloneComponent?: boolean; } @Component({ template: '' }) @@ -57,8 +54,8 @@ export class MatDialogLaunchComponent implements OnInit { export function matDialogStory(component: any, config?: MatDialogStoryConfig): StoryFn { const story: StoryFn = args => ({ moduleMetadata: { - imports: [UICommonModule, CommonModule, TranslocoModule, ...(config?.imports ?? [])], - declarations: [...(config?.standaloneComponent ? [] : [component]), ...(config?.declarations ?? [])], + imports: [MatDialogModule, TranslocoModule, component, ...(config?.imports ?? [])], + declarations: [...(config?.declarations ?? [])], providers: [ { provide: MAT_DIALOG_DATA, useValue: args.data }, { provide: COMPONENT_UNDER_TEST, useValue: component }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/app-routing.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/app-routing.module.ts deleted file mode 100644 index 8fa7b160df4..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/app-routing.module.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { AuthGuard } from 'xforge-common/auth.guard'; -import { SystemAdminAuthGuard } from 'xforge-common/system-admin-auth.guard'; -import { SystemAdministrationComponent } from 'xforge-common/system-administration/system-administration.component'; -import { ConnectProjectComponent } from './connect-project/connect-project.component'; -import { EventMetricsAuthGuard } from './event-metrics/event-metrics-auth.guard'; -import { EventMetricsComponent } from './event-metrics/event-metrics.component'; -import { JoinComponent } from './join/join.component'; -import { MyProjectsComponent } from './my-projects/my-projects.component'; -import { PermissionsViewerComponent } from './permissions-viewer/permissions-viewer.component'; -import { ProjectComponent } from './project/project.component'; -import { ServalAdminAuthGuard } from './serval-administration/serval-admin-auth.guard'; -import { ServalAdministrationComponent } from './serval-administration/serval-administration.component'; -import { ServalProjectComponent } from './serval-administration/serval-project.component'; -import { SettingsComponent } from './settings/settings.component'; -import { PageNotFoundComponent } from './shared/page-not-found/page-not-found.component'; -import { SettingsAuthGuard, SyncAuthGuard } from './shared/project-router.guard'; -import { SyncComponent } from './sync/sync.component'; - -const routes: Routes = [ - { path: 'callback/auth0', component: MyProjectsComponent, canActivate: [AuthGuard] }, - { path: 'connect-project', component: ConnectProjectComponent, canActivate: [AuthGuard] }, - { path: 'login', redirectTo: 'projects', pathMatch: 'full' }, - { path: 'join/:shareKey', component: JoinComponent }, - { path: 'join/:shareKey/:locale', component: JoinComponent }, - { path: 'projects/:projectId/event-log', component: EventMetricsComponent, canActivate: [EventMetricsAuthGuard] }, - { path: 'projects/:projectId/settings', component: SettingsComponent, canActivate: [SettingsAuthGuard] }, - { path: 'projects/:projectId/sync', component: SyncComponent, canActivate: [SyncAuthGuard] }, - { path: 'projects/:projectId', component: ProjectComponent, canActivate: [AuthGuard] }, - { path: 'projects', component: MyProjectsComponent, canActivate: [AuthGuard] }, - { path: 'system-administration/permissions-viewer', component: PermissionsViewerComponent }, - { path: 'serval-administration/:projectId', component: ServalProjectComponent, canActivate: [ServalAdminAuthGuard] }, - { path: 'serval-administration', component: ServalAdministrationComponent, canActivate: [ServalAdminAuthGuard] }, - { path: 'system-administration', component: SystemAdministrationComponent, canActivate: [SystemAdminAuthGuard] }, - { path: '**', component: PageNotFoundComponent } -]; - -@NgModule({ - imports: [ - RouterModule.forRoot(routes, { - // This setting was introduced to prevent canceling the "prompt on leave" dialog for pages like draft-usfm-format - // from mangling the browser history (SF-3577). - canceledNavigationResolution: 'computed' - }) - ], - exports: [RouterModule] -}) -export class AppRoutingModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts index 46179a7be9e..713eedbcd4d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.spec.ts @@ -2,9 +2,12 @@ import { BreakpointObserver } from '@angular/cdk/layout'; import { Location } from '@angular/common'; import { Component, DebugElement, NgZone } from '@angular/core'; import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu } from '@angular/material/menu'; +import { MatTooltip } from '@angular/material/tooltip'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { Route, Router, RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { provideRouter, Route, Router } from '@angular/router'; import { CookieService } from 'ngx-cookie-service'; import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role'; import { User } from 'realtime-server/lib/esm/common/models/user'; @@ -30,12 +33,11 @@ import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { PWA_BEFORE_PROMPT_CAN_BE_SHOWN_AGAIN, PwaService } from 'xforge-common/pwa.service'; import { TestBreakpointObserver } from 'xforge-common/test-breakpoint-observer'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { AppComponent } from './app.component'; import { SFProjectProfileDoc } from './core/models/sf-project-profile-doc'; @@ -65,8 +67,7 @@ const mockedErrorReportingService = mock(ErrorReportingService); const mockedDialogService = mock(DialogService); @Component({ - template: `
Mock
`, - standalone: false + template: `
Mock
` }) class MockComponent {} @@ -87,18 +88,20 @@ const ROUTES: Route[] = [ describe('AppComponent', () => { configureTestingModule(() => ({ - declarations: [AppComponent, NavigationComponent], imports: [ - UICommonModule, - NoopAnimationsModule, - RouterModule.forRoot(ROUTES), - TestTranslocoModule, - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), + AppComponent, + NavigationComponent, + getTestTranslocoModule(), AvatarComponent, - GlobalNoticesComponent + GlobalNoticesComponent, + MatMenu, + MatIcon, + MatTooltip ], providers: [ + provideRouter(ROUTES), + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: AuthService, useMock: mockedAuthService }, { provide: UserService, useMock: mockedUserService }, { provide: SettingsAuthGuard, useMock: mockedSettingsAuthGuard }, @@ -116,7 +119,8 @@ describe('AppComponent', () => { { provide: FileService, useMock: mockedFileService }, { provide: ErrorReportingService, useMock: mockedErrorReportingService }, { provide: BreakpointObserver, useClass: TestBreakpointObserver }, - { provide: DialogService, useMock: mockedDialogService } + { provide: DialogService, useMock: mockedDialogService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.ts index 8c03b2bedde..be249b1a954 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/app.component.ts @@ -1,9 +1,20 @@ +import { BidiModule } from '@angular/cdk/bidi'; import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; -import { DOCUMENT } from '@angular/common'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { AsyncPipe, DOCUMENT } from '@angular/common'; import { Component, DestroyRef, Inject, OnDestroy, OnInit } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { NavigationEnd, Router } from '@angular/router'; +import { MatButton, MatIconAnchor, MatIconButton } from '@angular/material/button'; +import { MatDivider } from '@angular/material/divider'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { MatDrawer, MatDrawerContainer } from '@angular/material/sidenav'; +import { MatToolbar, MatToolbarRow } from '@angular/material/toolbar'; +import { MatTooltip } from '@angular/material/tooltip'; +import { NavigationEnd, Router, RouterLink, RouterOutlet } from '@angular/router'; import Bugsnag from '@bugsnag/js'; +import { TranslocoModule } from '@ngneat/transloco'; import { cloneDeep } from 'lodash-es'; import { CookieService } from 'ngx-cookie-service'; import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role'; @@ -13,6 +24,7 @@ import { Observable, Subscription } from 'rxjs'; import { filter, map } from 'rxjs/operators'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { AuthService } from 'xforge-common/auth.service'; +import { AvatarComponent } from 'xforge-common/avatar/avatar.component'; import { DataLoadingComponent } from 'xforge-common/data-loading-component'; import { DiagnosticOverlayService } from 'xforge-common/diagnostic-overlay.service'; import { DialogService } from 'xforge-common/dialog.service'; @@ -28,6 +40,7 @@ import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { PWA_BEFORE_PROMPT_CAN_BE_SHOWN_AGAIN, PwaService } from 'xforge-common/pwa.service'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; import { BrowserIssue, SupportedBrowsersDialogComponent @@ -42,6 +55,8 @@ import { SFProjectProfileDoc } from './core/models/sf-project-profile-doc'; import { roleCanAccessTranslate } from './core/models/sf-project-role-info'; import { SFProjectUserConfigDoc } from './core/models/sf-project-user-config-doc'; import { SFProjectService } from './core/sf-project.service'; +import { NavigationComponent } from './navigation/navigation.component'; +import { GlobalNoticesComponent } from './shared/global-notices/global-notices.component'; import { checkAppAccess } from './shared/utils'; declare function gtag(...args: any): void; @@ -50,7 +65,33 @@ declare function gtag(...args: any): void; selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], - standalone: false + imports: [ + AsyncPipe, + TranslocoModule, + RouterLink, + AvatarComponent, + RouterLinkDirective, + NavigationComponent, + GlobalNoticesComponent, + RouterOutlet, + MatIcon, + MatDrawerContainer, + MatButton, + MatIconAnchor, + MatIconButton, + MatMenu, + MatMenuItem, + MatMenuTrigger, + MatTooltip, + MatToolbar, + MatToolbarRow, + MatProgressBar, + MatDivider, + MatDrawer, + MatDrawerContainer, + CdkScrollable, + BidiModule + ] }) export class AppComponent extends DataLoadingComponent implements OnInit, OnDestroy { version: string = versionData.version; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/app.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/app.module.ts deleted file mode 100644 index 754f9705121..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/app.module.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { OverlayContainer } from '@angular/cdk/overlay'; -import { DatePipe } from '@angular/common'; -import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; -import { APP_ID, ErrorHandler, inject, NgModule, provideAppInitializer } from '@angular/core'; -import { MatRipple } from '@angular/material/core'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { ServiceWorkerModule } from '@angular/service-worker'; -import { TranslocoModule, TranslocoService } from '@ngneat/transloco'; -import { CookieService } from 'ngx-cookie-service'; -import { QuillModule } from 'ngx-quill'; -import { - defaultTranslocoMarkupTranspilers, - provideTranslationMarkupTranspiler, - TranslocoMarkupModule -} from 'ngx-transloco-markup'; -import { translocoMarkupRouterLinkRenderer } from 'ngx-transloco-markup-router-link'; -import { AvatarComponent } from 'xforge-common/avatar/avatar.component'; -import { EditNameDialogComponent } from 'xforge-common/edit-name-dialog/edit-name-dialog.component'; -import { ErrorDialogComponent } from 'xforge-common/error-dialog/error-dialog.component'; -import { ExceptionHandlingService } from 'xforge-common/exception-handling.service'; -import { FeatureFlagsDialogComponent } from 'xforge-common/feature-flags/feature-flags-dialog.component'; -import { EmTextTranspiler } from 'xforge-common/i18n-transpilers/em-text.transpiler'; -import { InAppRootOverlayContainer } from 'xforge-common/overlay-container'; -import { SupportedBrowsersDialogComponent } from 'xforge-common/supported-browsers-dialog/supported-browsers-dialog.component'; -import { UICommonModule } from 'xforge-common/ui-common.module'; -import { WriteStatusComponent } from 'xforge-common/write-status/write-status.component'; -import { XForgeCommonModule } from 'xforge-common/xforge-common.module'; -import { environment } from '../environments/environment'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { CheckingModule } from './checking/checking.module'; -import { ConnectProjectComponent } from './connect-project/connect-project.component'; -import { CoreModule } from './core/core.module'; -import { JoinComponent } from './join/join.component'; -import { MyProjectsComponent } from './my-projects/my-projects.component'; -import { NavigationComponent } from './navigation/navigation.component'; -import { ProjectComponent } from './project/project.component'; -import { ScriptureChooserDialogComponent } from './scripture-chooser-dialog/scripture-chooser-dialog.component'; -import { DeleteProjectDialogComponent } from './settings/delete-project-dialog/delete-project-dialog.component'; -import { SettingsComponent } from './settings/settings.component'; -import { GlobalNoticesComponent } from './shared/global-notices/global-notices.component'; -import { SharedModule } from './shared/shared.module'; -import { TextNoteDialogComponent } from './shared/text/text-note-dialog/text-note-dialog.component'; -import { preloadEnglishTranslations } from './shared/utils'; -import { SyncComponent } from './sync/sync.component'; -import { LynxInsightsModule } from './translate/editor/lynx/insights/lynx-insights.module'; -import { TranslateModule } from './translate/translate.module'; -import { UsersModule } from './users/users.module'; - -@NgModule({ - declarations: [ - AppComponent, - NavigationComponent, - ConnectProjectComponent, - DeleteProjectDialogComponent, - ProjectComponent, - SettingsComponent, - MyProjectsComponent, - SyncComponent, - ScriptureChooserDialogComponent, - SupportedBrowsersDialogComponent, - ErrorDialogComponent, - EditNameDialogComponent, - FeatureFlagsDialogComponent, - TextNoteDialogComponent, - JoinComponent - ], - bootstrap: [AppComponent], - imports: [ - BrowserAnimationsModule, - CoreModule, - ServiceWorkerModule.register('sf-service-worker.js', { - enabled: environment.pwaTest || environment.production, - registrationStrategy: 'registerImmediately' - }), - TranslateModule, - CheckingModule, - UsersModule, - UICommonModule.forRoot(), - XForgeCommonModule, - TranslocoModule, - TranslocoMarkupModule, - AppRoutingModule, - SharedModule.forRoot(), - AvatarComponent, - MatRipple, - GlobalNoticesComponent, - QuillModule.forRoot(), - LynxInsightsModule.forRoot(), - WriteStatusComponent - ], - providers: [ - { provide: APP_ID, useValue: 'ng-cli-universal' }, - CookieService, - DatePipe, - provideTranslationMarkupTranspiler(EmTextTranspiler), - translocoMarkupRouterLinkRenderer(), - defaultTranslocoMarkupTranspilers(), - { provide: ErrorHandler, useClass: ExceptionHandlingService }, - { provide: OverlayContainer, useClass: InAppRootOverlayContainer }, - provideHttpClient(withInterceptorsFromDi()), - provideAppInitializer(() => { - const initializerFn = preloadEnglishTranslations(inject(TranslocoService)); - return initializerFn(); - }) - ] -}) -export class AppModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/app.routes.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/app.routes.ts new file mode 100644 index 00000000000..2fef5e85b6a --- /dev/null +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/app.routes.ts @@ -0,0 +1,96 @@ +import { Routes } from '@angular/router'; +import { AuthGuard } from 'xforge-common/auth.guard'; +import { SystemAdminAuthGuard } from 'xforge-common/system-admin-auth.guard'; +import { SystemAdministrationComponent } from 'xforge-common/system-administration/system-administration.component'; +import { CheckingOverviewComponent } from './checking/checking-overview/checking-overview.component'; +import { CheckingComponent } from './checking/checking/checking.component'; +import { ConnectProjectComponent } from './connect-project/connect-project.component'; +import { EventMetricsAuthGuard } from './event-metrics/event-metrics-auth.guard'; +import { EventMetricsComponent } from './event-metrics/event-metrics.component'; +import { JoinComponent } from './join/join.component'; +import { MyProjectsComponent } from './my-projects/my-projects.component'; +import { PermissionsViewerComponent } from './permissions-viewer/permissions-viewer.component'; +import { ProjectComponent } from './project/project.component'; +import { ServalAdminAuthGuard } from './serval-administration/serval-admin-auth.guard'; +import { ServalAdministrationComponent } from './serval-administration/serval-administration.component'; +import { ServalProjectComponent } from './serval-administration/serval-project.component'; +import { SettingsComponent } from './settings/settings.component'; +import { PageNotFoundComponent } from './shared/page-not-found/page-not-found.component'; +import { + CheckingAuthGuard, + DraftNavigationAuthGuard, + NmtDraftAuthGuard, + SettingsAuthGuard, + SyncAuthGuard, + TranslateAuthGuard, + UsersAuthGuard +} from './shared/project-router.guard'; +import { SyncComponent } from './sync/sync.component'; +import { DraftGenerationComponent } from './translate/draft-generation/draft-generation.component'; +import { DraftSourcesComponent } from './translate/draft-generation/draft-sources/draft-sources.component'; +import { DraftUsfmFormatComponent } from './translate/draft-generation/draft-usfm-format/draft-usfm-format.component'; +import { EditorComponent } from './translate/editor/editor.component'; +import { TranslateOverviewComponent } from './translate/translate-overview/translate-overview.component'; +import { UsersComponent } from './users/users.component'; + +export const APP_ROUTES: Routes = [ + { path: 'callback/auth0', component: MyProjectsComponent, canActivate: [AuthGuard] }, + { path: 'connect-project', component: ConnectProjectComponent, canActivate: [AuthGuard] }, + { path: 'login', redirectTo: 'projects', pathMatch: 'full' }, + { path: 'join/:shareKey', component: JoinComponent }, + { path: 'join/:shareKey/:locale', component: JoinComponent }, + { + path: 'projects/:projectId/checking/:bookId/:chapter', + component: CheckingComponent, + canActivate: [CheckingAuthGuard] + }, + { path: 'projects/:projectId/checking/:bookId', component: CheckingComponent, canActivate: [CheckingAuthGuard] }, + { path: 'projects/:projectId/checking', component: CheckingOverviewComponent, canActivate: [CheckingAuthGuard] }, + { + path: 'projects/:projectId/draft-generation/format/:bookId/:chapter', + component: DraftUsfmFormatComponent, + canActivate: [NmtDraftAuthGuard], + canDeactivate: [DraftNavigationAuthGuard] + }, + { + path: 'projects/:projectId/draft-generation/format/:bookId', + component: DraftUsfmFormatComponent, + canActivate: [NmtDraftAuthGuard], + canDeactivate: [DraftNavigationAuthGuard] + }, + { + path: 'projects/:projectId/draft-generation/format', + component: DraftUsfmFormatComponent, + canActivate: [NmtDraftAuthGuard], + canDeactivate: [DraftNavigationAuthGuard] + }, + { + path: 'projects/:projectId/draft-generation/sources', + component: DraftSourcesComponent, + canActivate: [NmtDraftAuthGuard], + canDeactivate: [DraftNavigationAuthGuard] + }, + { + path: 'projects/:projectId/draft-generation', + component: DraftGenerationComponent, + canActivate: [NmtDraftAuthGuard] + }, + { path: 'projects/:projectId/event-log', component: EventMetricsComponent, canActivate: [EventMetricsAuthGuard] }, + { path: 'projects/:projectId/settings', component: SettingsComponent, canActivate: [SettingsAuthGuard] }, + { path: 'projects/:projectId/sync', component: SyncComponent, canActivate: [SyncAuthGuard] }, + { + path: 'projects/:projectId/translate/:bookId/:chapter', + component: EditorComponent, + canActivate: [TranslateAuthGuard] + }, + { path: 'projects/:projectId/translate/:bookId', component: EditorComponent, canActivate: [TranslateAuthGuard] }, + { path: 'projects/:projectId/translate', component: TranslateOverviewComponent, canActivate: [TranslateAuthGuard] }, + { path: 'projects/:projectId/users', component: UsersComponent, canActivate: [UsersAuthGuard] }, + { path: 'projects/:projectId', component: ProjectComponent, canActivate: [AuthGuard] }, + { path: 'projects', component: MyProjectsComponent, canActivate: [AuthGuard] }, + { path: 'system-administration/permissions-viewer', component: PermissionsViewerComponent }, + { path: 'serval-administration/:projectId', component: ServalProjectComponent, canActivate: [ServalAdminAuthGuard] }, + { path: 'serval-administration', component: ServalAdministrationComponent, canActivate: [ServalAdminAuthGuard] }, + { path: 'system-administration', component: SystemAdministrationComponent, canActivate: [SystemAdminAuthGuard] }, + { path: '**', component: PageNotFoundComponent } +]; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/attach-audio/attach-audio.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/attach-audio/attach-audio.component.spec.ts index 69ad2fea4ff..6a7e1bc0ccb 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/attach-audio/attach-audio.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/attach-audio/attach-audio.component.spec.ts @@ -7,11 +7,10 @@ import { InvalidFileItem } from 'angular-file/file-upload/fileTools'; import { of } from 'rxjs'; import { anything, instance, mock, verify, when } from 'ts-mockito'; import { DialogService } from 'xforge-common/dialog.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; -import { configureTestingModule, getAudioBlob, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; +import { configureTestingModule, getAudioBlob, getTestTranslocoModule } from 'xforge-common/test-utils'; import { AudioRecorderDialogComponent } from '../../shared/audio-recorder-dialog/audio-recorder-dialog.component'; -import { SharedModule } from '../../shared/shared.module'; +import { provideQuillRegistrations } from '../../shared/text/quill-editor-registration/quill-providers'; import { TextAndAudioComponent } from '../text-and-audio/text-and-audio.component'; import { AttachAudioComponent } from './attach-audio.component'; @@ -21,9 +20,12 @@ describe('AttachAudioComponent', () => { let env: TestEnvironment; configureTestingModule(() => ({ - imports: [UICommonModule, ngfModule, SharedModule.forRoot(), TestTranslocoModule, TestOnlineStatusModule.forRoot()], - declarations: [AttachAudioComponent], - providers: [{ provide: DialogService, useMock: mockDialogService }] + imports: [AttachAudioComponent, ngfModule, getTestTranslocoModule()], + providers: [ + provideQuillRegistrations(), + provideTestOnlineStatus(), + { provide: DialogService, useMock: mockDialogService } + ] })); beforeEach(async () => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/attach-audio/attach-audio.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/attach-audio/attach-audio.component.ts index 949fddeee21..99c005b2b33 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/attach-audio/attach-audio.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/attach-audio/attach-audio.component.ts @@ -1,5 +1,11 @@ +import { NgClass } from '@angular/common'; import { Component, Input, ViewChild } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; import { MatDialogRef } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; +import { ngfModule } from 'angular-file'; import { InvalidFileItem } from 'angular-file/file-upload/fileTools'; import { firstValueFrom } from 'rxjs'; import { DialogService } from 'xforge-common/dialog.service'; @@ -16,7 +22,7 @@ import { TextAndAudioComponent } from '../text-and-audio/text-and-audio.componen selector: 'app-attach-audio', templateUrl: './attach-audio.component.html', styleUrl: './attach-audio.component.scss', - standalone: false + imports: [TranslocoModule, NgClass, MatIconButton, MatTooltip, MatIcon, ngfModule, SingleButtonAudioPlayerComponent] }) export class AttachAudioComponent { @ViewChild(SingleButtonAudioPlayerComponent) audioPlayer?: SingleButtonAudioPlayerComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/chapter-audio-dialog/chapter-audio-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/chapter-audio-dialog/chapter-audio-dialog.component.spec.ts index 870a4428824..1a687cf08b2 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/chapter-audio-dialog/chapter-audio-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/chapter-audio-dialog/chapter-audio-dialog.component.spec.ts @@ -1,8 +1,8 @@ import { OverlayContainer } from '@angular/cdk/overlay'; -import { DebugElement, NgModule, NgZone } from '@angular/core'; +import { DebugElement, NgZone } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { Canon } from '@sillsdev/scripture'; import { ngfModule } from 'angular-file'; import { getTextAudioId, TextAudio } from 'realtime-server/lib/esm/scriptureforge/models/text-audio'; @@ -14,21 +14,21 @@ import { CsvService } from 'xforge-common/csv-service.service'; import { FileService } from 'xforge-common/file.service'; import { FileOfflineData, FileType } from 'xforge-common/models/file-offline-data'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { ChildViewContainerComponent, configureTestingModule, getAudioBlob, - getShortAudioBlob + getShortAudioBlob, + getTestTranslocoModule } from 'xforge-common/test-utils'; import { QuestionDoc } from '../../core/models/question-doc'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { TextAudioDoc } from '../../core/models/text-audio-doc'; import { TextsByBookId } from '../../core/models/texts-by-book-id'; -import { CheckingModule } from '../checking.module'; import { AudioAttachment } from '../checking/checking-audio-player/checking-audio-player.component'; import { ChapterAudioDialogComponent, @@ -41,11 +41,14 @@ const mockedFileService = mock(FileService); describe('ChapterAudioDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, TestOnlineStatusModule.forRoot(), TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [ngfModule, ChapterAudioDialogComponent, getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: CsvService, useMock: mockedCsvService }, { provide: FileService, useMock: mockedFileService }, - { provide: OnlineStatusService, useClass: TestOnlineStatusService } + { provide: OnlineStatusService, useClass: TestOnlineStatusService }, + provideNoopAnimations() ] })); @@ -599,11 +602,6 @@ describe('ChapterAudioDialogComponent', () => { }); }); -@NgModule({ - imports: [NoopAnimationsModule, ngfModule, CheckingModule] -}) -class DialogTestModule {} - class TestEnvironment { static genesisText: TextInfo = { bookNum: 1, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/chapter-audio-dialog/chapter-audio-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/chapter-audio-dialog/chapter-audio-dialog.component.ts index 7209fa5efd9..a340e61d7df 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/chapter-audio-dialog/chapter-audio-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/chapter-audio-dialog/chapter-audio-dialog.component.ts @@ -1,5 +1,19 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { NgClass } from '@angular/common'; import { AfterViewInit, Component, DestroyRef, ElementRef, Inject, OnDestroy, ViewChild } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatAnchor, MatButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; import { cloneDeep, reject } from 'lodash-es'; import { Chapter, TextInfo } from 'realtime-server//lib/esm/scriptureforge/models/text-info'; @@ -21,7 +35,9 @@ import { TextAudioDoc } from '../../core/models/text-audio-doc'; import { TextDocId } from '../../core/models/text-doc'; import { TextsByBookId } from '../../core/models/texts-by-book-id'; import { SFProjectService } from '../../core/sf-project.service'; +import { NoticeComponent } from '../../shared/notice/notice.component'; import { AudioAttachment } from '../checking/checking-audio-player/checking-audio-player.component'; +import { CheckingScriptureAudioPlayerComponent } from '../checking/checking-scripture-audio-player/checking-scripture-audio-player.component'; import { SingleButtonAudioPlayerComponent } from '../checking/single-button-audio-player/single-button-audio-player.component'; const TIMING_FILE_EXTENSION_REGEX = /.(tsv|csv|txt)$/i; @@ -45,7 +61,23 @@ export interface ChapterAudioDialogResult { selector: 'app-chapter-audio-dialog', templateUrl: './chapter-audio-dialog.component.html', styleUrls: ['./chapter-audio-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + MatTooltip, + MatButton, + NgClass, + SingleButtonAudioPlayerComponent, + MatIcon, + CheckingScriptureAudioPlayerComponent, + NoticeComponent, + MatDialogActions, + MatAnchor, + MatDialogClose, + MatProgressSpinner + ] }) export class ChapterAudioDialogComponent implements AfterViewInit, OnDestroy { @ViewChild('dropzone') dropzone!: ElementRef; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-overview/checking-overview.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-overview/checking-overview.component.spec.ts index fe0dfe40144..edd4e65d601 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-overview/checking-overview.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-overview/checking-overview.component.spec.ts @@ -1,9 +1,9 @@ import { Location } from '@angular/common'; -import { DebugElement, NgModule, NgZone } from '@angular/core'; +import { DebugElement, NgZone } from '@angular/core'; import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatExpansionPanel } from '@angular/material/expansion'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { ngfModule } from 'angular-file'; import { saveAs } from 'file-saver'; @@ -32,11 +32,11 @@ import { DialogService } from 'xforge-common/dialog.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { noopDestroyRef } from 'xforge-common/realtime.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { QuestionDoc } from '../../core/models/question-doc'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; @@ -45,7 +45,6 @@ import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { TextDocId } from '../../core/models/text-doc'; import { SFProjectService } from '../../core/sf-project.service'; import { ChapterAudioDialogService } from '../chapter-audio-dialog/chapter-audio-dialog.service'; -import { CheckingModule } from '../checking.module'; import { CheckingQuestionsService } from '../checking/checking-questions.service'; import { ImportQuestionsDialogComponent } from '../import-questions-dialog/import-questions-dialog.component'; import { QuestionDialogService } from '../question-dialog/question-dialog.service'; @@ -62,8 +61,10 @@ const mockedChapterAudioDialogService = mock(ChapterAudioDialogService); describe('CheckingOverviewComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, TestOnlineStatusModule.forRoot(), TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [ngfModule, getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: ActivatedRoute, useMock: mockedActivatedRoute }, { provide: DialogService, useMock: mockedDialogService }, { provide: NoticeService, useMock: mockedNoticeService }, @@ -72,7 +73,8 @@ describe('CheckingOverviewComponent', () => { { provide: UserService, useMock: mockedUserService }, { provide: QuestionDialogService, useMock: mockedQuestionDialogService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, - { provide: ChapterAudioDialogService, useMock: mockedChapterAudioDialogService } + { provide: ChapterAudioDialogService, useMock: mockedChapterAudioDialogService }, + provideNoopAnimations() ] })); @@ -665,11 +667,6 @@ describe('CheckingOverviewComponent', () => { })); }); -@NgModule({ - imports: [NoopAnimationsModule, ngfModule, CheckingModule] -}) -class DialogTestModule {} - interface UserInfo { id: string; user: User; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-overview/checking-overview.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-overview/checking-overview.component.ts index 8b02647d816..47b67641472 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-overview/checking-overview.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-overview/checking-overview.component.ts @@ -1,5 +1,18 @@ +import { NgClass } from '@angular/common'; import { Component, DestroyRef, OnDestroy, OnInit } from '@angular/core'; +import { MatButton, MatIconButton, MatMiniFabButton } from '@angular/material/button'; +import { MatCard, MatCardContent } from '@angular/material/card'; +import { + MatExpansionPanel, + MatExpansionPanelContent, + MatExpansionPanelHeader, + MatExpansionPanelTitle +} from '@angular/material/expansion'; +import { MatIcon } from '@angular/material/icon'; +import { MatList, MatListItem, MatSelectionList } from '@angular/material/list'; +import { MatTooltip } from '@angular/material/tooltip'; import { ActivatedRoute } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; import { saveAs } from 'file-saver'; import Papa from 'papaparse'; @@ -11,11 +24,13 @@ import { asyncScheduler, merge, Subscription } from 'rxjs'; import { map, tap, throttleTime } from 'rxjs/operators'; import { DataLoadingComponent } from 'xforge-common/data-loading-component'; import { DialogService } from 'xforge-common/dialog.service'; +import { DonutChartComponent } from 'xforge-common/donut-chart/donut-chart.component'; import { I18nService } from 'xforge-common/i18n.service'; import { L10nNumberPipe } from 'xforge-common/l10n-number.pipe'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { QuestionDoc } from '../../core/models/question-doc'; @@ -38,7 +53,27 @@ import { QuestionDialogService } from '../question-dialog/question-dialog.servic selector: 'app-checking-overview', templateUrl: './checking-overview.component.html', styleUrls: ['./checking-overview.component.scss'], - standalone: false + imports: [ + TranslocoModule, + NgClass, + MatButton, + MatIcon, + MatMiniFabButton, + DonutChartComponent, + MatExpansionPanel, + MatExpansionPanelHeader, + MatExpansionPanelTitle, + MatIconButton, + MatTooltip, + MatExpansionPanelContent, + MatSelectionList, + MatListItem, + MatList, + RouterLinkDirective, + MatCard, + MatCardContent, + L10nNumberPipe + ] }) export class CheckingOverviewComponent extends DataLoadingComponent implements OnInit, OnDestroy { texts: TextInfo[] = []; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-routing.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-routing.module.ts deleted file mode 100644 index 03f03db09b9..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking-routing.module.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; - -import { CheckingAuthGuard } from '../shared/project-router.guard'; -import { CheckingOverviewComponent } from './checking-overview/checking-overview.component'; -import { CheckingComponent } from './checking/checking.component'; - -const routes: Routes = [ - { - path: 'projects/:projectId/checking/:bookId/:chapter', - component: CheckingComponent, - canActivate: [CheckingAuthGuard] - }, - { path: 'projects/:projectId/checking/:bookId', component: CheckingComponent, canActivate: [CheckingAuthGuard] }, - { path: 'projects/:projectId/checking', component: CheckingOverviewComponent, canActivate: [CheckingAuthGuard] } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class CheckingRoutingModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking.module.ts deleted file mode 100644 index adbbac70071..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking.module.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { TranslocoModule } from '@ngneat/transloco'; -import { ngfModule } from 'angular-file'; -import { AngularSplitModule } from 'angular-split'; -import { OwnerComponent } from 'xforge-common/owner/owner.component'; -import { UICommonModule } from 'xforge-common/ui-common.module'; -import { XForgeCommonModule } from 'xforge-common/xforge-common.module'; -import { AudioPlayerComponent } from '../shared/audio/audio-player/audio-player.component'; -import { AudioTimePipe } from '../shared/audio/audio-time-pipe'; -import { SharedModule } from '../shared/shared.module'; -import { TextChooserDialogComponent } from '../text-chooser-dialog/text-chooser-dialog.component'; -import { AttachAudioComponent } from './attach-audio/attach-audio.component'; -import { ChapterAudioDialogComponent } from './chapter-audio-dialog/chapter-audio-dialog.component'; -import { CheckingOverviewComponent } from './checking-overview/checking-overview.component'; -import { CheckingRoutingModule } from './checking-routing.module'; -import { CheckingAnswersComponent } from './checking/checking-answers/checking-answers.component'; -import { CheckingCommentsComponent } from './checking/checking-answers/checking-comments/checking-comments.component'; -import { CheckingInputFormComponent } from './checking/checking-answers/checking-input-form/checking-input-form.component'; -import { CheckingAudioPlayerComponent } from './checking/checking-audio-player/checking-audio-player.component'; -import { CheckingQuestionsComponent } from './checking/checking-questions/checking-questions.component'; -import { CheckingScriptureAudioPlayerComponent } from './checking/checking-scripture-audio-player/checking-scripture-audio-player.component'; -import { CheckingTextComponent } from './checking/checking-text/checking-text.component'; -import { CheckingComponent } from './checking/checking.component'; -import { FontSizeComponent } from './checking/font-size/font-size.component'; -import { ImportQuestionsConfirmationDialogComponent } from './import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component'; -import { ImportQuestionsDialogComponent } from './import-questions-dialog/import-questions-dialog.component'; -import { QuestionDialogComponent } from './question-dialog/question-dialog.component'; -import { TextAndAudioComponent } from './text-and-audio/text-and-audio.component'; - -@NgModule({ - declarations: [ - CheckingComponent, - CheckingOverviewComponent, - CheckingQuestionsComponent, - CheckingTextComponent, - CheckingAnswersComponent, - TextAndAudioComponent, - AttachAudioComponent, - QuestionDialogComponent, - ImportQuestionsDialogComponent, - ImportQuestionsConfirmationDialogComponent, - FontSizeComponent, - CheckingCommentsComponent, - CheckingInputFormComponent, - CheckingAudioPlayerComponent, - AudioPlayerComponent, - CheckingScriptureAudioPlayerComponent, - AudioTimePipe, - TextChooserDialogComponent, - ChapterAudioDialogComponent - ], - imports: [ - CheckingRoutingModule, - CommonModule, - SharedModule, - UICommonModule, - XForgeCommonModule, - OwnerComponent, - AngularSplitModule, - ngfModule, - TranslocoModule - ], - exports: [CheckingAudioPlayerComponent] -}) -export class CheckingModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-answers.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-answers.component.ts index 39c26d6a879..779695ee4e0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-answers.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-answers.component.ts @@ -1,3 +1,5 @@ +import { Dir } from '@angular/cdk/bidi'; +import { NgClass } from '@angular/common'; import { Component, DestroyRef, @@ -9,7 +11,11 @@ import { ViewChild, ViewChildren } from '@angular/core'; +import { MatButton, MatIconButton } from '@angular/material/button'; import { MatDialogRef } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { VerseRef } from '@sillsdev/scripture'; import { cloneDeep } from 'lodash-es'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; @@ -25,6 +31,7 @@ import { I18nService } from 'xforge-common/i18n.service'; import { FileType } from 'xforge-common/models/file-offline-data'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; +import { OwnerComponent } from 'xforge-common/owner/owner.component'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { QuestionDoc } from '../../../core/models/question-doc'; @@ -40,7 +47,10 @@ import { import { CheckingUtils } from '../../checking.utils'; import { QuestionDialogData } from '../../question-dialog/question-dialog.component'; import { QuestionDialogService } from '../../question-dialog/question-dialog.service'; -import { AudioAttachment } from '../checking-audio-player/checking-audio-player.component'; +import { + AudioAttachment, + CheckingAudioPlayerComponent +} from '../checking-audio-player/checking-audio-player.component'; import { CheckingTextComponent } from '../checking-text/checking-text.component'; import { CheckingCommentsComponent, CommentAction } from './checking-comments/checking-comments.component'; import { CheckingInput, CheckingInputFormComponent } from './checking-input-form/checking-input-form.component'; @@ -89,7 +99,20 @@ enum LikeAnswerResponse { selector: 'app-checking-answers', templateUrl: './checking-answers.component.html', styleUrls: ['./checking-answers.component.scss'], - standalone: false + imports: [ + TranslocoModule, + CheckingQuestionComponent, + MatIconButton, + MatTooltip, + MatIcon, + MatButton, + CheckingInputFormComponent, + NgClass, + Dir, + CheckingAudioPlayerComponent, + OwnerComponent, + CheckingCommentsComponent + ] }) export class CheckingAnswersComponent implements OnInit { @ViewChild(CheckingInputFormComponent) answerInput?: CheckingInputFormComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-comments/checking-comments.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-comments/checking-comments.component.ts index 88f5ded1bc7..a4e05b85791 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-comments/checking-comments.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-comments/checking-comments.component.ts @@ -1,4 +1,9 @@ +import { NgClass } from '@angular/common'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { cloneDeep, sortBy } from 'lodash-es'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { Answer } from 'realtime-server/lib/esm/scriptureforge/models/answer'; @@ -8,11 +13,13 @@ import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scri import { debounceTime } from 'rxjs/operators'; import { DialogService } from 'xforge-common/dialog.service'; import { I18nService } from 'xforge-common/i18n.service'; +import { OwnerComponent } from 'xforge-common/owner/owner.component'; import { SubscriptionDisposable } from 'xforge-common/subscription-disposable'; import { UserService } from 'xforge-common/user.service'; import { QuestionDoc } from '../../../../core/models/question-doc'; import { SFProjectUserConfigDoc } from '../../../../core/models/sf-project-user-config-doc'; import { AudioAttachment } from '../../checking-audio-player/checking-audio-player.component'; +import { SingleButtonAudioPlayerComponent } from '../../single-button-audio-player/single-button-audio-player.component'; import { CheckingInputFormComponent } from '../checking-input-form/checking-input-form.component'; export interface CommentAction { @@ -27,7 +34,17 @@ export interface CommentAction { selector: 'app-checking-comments', templateUrl: './checking-comments.component.html', styleUrls: ['./checking-comments.component.scss'], - standalone: false + imports: [ + TranslocoModule, + NgClass, + SingleButtonAudioPlayerComponent, + MatIcon, + MatIconButton, + MatTooltip, + OwnerComponent, + CheckingInputFormComponent, + MatButton + ] }) export class CheckingCommentsComponent extends SubscriptionDisposable implements OnInit { @ViewChild(CheckingInputFormComponent) inputComponent?: CheckingInputFormComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-comments/checking-comments.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-comments/checking-comments.stories.ts index d7fa30b6fe3..cc633f27be0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-comments/checking-comments.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-comments/checking-comments.stories.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { expect, within } from '@storybook/test'; import { createTestUserProfile } from 'realtime-server/lib/esm/common/models/user-test-data'; @@ -6,10 +5,8 @@ import { Comment } from 'realtime-server/lib/esm/scriptureforge/models/comment'; import { createTestProject } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; import { instance, mock, when } from 'ts-mockito'; import { DialogService } from 'xforge-common/dialog.service'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { UserProfileDoc } from 'xforge-common/models/user-profile-doc'; import { OwnerComponent } from 'xforge-common/owner/owner.component'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { UserService } from 'xforge-common/user.service'; import { CheckingInputFormComponent } from '../checking-input-form/checking-input-form.component'; import { CheckingCommentsComponent } from './checking-comments.component'; @@ -49,12 +46,11 @@ const meta: Meta = { component: CheckingCommentsComponent, decorators: [ moduleMetadata({ - imports: [CommonModule, UICommonModule, I18nStoryModule, OwnerComponent], + imports: [OwnerComponent, CheckingInputFormComponent], providers: [ { provide: DialogService, useValue: instance(mockedDialogService) }, { provide: UserService, useValue: instance(mockedUserService) } - ], - declarations: [CheckingInputFormComponent] + ] }) ], args: defaultArgs diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-input-form/checking-input-form.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-input-form/checking-input-form.component.ts index 7500ee4179e..658930968f0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-input-form/checking-input-form.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-input-form/checking-input-form.component.ts @@ -1,14 +1,22 @@ import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; +import { NgClass } from '@angular/common'; import { Component, DestroyRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { Answer } from 'realtime-server/lib/esm/scriptureforge/models/answer'; import { Comment } from 'realtime-server/lib/esm/scriptureforge/models/comment'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { VerseRefData } from 'realtime-server/lib/esm/scriptureforge/models/verse-ref-data'; +import { AutofocusDirective } from 'xforge-common/autofocus.directive'; import { DialogService } from 'xforge-common/dialog.service'; import { FontService } from 'xforge-common/font.service'; import { I18nService } from 'xforge-common/i18n.service'; import { Breakpoint, MediaBreakpointService } from 'xforge-common/media-breakpoints/media-breakpoint.service'; import { NoticeService } from 'xforge-common/notice.service'; +import { ScrollIntoViewDirective } from 'xforge-common/scroll-into-view'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { QuestionDoc } from '../../../../core/models/question-doc'; import { TextsByBookId } from '../../../../core/models/texts-by-book-id'; @@ -17,6 +25,7 @@ import { TextChooserDialogData, TextSelection } from '../../../../text-chooser-dialog/text-chooser-dialog.component'; +import { AttachAudioComponent } from '../../../attach-audio/attach-audio.component'; import { CheckingUtils } from '../../../checking.utils'; import { TextAndAudioComponent } from '../../../text-and-audio/text-and-audio.component'; import { AudioAttachment } from '../../checking-audio-player/checking-audio-player.component'; @@ -37,7 +46,19 @@ function isAnswer(value: Answer | Comment | undefined): value is Answer { selector: 'app-checking-input-form', templateUrl: './checking-input-form.component.html', styleUrls: ['./checking-input-form.component.scss'], - standalone: false + imports: [ + TranslocoModule, + FormsModule, + ScrollIntoViewDirective, + TextAndAudioComponent, + AutofocusDirective, + NgClass, + AttachAudioComponent, + MatIconButton, + MatTooltip, + MatIcon, + MatButton + ] }) export class CheckingInputFormComponent { @Input() project?: SFProjectProfile; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-input-form/checking-input-form.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-input-form/checking-input-form.stories.ts index a9046bda125..0490eee9e35 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-input-form/checking-input-form.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-input-form/checking-input-form.stories.ts @@ -1,9 +1,7 @@ -import { CommonModule } from '@angular/common'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { expect, userEvent, within } from '@storybook/test'; import { Answer } from 'realtime-server/lib/esm/scriptureforge/models/answer'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { AutofocusDirective } from 'xforge-common/autofocus.directive'; import { AttachAudioComponent } from '../../../attach-audio/attach-audio.component'; import { TextAndAudioComponent } from '../../../text-and-audio/text-and-audio.component'; import { CheckingInputFormComponent } from './checking-input-form.component'; @@ -13,8 +11,7 @@ const meta: Meta = { component: CheckingInputFormComponent, decorators: [ moduleMetadata({ - imports: [CommonModule, UICommonModule, I18nStoryModule], - declarations: [TextAndAudioComponent, AttachAudioComponent] + imports: [AutofocusDirective, TextAndAudioComponent, AttachAudioComponent] }) ] }; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.component.spec.ts index b62bd3f7e69..a3b03a2433c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.component.spec.ts @@ -9,9 +9,8 @@ import { BehaviorSubject, lastValueFrom, Subject } from 'rxjs'; import { takeWhile } from 'rxjs/operators'; import { anything, instance, mock, when } from 'ts-mockito'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { QuestionDoc } from '../../../../core/models/question-doc'; import { SFProjectUserConfigDoc } from '../../../../core/models/sf-project-user-config-doc'; import { TextAudioDoc } from '../../../../core/models/text-audio-doc'; @@ -33,7 +32,7 @@ const mockedSFProjectUserConfigDoc = mock(SFProjectUserConfigDoc); [questionDoc]="questionDoc" (audioPlayed)="played = true" >`, - standalone: false + imports: [CheckingQuestionComponent] }) class MockComponent { @ViewChild('question') question!: CheckingQuestionComponent; @@ -60,9 +59,8 @@ class MockComponent { describe('CheckingQuestionComponent', () => { configureTestingModule(() => ({ - imports: [UICommonModule, TestTranslocoModule, TestOnlineStatusModule.forRoot()], - declarations: [CheckingQuestionComponent, SingleButtonAudioPlayerComponent, MockComponent], - providers: [{ provide: SFProjectService, useMock: mockedSFProjectService }] + imports: [CheckingQuestionComponent, SingleButtonAudioPlayerComponent, getTestTranslocoModule(), MockComponent], + providers: [provideTestOnlineStatus(), { provide: SFProjectService, useMock: mockedSFProjectService }] })); it('selects scripture text when scripture audio is present', async () => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.component.ts index 925bc48045e..09cfbc63ebe 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.component.ts @@ -9,6 +9,8 @@ import { SimpleChanges, ViewChild } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; +import { TranslocoModule } from '@ngneat/transloco'; import { VerseRef } from '@sillsdev/scripture'; import { AudioTiming } from 'realtime-server/lib/esm/scriptureforge/models/audio-timing'; import { getTextAudioId, TextAudio } from 'realtime-server/lib/esm/scriptureforge/models/text-audio'; @@ -31,7 +33,7 @@ import { SingleButtonAudioPlayerComponent } from '../../single-button-audio-play selector: 'app-checking-question', templateUrl: './checking-question.component.html', styleUrls: ['./checking-question.component.scss'], - standalone: false + imports: [TranslocoModule, SingleButtonAudioPlayerComponent, MatIcon] }) export class CheckingQuestionComponent extends SubscriptionDisposable implements OnChanges, OnDestroy { @Output() audioPlayed: EventEmitter = new EventEmitter(); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.stories.ts index 7712de97405..4cf3c6bb3fb 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-answers/checking-question/checking-question.stories.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { expect } from '@storybook/test'; import { cloneDeep } from 'mingo/util'; @@ -10,10 +9,8 @@ import { import { createTestProjectUserConfig } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-user-config-test-data'; import { getTextAudioId, TextAudio } from 'realtime-server/lib/esm/scriptureforge/models/text-audio'; import { anything, instance, mock, when } from 'ts-mockito'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { QuestionDoc } from '../../../../core/models/question-doc'; import { SFProjectUserConfigDoc } from '../../../../core/models/sf-project-user-config-doc'; import { SF_TYPE_REGISTRY } from '../../../../core/models/sf-type-registry'; @@ -68,9 +65,11 @@ const meta: Meta = { component: CheckingQuestionComponent, decorators: [ moduleMetadata({ - imports: [CommonModule, UICommonModule, I18nStoryModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], - providers: [{ provide: SFProjectService, useValue: instance(mockedProjectService) }], - declarations: [SingleButtonAudioPlayerComponent] + imports: [SingleButtonAudioPlayerComponent], + providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), + { provide: SFProjectService, useValue: instance(mockedProjectService) } + ] }) ], args: { questionDoc: instance(questionDoc) } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player-new.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player-new.stories.ts index 33f82ef7db4..b7677140576 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player-new.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player-new.stories.ts @@ -1,11 +1,8 @@ -import { CommonModule } from '@angular/common'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { userEvent, within } from '@storybook/test'; import { of } from 'rxjs'; import { instance, mock, when } from 'ts-mockito'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { AudioPlayerComponent } from '../../../shared/audio/audio-player/audio-player.component'; import { AudioTimePipe } from '../../../shared/audio/audio-time-pipe'; import { InfoComponent } from '../../../shared/info/info.component'; @@ -20,14 +17,8 @@ const meta: Meta = { component: CheckingAudioPlayerComponent, decorators: [ moduleMetadata({ - imports: [UICommonModule, CommonModule, I18nStoryModule], - declarations: [CheckingAudioPlayerComponent, AudioPlayerComponent, AudioTimePipe, InfoComponent], - providers: [ - { - provide: OnlineStatusService, - useValue: instance(mockedOnlineStatusService) - } - ] + imports: [CheckingAudioPlayerComponent, AudioPlayerComponent, AudioTimePipe, InfoComponent], + providers: [{ provide: OnlineStatusService, useValue: instance(mockedOnlineStatusService) }] }) ], args: { source: './test-audio-player.webm' } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player.component.spec.ts index 555a25c6d93..5c7286c9342 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player.component.spec.ts @@ -5,10 +5,9 @@ import { By } from '@angular/platform-browser'; import { lastValueFrom } from 'rxjs'; import { takeWhile } from 'rxjs/operators'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { getAudioBlob, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { getAudioBlob, getTestTranslocoModule } from 'xforge-common/test-utils'; import { AudioStatus } from '../../../shared/audio/audio-player'; import { AudioPlayerComponent } from '../../../shared/audio/audio-player/audio-player.component'; import { AudioTimePipe } from '../../../shared/audio/audio-time-pipe'; @@ -179,7 +178,7 @@ describe('CheckingAudioPlayerComponent', () => { @Component({ selector: 'app-host', template: '', - standalone: false + imports: [CheckingAudioPlayerComponent] }) class HostComponent { @ViewChild(CheckingAudioPlayerComponent) player1!: CheckingAudioPlayerComponent; @@ -195,9 +194,15 @@ class TestEnvironment { constructor(template: string, isOnline = true) { TestBed.configureTestingModule({ - declarations: [HostComponent, CheckingAudioPlayerComponent, AudioPlayerComponent, AudioTimePipe, InfoComponent], - providers: [{ provide: OnlineStatusService, useClass: TestOnlineStatusService }], - imports: [UICommonModule, TestOnlineStatusModule.forRoot(), TestTranslocoModule] + imports: [ + getTestTranslocoModule(), + HostComponent, + CheckingAudioPlayerComponent, + AudioPlayerComponent, + AudioTimePipe, + InfoComponent + ], + providers: [{ provide: OnlineStatusService, useClass: TestOnlineStatusService }, provideTestOnlineStatus()] }); TestBed.overrideComponent(HostComponent, { set: { template: template } }); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player.component.ts index 7d7fc61b0b9..16cafca0917 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-audio-player/checking-audio-player.component.ts @@ -1,7 +1,12 @@ +import { Dir } from '@angular/cdk/bidi'; import { AfterViewInit, Component, DestroyRef, Input, ViewChild } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { TranslocoModule } from '@ngneat/transloco'; import { I18nService } from 'xforge-common/i18n.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { AudioPlayerComponent } from '../../../shared/audio/audio-player/audio-player.component'; + export interface AudioAttachment { status?: 'denied' | 'processed' | 'recording' | 'reset' | 'stopped' | 'uploaded'; url?: string; @@ -13,7 +18,7 @@ export interface AudioAttachment { selector: 'app-checking-audio-player', templateUrl: './checking-audio-player.component.html', styleUrls: ['./checking-audio-player.component.scss'], - standalone: false + imports: [TranslocoModule, Dir, MatIconButton, MatIcon, AudioPlayerComponent] }) export class CheckingAudioPlayerComponent implements AfterViewInit { private _isAudioAvailable = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-questions.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-questions.service.spec.ts index b0803f0dd98..b08689940e1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-questions.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-questions.service.spec.ts @@ -5,7 +5,7 @@ import { FileType } from 'xforge-common/models/file-offline-data'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { Snapshot } from 'xforge-common/models/snapshot'; import { noopDestroyRef } from 'xforge-common/realtime.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { TypeRegistry } from 'xforge-common/type-registry'; @@ -170,7 +170,7 @@ describe('CheckingQuestionsService', () => { let realtimeService: TestRealtimeService; configureTestingModule(() => ({ - imports: [TestRealtimeModule.forRoot(new TypeRegistry([QuestionDoc], [FileType.Audio], []))] + providers: [provideTestRealtime(new TypeRegistry([QuestionDoc], [FileType.Audio], []))] })); beforeEach(() => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-questions/checking-questions.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-questions/checking-questions.component.ts index a1482ac74d7..2f379a19745 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-questions/checking-questions.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-questions/checking-questions.component.ts @@ -1,3 +1,4 @@ +import { NgClass } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -13,7 +14,12 @@ import { SimpleChanges, ViewChildren } from '@angular/core'; -import { MatListItem } from '@angular/material/list'; +import { MatBadge } from '@angular/material/badge'; +import { MatButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatActionList, MatListItem } from '@angular/material/list'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { sortBy } from 'lodash-es'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { Answer } from 'realtime-server/lib/esm/scriptureforge/models/answer'; @@ -62,7 +68,7 @@ export interface QuestionChangedEvent { templateUrl: './checking-questions.component.html', styleUrls: ['./checking-questions.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, - standalone: false + imports: [TranslocoModule, MatActionList, MatListItem, NgClass, MatTooltip, MatBadge, MatIcon, MatButton] }) export class CheckingQuestionsComponent implements OnInit, OnChanges { @Output() update = new EventEmitter(); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.component.spec.ts index a39b99e871b..c4aba153ad6 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.component.spec.ts @@ -4,11 +4,11 @@ import { By } from '@angular/platform-browser'; import { AudioTiming } from 'realtime-server/lib/esm/scriptureforge/models/audio-timing'; import { BehaviorSubject } from 'rxjs'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { getTestTranslocoModule } from 'xforge-common/test-utils'; import { TextDocId } from '../../../core/models/text-doc'; +import { AudioPlayerComponent } from '../../../shared/audio/audio-player/audio-player.component'; import { AudioPlayerStub, getAudioTimings, getAudioTimingWithHeadings } from '../../checking-test.utils'; import { CheckingScriptureAudioPlayerComponent } from './checking-scripture-audio-player.component'; @@ -238,7 +238,7 @@ describe('ScriptureAudioComponent', () => { @Component({ selector: 'app-host', template: '', - standalone: false + imports: [CheckingScriptureAudioPlayerComponent] }) class HostComponent { @ViewChild(CheckingScriptureAudioPlayerComponent) audioPlayer!: CheckingScriptureAudioPlayerComponent; @@ -246,8 +246,7 @@ class HostComponent { @Component({ selector: 'app-audio-player', - template: '

Mock Audio Player

', - standalone: false + template: '

Mock Audio Player

' }) class AudioPlayerStubComponent { readonly testOnlineStatusService: TestOnlineStatusService = TestBed.inject( @@ -278,10 +277,19 @@ class TestEnvironment { const template = ``; TestBed.configureTestingModule({ - declarations: [HostComponent, CheckingScriptureAudioPlayerComponent, AudioPlayerStubComponent], - imports: [UICommonModule, TestOnlineStatusModule.forRoot(), TestTranslocoModule] + imports: [ + getTestTranslocoModule(), + HostComponent, + CheckingScriptureAudioPlayerComponent, + AudioPlayerStubComponent + ], + providers: [provideTestOnlineStatus()] }); TestBed.overrideComponent(HostComponent, { set: { template: template } }); + TestBed.overrideComponent(CheckingScriptureAudioPlayerComponent, { + remove: { imports: [AudioPlayerComponent] }, + add: { imports: [AudioPlayerStubComponent] } + }); this.ngZone = TestBed.inject(NgZone); this.fixture = TestBed.createComponent(HostComponent); this.component = this.fixture.componentInstance; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.component.ts index c6e238125f9..208e6c69ee9 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.component.ts @@ -1,4 +1,8 @@ +import { Dir } from '@angular/cdk/bidi'; import { AfterViewInit, Component, DestroyRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon, VerseRef } from '@sillsdev/scripture'; import { AudioTiming } from 'realtime-server/lib/esm/scriptureforge/models/audio-timing'; import { Subscription } from 'rxjs'; @@ -14,7 +18,7 @@ import { AudioHeadingRef, AudioTextRef, CheckingUtils } from '../../checking.uti selector: 'app-checking-scripture-audio-player', templateUrl: './checking-scripture-audio-player.component.html', styleUrls: ['./checking-scripture-audio-player.component.scss'], - standalone: false + imports: [TranslocoModule, Dir, MatIconButton, MatIcon, AudioPlayerComponent] }) export class CheckingScriptureAudioPlayerComponent implements AfterViewInit { @Input() canClose: boolean = true; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.stories.ts index 4773f61b050..3eab39227c7 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-scripture-audio-player/checking-scripture-audio-player.stories.ts @@ -1,10 +1,7 @@ -import { CommonModule } from '@angular/common'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { of } from 'rxjs'; import { instance, mock, when } from 'ts-mockito'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { SFProjectService } from '../../../core/sf-project.service'; import { AudioPlayerComponent } from '../../../shared/audio/audio-player/audio-player.component'; import { AudioTimePipe } from '../../../shared/audio/audio-time-pipe'; @@ -38,17 +35,10 @@ const meta: Meta = { }, decorators: [ moduleMetadata({ - imports: [UICommonModule, CommonModule, I18nStoryModule], - declarations: [AudioPlayerComponent, AudioTimePipe], + imports: [AudioPlayerComponent, AudioTimePipe], providers: [ - { - provide: SFProjectService, - useValue: instance(mockedSFProjectService) - }, - { - provide: OnlineStatusService, - useValue: instance(mockedOnlineStatusService) - } + { provide: SFProjectService, useValue: instance(mockedSFProjectService) }, + { provide: OnlineStatusService, useValue: instance(mockedOnlineStatusService) } ] }), (story, context) => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-text/checking-text.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-text/checking-text.component.spec.ts index f51d96a4e4d..96d3777dc62 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-text/checking-text.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-text/checking-text.component.spec.ts @@ -1,5 +1,5 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { VerseRef } from '@sillsdev/scripture'; import { User } from 'realtime-server/lib/esm/common/models/user'; import { createTestUser } from 'realtime-server/lib/esm/common/models/user-test-data'; @@ -10,19 +10,18 @@ import { anything, mock, when } from 'ts-mockito'; import { DialogService } from 'xforge-common/dialog.service'; import { UserDoc } from 'xforge-common/models/user-doc'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../../core/models/sf-type-registry'; import { TextDoc, TextDocId } from '../../../core/models/text-doc'; import { SFProjectService } from '../../../core/sf-project.service'; -import { SharedModule } from '../../../shared/shared.module'; import { getCombinedVerseTextDoc, getTextDoc } from '../../../shared/test-utils'; +import { provideQuillRegistrations } from '../../../shared/text/quill-editor-registration/quill-providers'; import { EDITOR_READY_TIMEOUT } from '../../../shared/text/text.component'; import { CheckingTextComponent } from './checking-text.component'; @@ -32,20 +31,16 @@ const mockedDialogService = mock(DialogService); describe('CheckingTextComponent', () => { configureTestingModule(() => ({ - declarations: [CheckingTextComponent], - imports: [ - NoopAnimationsModule, - SharedModule.forRoot(), - UICommonModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - TestOnlineStatusModule.forRoot(), - TestTranslocoModule - ], + imports: [CheckingTextComponent, getTestTranslocoModule()], providers: [ + provideQuillRegistrations(), + provideTestRealtime(SF_TYPE_REGISTRY), + provideTestOnlineStatus(), { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: SFProjectService, useMock: mockedSFProjectService }, { provide: UserService, useMock: mockedUserService }, - { provide: DialogService, useMock: mockedDialogService } + { provide: DialogService, useMock: mockedDialogService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-text/checking-text.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-text/checking-text.component.ts index e1b6351d74d..4e1dffdb027 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-text/checking-text.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking-text/checking-text.component.ts @@ -13,7 +13,7 @@ import { verseRefFromMouseEvent } from '../../../shared/utils'; selector: 'app-checking-text', templateUrl: './checking-text.component.html', styleUrls: ['./checking-text.component.scss'], - standalone: false + imports: [TextComponent] }) export class CheckingTextComponent implements AfterViewInit { @ViewChild(TextComponent, { static: true }) textComponent!: TextComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking.component.spec.ts index ad5cf30fe0a..6895b9a2c17 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking.component.spec.ts @@ -3,13 +3,14 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { Location } from '@angular/common'; import { DebugElement, DestroyRef, NgZone } from '@angular/core'; import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; import { MatButtonHarness } from '@angular/material/button/testing'; import { MatDialogRef } from '@angular/material/dialog'; import { MatMenuHarness } from '@angular/material/menu/testing'; import { MatSelectHarness } from '@angular/material/select/testing'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ActivatedRoute, ActivatedRouteSnapshot, Params, Route, Router, RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { ActivatedRoute, ActivatedRouteSnapshot, Params, provideRouter, Route, Router } from '@angular/router'; import { Canon, VerseRef } from '@sillsdev/scripture'; import { ngfModule } from 'angular-file'; import { AngularSplitModule } from 'angular-split'; @@ -47,12 +48,11 @@ import { UserProfileDoc } from 'xforge-common/models/user-profile-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { OwnerComponent } from 'xforge-common/owner/owner.component'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, getAudioBlob, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getAudioBlob, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { objectId } from 'xforge-common/utils'; import { QuestionDoc } from '../../core/models/question-doc'; @@ -67,7 +67,7 @@ import { TranslationEngineService } from '../../core/translation-engine.service' import { AudioRecorderDialogComponent } from '../../shared/audio-recorder-dialog/audio-recorder-dialog.component'; import { AudioPlayerComponent } from '../../shared/audio/audio-player/audio-player.component'; import { AudioTimePipe } from '../../shared/audio/audio-time-pipe'; -import { SharedModule } from '../../shared/shared.module'; +import { provideQuillRegistrations } from '../../shared/text/quill-editor-registration/quill-providers'; import { TextChooserDialogComponent, TextSelection } from '../../text-chooser-dialog/text-chooser-dialog.component'; import { AttachAudioComponent } from '../attach-audio/attach-audio.component'; import { ChapterAudioDialogService } from '../chapter-audio-dialog/chapter-audio-dialog.service'; @@ -135,9 +135,8 @@ const ROUTES: Route[] = [ describe('CheckingComponent', () => { configureTestingModule(() => ({ - declarations: [ + imports: [ AudioTimePipe, - AudioPlayerComponent, CheckingAnswersComponent, CheckingAudioPlayerComponent, CheckingInputFormComponent, @@ -145,24 +144,22 @@ describe('CheckingComponent', () => { CheckingComponent, CheckingScriptureAudioPlayerComponent, CheckingQuestionsComponent, - CheckingTextComponent, TextAndAudioComponent, FontSizeComponent, - AttachAudioComponent - ], - imports: [ + AttachAudioComponent, + AudioPlayerComponent, + CheckingTextComponent, AngularSplitModule, ngfModule, - NoopAnimationsModule, - RouterModule.forRoot(ROUTES), - SharedModule.forRoot(), - UICommonModule, + ReactiveFormsModule, OwnerComponent, - TestTranslocoModule, - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) + getTestTranslocoModule() ], providers: [ + provideRouter(ROUTES), + provideQuillRegistrations(), + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: ActivatedRoute, useMock: mockedActivatedRoute }, { provide: UserService, useMock: mockedUserService }, { provide: SFProjectService, useMock: mockedProjectService }, @@ -172,7 +169,8 @@ describe('CheckingComponent', () => { { provide: QuestionDialogService, useMock: mockedQuestionDialogService }, { provide: ChapterAudioDialogService, useMock: mockedChapterAudioDialogService }, { provide: FileService, useMock: mockedFileService }, - { provide: OnlineStatusService, useClass: TestOnlineStatusService } + { provide: OnlineStatusService, useClass: TestOnlineStatusService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking.component.ts index 438cd4f85a4..87216fe1063 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/checking.component.ts @@ -1,8 +1,16 @@ +import { Dir } from '@angular/cdk/bidi'; import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; +import { AsyncPipe, KeyValuePipe, NgClass } from '@angular/common'; import { AfterViewInit, Component, DestroyRef, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatListSubheaderCssMatStyler, MatSelectionList } from '@angular/material/list'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { MatTooltip } from '@angular/material/tooltip'; import { ActivatedRoute, NavigationBehaviorOptions, Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon, VerseRef } from '@sillsdev/scripture'; -import { SplitComponent } from 'angular-split'; +import { AngularSplitModule, SplitComponent } from 'angular-split'; import { cloneDeep, debounce } from 'lodash-es'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { Answer, AnswerStatus } from 'realtime-server/lib/esm/scriptureforge/models/answer'; @@ -17,12 +25,14 @@ import { toVerseRef, VerseRefData } from 'realtime-server/lib/esm/scriptureforge import { asyncScheduler, BehaviorSubject, combineLatest, merge, Observable, of, Subscription } from 'rxjs'; import { distinctUntilChanged, filter, map, startWith, take, throttleTime } from 'rxjs/operators'; import { DataLoadingComponent } from 'xforge-common/data-loading-component'; +import { DonutChartComponent } from 'xforge-common/donut-chart/donut-chart.component'; import { I18nService } from 'xforge-common/i18n.service'; import { Breakpoint, MediaBreakpointService } from 'xforge-common/media-breakpoints/media-breakpoint.service'; import { FileType } from 'xforge-common/models/file-offline-data'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { objectId } from 'xforge-common/utils'; @@ -35,6 +45,8 @@ import { TextDocId } from '../../core/models/text-doc'; import { TextsByBookId } from '../../core/models/texts-by-book-id'; import { PermissionsService } from '../../core/permissions.service'; import { SFProjectService } from '../../core/sf-project.service'; +import { BookChapterChooserComponent } from '../../shared/book-chapter-chooser/book-chapter-chooser.component'; +import { ShareButtonComponent } from '../../shared/share/share-button.component'; import { getVerseStrFromSegmentRef } from '../../shared/utils'; import { ChapterAudioDialogData } from '../chapter-audio-dialog/chapter-audio-dialog.component'; import { ChapterAudioDialogService } from '../chapter-audio-dialog/chapter-audio-dialog.service'; @@ -48,6 +60,7 @@ import { CheckingQuestionsService, PreCreationQuestionData, QuestionFilter } fro import { CheckingQuestionsComponent, QuestionChangedEvent } from './checking-questions/checking-questions.component'; import { CheckingScriptureAudioPlayerComponent } from './checking-scripture-audio-player/checking-scripture-audio-player.component'; import { CheckingTextComponent } from './checking-text/checking-text.component'; +import { FontSizeComponent } from './font-size/font-size.component'; interface Summary { unread: number; @@ -59,7 +72,32 @@ interface Summary { selector: 'app-checking', templateUrl: './checking.component.html', styleUrls: ['./checking.component.scss'], - standalone: false + imports: [ + TranslocoModule, + NgClass, + MatMenu, + MatSelectionList, + MatListSubheaderCssMatStyler, + MatMenuItem, + MatIcon, + MatIconButton, + MatButton, + MatMenuTrigger, + CheckingQuestionsComponent, + BookChapterChooserComponent, + MatTooltip, + FontSizeComponent, + ShareButtonComponent, + AngularSplitModule, + Dir, + CheckingTextComponent, + CheckingAnswersComponent, + CheckingScriptureAudioPlayerComponent, + RouterLinkDirective, + DonutChartComponent, + AsyncPipe, + KeyValuePipe + ] }) export class CheckingComponent extends DataLoadingComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild('answerPanelContainer') set answersPanelElement(answersPanelContainerElement: ElementRef) { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.component.spec.ts index b45b83cef7b..eee3f1f6df7 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.component.spec.ts @@ -3,9 +3,8 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { MatButtonHarness } from '@angular/material/button/testing'; import { MatMenuHarness, MatMenuItemHarness } from '@angular/material/menu/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { getTestTranslocoModule } from 'xforge-common/test-utils'; import { FontSizeComponent } from './font-size.component'; describe('FontSizeComponent', () => { @@ -31,8 +30,8 @@ describe('FontSizeComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - imports: [UICommonModule, NoopAnimationsModule, TestTranslocoModule], - declarations: [FontSizeComponent] + imports: [getTestTranslocoModule(), FontSizeComponent], + providers: [provideNoopAnimations()] }).compileComponents(); fixture = TestBed.createComponent(FontSizeComponent); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.component.ts index d3beb3d8b53..acc66b2ef45 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.component.ts @@ -1,10 +1,16 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { TranslocoModule } from '@ngneat/transloco'; +import { MatIconButton } from '@angular/material/button'; +import { MatMenuTrigger, MatMenu, MatMenuItem } from '@angular/material/menu'; +import { NgClass } from '@angular/common'; +import { MatTooltip } from '@angular/material/tooltip'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'app-font-size', templateUrl: './font-size.component.html', styleUrls: ['./font-size.component.scss'], - standalone: false + imports: [TranslocoModule, MatIconButton, MatMenuTrigger, NgClass, MatTooltip, MatIcon, MatMenu, MatMenuItem] }) export class FontSizeComponent implements OnInit { @Input() min: number = 1; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.stories.ts index 6b231d47192..ad9dd3d541e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/font-size/font-size.stories.ts @@ -1,9 +1,7 @@ -import { CommonModule } from '@angular/common'; import { componentWrapperDecorator, Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { expect, userEvent } from '@storybook/test'; import { PointerEventsCheckLevel } from '@testing-library/user-event'; -import { TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { getTestTranslocoModule } from 'xforge-common/test-utils'; import { FontSizeComponent } from './font-size.component'; export default { @@ -11,7 +9,7 @@ export default { component: FontSizeComponent, decorators: [ moduleMetadata({ - imports: [CommonModule, UICommonModule, TestTranslocoModule] + imports: [getTestTranslocoModule()] }), componentWrapperDecorator( story => ` diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.component.spec.ts index 1bb6cdae3f5..11ffbc90514 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.component.spec.ts @@ -1,11 +1,15 @@ +import { NgClass } from '@angular/common'; import { Component, DebugElement, NgZone, ViewChild } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { MatTooltip } from '@angular/material/tooltip'; import { By } from '@angular/platform-browser'; +import { TranslocoModule } from '@ngneat/transloco'; import { BehaviorSubject } from 'rxjs'; import { instance, mock, resetCalls, verify, when } from 'ts-mockito'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { AudioPlayer, AudioStatus } from '../../../shared/audio/audio-player'; import { AudioSegmentPlayer } from '../../../shared/audio/audio-segment-player'; import { SingleButtonAudioPlayerComponent } from './single-button-audio-player.component'; @@ -15,8 +19,8 @@ when(audioMock.status$).thenReturn(new BehaviorSubject(AudioStatus. describe('SingleButtonAudioPlayerComponent', () => { configureTestingModule(() => ({ - imports: [UICommonModule, TestTranslocoModule, TestOnlineStatusModule.forRoot()], - declarations: [TestComponent, MockComponent] + imports: [TestComponent, getTestTranslocoModule(), MockComponent], + providers: [provideTestOnlineStatus()] })); let env: TestEnvironment; @@ -158,10 +162,22 @@ class TestEnvironment { } @Component({ - template: ` + selector: 'app-test-player', + templateUrl: './single-button-audio-player.component.html', + styleUrls: ['./single-button-audio-player.component.scss'], + imports: [TranslocoModule, NgClass, MatProgressSpinner, MatIcon, MatTooltip] +}) +class TestComponent extends SingleButtonAudioPlayerComponent { + public setAudio(audioPlayer: AudioPlayer | undefined): void { + this.audio = audioPlayer; + } +} + +@Component({ + template: ` play - `, - standalone: false + `, + imports: [TestComponent, MatIcon] }) class MockComponent { @ViewChild('player') player!: TestComponent; @@ -172,9 +188,3 @@ class MockComponent { this.source = 'test-audio-player.webm'; } } - -class TestComponent extends SingleButtonAudioPlayerComponent { - public setAudio(audioPlayer: AudioPlayer | undefined): void { - this.audio = audioPlayer; - } -} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.component.ts index a97291922f9..1c2dec57e92 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.component.ts @@ -1,4 +1,9 @@ +import { NgClass } from '@angular/common'; import { Component, Input, OnChanges, OnDestroy } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { BehaviorSubject, Subscription } from 'rxjs'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { AudioPlayer, AudioStatus } from '../../../shared/audio/audio-player'; @@ -9,7 +14,7 @@ import { AudioSegmentPlayer } from '../../../shared/audio/audio-segment-player'; selector: 'app-single-button-audio-player', templateUrl: './single-button-audio-player.component.html', styleUrls: ['./single-button-audio-player.component.scss'], - standalone: false + imports: [TranslocoModule, NgClass, MatProgressSpinner, MatIcon, MatTooltip] }) export class SingleButtonAudioPlayerComponent extends AudioPlayerBaseComponent implements OnChanges, OnDestroy { private _source?: string; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.stories.ts index a3204b8859b..80df7f08955 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/checking/single-button-audio-player/single-button-audio-player.stories.ts @@ -1,11 +1,9 @@ -import { CommonModule } from '@angular/common'; import { Component, ViewChild } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { of } from 'rxjs'; import { instance, mock, when } from 'ts-mockito'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { SingleButtonAudioPlayerComponent } from './single-button-audio-player.component'; @Component({ @@ -13,7 +11,7 @@ import { SingleButtonAudioPlayerComponent } from './single-button-audio-player.c template: ` {{ player.playing ? 'stop' : 'play_arrow' }} `, - standalone: false + imports: [SingleButtonAudioPlayerComponent, MatIcon] }) class TestComponent { @ViewChild('player') player!: SingleButtonAudioPlayerComponent; @@ -31,14 +29,8 @@ const meta: Meta = { component: TestComponent, decorators: [ moduleMetadata({ - imports: [UICommonModule, CommonModule, I18nStoryModule], - providers: [ - { - provide: OnlineStatusService, - useValue: instance(mockedOnlineStatusService) - } - ], - declarations: [SingleButtonAudioPlayerComponent, TestComponent] + imports: [SingleButtonAudioPlayerComponent, TestComponent], + providers: [{ provide: OnlineStatusService, useValue: instance(mockedOnlineStatusService) }] }) ] }; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.html index d6acdd07246..25da6b6ec14 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.html @@ -1,5 +1,5 @@ - +

{{ t("some_questions_edited") }}

{{ t("edited_questions_explanation") }} @@ -44,5 +44,5 @@

{{ t("some_questions_edited") }}

{{ t("done") }} - +
diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.spec.ts index c7be2fa0e3c..655c8c99f6a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.spec.ts @@ -1,11 +1,9 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { NgModule } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { firstValueFrom } from 'rxjs'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { EditedQuestion, ImportQuestionsConfirmationDialogComponent, @@ -15,7 +13,8 @@ import { describe('ImportQuestionsConfirmationDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule] + imports: [getTestTranslocoModule(), ImportQuestionsConfirmationDialogComponent], + providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] })); it('Allows selecting and unselecting all questions', fakeAsync(async () => { @@ -69,13 +68,6 @@ describe('ImportQuestionsConfirmationDialogComponent', () => { })); }); -@NgModule({ - declarations: [ImportQuestionsConfirmationDialogComponent], - imports: [UICommonModule, TestTranslocoModule], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}) -class DialogTestModule {} - class TestEnvironment { fixture: ComponentFixture; component: ImportQuestionsConfirmationDialogComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.ts index 946ccff4ed0..a6e902d3497 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-confirmation-dialog/import-questions-confirmation-dialog.component.ts @@ -1,7 +1,30 @@ import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { MatTableDataSource } from '@angular/material/table'; +import { + MAT_DIALOG_DATA, + MatDialogRef, + MatDialogTitle, + MatDialogContent, + MatDialogActions +} from '@angular/material/dialog'; +import { + MatTableDataSource, + MatTable, + MatColumnDef, + MatHeaderCellDef, + MatHeaderCell, + MatCellDef, + MatCell, + MatHeaderRowDef, + MatHeaderRow, + MatRowDef, + MatRow +} from '@angular/material/table'; import { I18nService } from 'xforge-common/i18n.service'; +import { TranslocoModule } from '@ngneat/transloco'; +import { Dir } from '@angular/cdk/bidi'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { MatButton } from '@angular/material/button'; export interface ImportQuestionsConfirmationDialogData { questions: EditedQuestion[]; @@ -19,7 +42,26 @@ export interface EditedQuestion { @Component({ templateUrl: './import-questions-confirmation-dialog.component.html', styleUrls: ['./import-questions-confirmation-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + Dir, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + MatTable, + MatColumnDef, + MatHeaderCellDef, + MatHeaderCell, + MatCheckbox, + MatCellDef, + MatCell, + MatHeaderRowDef, + MatHeaderRow, + MatRowDef, + MatRow, + MatDialogActions, + MatButton + ] }) export class ImportQuestionsConfirmationDialogComponent { questions: EditedQuestion[]; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.html index 5deb5eb2050..527482691b5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.html @@ -178,8 +178,8 @@

{{ referenceForDisplay(element.question) }} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.spec.ts index d6ed5c2900a..ed9a29a21fa 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.spec.ts @@ -1,12 +1,9 @@ import { OverlayContainer } from '@angular/cdk/overlay'; -import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; -import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { NgModule } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; -import { FormControl } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { MatCheckbox } from '@angular/material/checkbox'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { Canon, VerseRef } from '@sillsdev/scripture'; import { ngfModule } from 'angular-file'; import { Answer } from 'realtime-server/lib/esm/scriptureforge/models/answer'; @@ -19,11 +16,10 @@ import { CsvService } from 'xforge-common/csv-service.service'; import { DialogService } from 'xforge-common/dialog.service'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { TestingRetryingRequestService } from 'xforge-common/testing-retrying-request.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { QuestionDoc } from '../../core/models/question-doc'; import { TextsByBookId } from '../../core/models/texts-by-book-id'; import { SFProjectService } from '../../core/sf-project.service'; @@ -44,13 +40,21 @@ const mockedRealtimeQuery: RealtimeQuery = mock(RealtimeQuery); describe('ImportQuestionsDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, TestOnlineStatusModule.forRoot()], + imports: [ + ReactiveFormsModule, + getTestTranslocoModule(), + ngfModule, + ScriptureChooserDialogComponent, + ImportQuestionsDialogComponent + ], providers: [ + provideTestOnlineStatus(), { provide: SFProjectService, useMock: mockedProjectService }, { provide: CheckingQuestionsService, useMock: mockedQuestionsService }, { provide: DialogService, useMock: mockedDialogService }, { provide: CsvService, useMock: mockedCsvService }, - { provide: OnlineStatusService, useClass: TestOnlineStatusService } + { provide: OnlineStatusService, useClass: TestOnlineStatusService }, + provideNoopAnimations() ] })); @@ -500,14 +504,6 @@ describe('ImportQuestionsDialogComponent', () => { })); }); -@NgModule({ - declarations: [ScriptureChooserDialogComponent, ImportQuestionsDialogComponent], - - imports: [UICommonModule, TestTranslocoModule, NoopAnimationsModule, ngfModule], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}) -class DialogTestModule {} - class TestEnvironment { fixture: ComponentFixture; component: ImportQuestionsDialogComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.ts index 89a453ed1eb..5f99cf9a609 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/import-questions-dialog/import-questions-dialog.component.ts @@ -1,9 +1,39 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { AsyncPipe } from '@angular/common'; import { Component, DestroyRef, ElementRef, Inject, NgZone, OnDestroy, ViewChild } from '@angular/core'; -import { AbstractControl, FormControl, FormGroup } from '@angular/forms'; +import { AbstractControl, FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatAnchor, MatButton, MatIconButton } from '@angular/material/button'; +import { MatCard, MatCardActions, MatCardContent, MatCardTitle } from '@angular/material/card'; import { MatCheckbox } from '@angular/material/checkbox'; -import { MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; -import { TranslocoService } from '@ngneat/transloco'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogConfig, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatError, MatFormField, MatLabel, MatSuffix } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatInput } from '@angular/material/input'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + MatTable +} from '@angular/material/table'; +import { TranslocoModule, TranslocoService } from '@ngneat/transloco'; import { Canon, VerseRef } from '@sillsdev/scripture'; +import { ngfModule } from 'angular-file'; import { Question } from 'realtime-server/lib/esm/scriptureforge/models/question'; import { fromVerseRef, toVerseRef } from 'realtime-server/lib/esm/scriptureforge/models/verse-ref-data'; import { Subject } from 'rxjs'; @@ -68,7 +98,44 @@ type DialogStatus = 'initial' | 'no_questions' | 'filter' | 'loading' | 'progres @Component({ templateUrl: './import-questions-dialog.component.html', styleUrls: ['./import-questions-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + MatIconButton, + MatDialogClose, + MatIcon, + CdkScrollable, + MatDialogContent, + MatCard, + MatCardTitle, + MatCardContent, + MatCardActions, + MatButton, + MatAnchor, + MatError, + ngfModule, + MatProgressSpinner, + MatTable, + MatColumnDef, + MatHeaderCellDef, + MatHeaderCell, + MatCellDef, + MatCell, + MatHeaderRowDef, + MatHeaderRow, + MatRowDef, + MatRow, + FormsModule, + ReactiveFormsModule, + MatFormField, + MatLabel, + MatInput, + MatSuffix, + MatCheckbox, + MatProgressBar, + MatDialogActions, + AsyncPipe + ] }) export class ImportQuestionsDialogComponent implements OnDestroy { questionSource: null | 'transcelerator' | 'csv_file' = null; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.component.spec.ts index 707818e2b03..35638d89825 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.component.spec.ts @@ -1,12 +1,9 @@ -import { CommonModule } from '@angular/common'; -import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; -import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { DebugElement, NgModule } from '@angular/core'; +import { DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { VerseRef } from '@sillsdev/scripture'; import { CookieService } from 'ngx-cookie-service'; import { Delta } from 'quill'; @@ -27,17 +24,16 @@ import { createStorageFileData, FileType } from 'xforge-common/models/file-offli import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { ChildViewContainerComponent, configureTestingModule, getAudioBlob, - TestTranslocoModule + getTestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { UserService } from 'xforge-common/user.service'; import { QuestionDoc } from '../../core/models/question-doc'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; @@ -45,10 +41,9 @@ import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { TextDoc, TextDocId } from '../../core/models/text-doc'; import { SFProjectService } from '../../core/sf-project.service'; import { ScriptureChooserDialogComponent } from '../../scripture-chooser-dialog/scripture-chooser-dialog.component'; -import { SharedModule } from '../../shared/shared.module'; import { getTextDoc } from '../../shared/test-utils'; +import { provideQuillRegistrations } from '../../shared/text/quill-editor-registration/quill-providers'; import { EDITOR_READY_TIMEOUT } from '../../shared/text/text.component'; -import { CheckingModule } from '../checking.module'; import { AudioAttachment } from '../checking/checking-audio-player/checking-audio-player.component'; import { QuestionDialogComponent, QuestionDialogData } from './question-dialog.component'; @@ -65,12 +60,14 @@ describe('QuestionDialogComponent', () => { imports: [ ReactiveFormsModule, FormsModule, - DialogTestModule, - SharedModule.forRoot(), - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) + getTestTranslocoModule(), + ScriptureChooserDialogComponent, + QuestionDialogComponent ], providers: [ + provideQuillRegistrations(), + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: AuthService, useMock: mockedAuthService }, { provide: UserService, useMock: mockedUserService }, { provide: NoticeService, useMock: mockedNoticeService }, @@ -78,7 +75,8 @@ describe('QuestionDialogComponent', () => { { provide: BugsnagService, useMock: mockedBugsnagService }, { provide: CookieService, useMock: mockedCookieService }, { provide: FileService, useMock: mockedFileService }, - { provide: OnlineStatusService, useClass: TestOnlineStatusService } + { provide: OnlineStatusService, useClass: TestOnlineStatusService }, + provideNoopAnimations() ] })); @@ -575,14 +573,6 @@ describe('QuestionDialogComponent', () => { })); }); -@NgModule({ - declarations: [ScriptureChooserDialogComponent], - exports: [ScriptureChooserDialogComponent], - imports: [CommonModule, UICommonModule, CheckingModule, TestTranslocoModule, NoopAnimationsModule], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}) -class DialogTestModule {} - class TestEnvironment { readonly fixture: ComponentFixture; readonly component: QuestionDialogComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.component.ts index a76f48670f6..7ed6577bdcc 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.component.ts @@ -1,6 +1,20 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component, DestroyRef, Inject, OnInit, ViewChild } from '@angular/core'; -import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; +import { AbstractControl, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogConfig, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatError, MatFormField, MatLabel, MatSuffix } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatInput } from '@angular/material/input'; +import { TranslocoModule } from '@ngneat/transloco'; import { VerseRef } from '@sillsdev/scripture'; import { cloneDeep } from 'lodash-es'; import { Question } from 'realtime-server/lib/esm/scriptureforge/models/question'; @@ -18,7 +32,9 @@ import { } from '../../scripture-chooser-dialog/scripture-chooser-dialog.component'; import { ParentAndStartErrorStateMatcher, SFValidators } from '../../shared/sfvalidators'; import { combineVerseRefStrs } from '../../shared/utils'; +import { AttachAudioComponent } from '../attach-audio/attach-audio.component'; import { AudioAttachment } from '../checking/checking-audio-player/checking-audio-player.component'; +import { CheckingTextComponent } from '../checking/checking-text/checking-text.component'; import { TextAndAudioComponent } from '../text-and-audio/text-and-audio.component'; export interface QuestionDialogData { questionDoc?: QuestionDoc; @@ -38,7 +54,27 @@ export interface QuestionDialogResult { @Component({ templateUrl: './question-dialog.component.html', styleUrls: ['./question-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + MatIcon, + CdkScrollable, + MatDialogContent, + FormsModule, + ReactiveFormsModule, + MatFormField, + MatLabel, + MatInput, + MatIconButton, + MatSuffix, + MatError, + CheckingTextComponent, + TextAndAudioComponent, + AttachAudioComponent, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class QuestionDialogComponent implements OnInit { @ViewChild(TextAndAudioComponent) textAndAudio?: TextAndAudioComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.service.spec.ts index 2baef174b86..5227764ee0c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/question-dialog/question-dialog.service.spec.ts @@ -17,9 +17,9 @@ import { DialogService } from 'xforge-common/dialog.service'; import { FileService } from 'xforge-common/file.service'; import { FileType } from 'xforge-common/models/file-offline-data'; import { NoticeService } from 'xforge-common/notice.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { QuestionDoc } from '../../core/models/question-doc'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; @@ -39,8 +39,9 @@ const mockedFileService = mock(FileService); describe('QuestionDialogService', () => { configureTestingModule(() => ({ - imports: [TestTranslocoModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [getTestTranslocoModule(false)], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), { provide: FileService, useMock: mockedFileService }, { provide: DialogService, useMock: mockedDialogService }, { provide: SFProjectService, useMock: mockedProjectService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/text-and-audio/text-and-audio.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/text-and-audio/text-and-audio.component.ts index 9389e01005f..f8c71dca9c4 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/checking/text-and-audio/text-and-audio.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/checking/text-and-audio/text-and-audio.component.ts @@ -1,12 +1,22 @@ +import { NgClass } from '@angular/common'; import { AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { AbstractControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { + AbstractControl, + FormsModule, + ReactiveFormsModule, + UntypedFormControl, + UntypedFormGroup +} from '@angular/forms'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; +import { TranslocoModule } from '@ngneat/transloco'; import { AudioAttachment } from '../checking/checking-audio-player/checking-audio-player.component'; @Component({ selector: 'app-text-and-audio', templateUrl: './text-and-audio.component.html', styleUrls: ['./text-and-audio.component.scss'], - standalone: false + imports: [TranslocoModule, FormsModule, ReactiveFormsModule, MatFormField, MatLabel, MatInput, NgClass] }) export class TextAndAudioComponent implements AfterViewInit, OnInit, OnDestroy { @Input() input?: { text?: string; audioUrl?: string }; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/connect-project/connect-project.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/connect-project/connect-project.component.spec.ts index f8fea478f22..89f9e11ea60 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/connect-project/connect-project.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/connect-project/connect-project.component.spec.ts @@ -2,7 +2,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { DebugElement, ErrorHandler } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { Router } from '@angular/router'; import { SFProject } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; @@ -12,12 +12,11 @@ import { AuthService } from 'xforge-common/auth.service'; import { CommandError, CommandErrorCode } from 'xforge-common/command.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { ParatextProject } from '../core/models/paratext-project'; import { SFProjectCreateSettings } from '../core/models/sf-project-create-settings'; import { SFProjectDoc } from '../core/models/sf-project-doc'; @@ -44,15 +43,10 @@ const mockedErrorHandler = mock(ErrorHandler); describe('ConnectProjectComponent', () => { configureTestingModule(() => ({ - imports: [ - NoopAnimationsModule, - UICommonModule, - TestTranslocoModule, - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) - ], - declarations: [ConnectProjectComponent, ProjectSelectComponent, SyncProgressComponent], + imports: [ConnectProjectComponent, ProjectSelectComponent, SyncProgressComponent, getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: AuthService, useMock: mockedAuthService }, { provide: ParatextService, useMock: mockedParatextService }, { provide: ProjectNotificationService, useMock: mockedProjectNotificationService }, @@ -60,7 +54,8 @@ describe('ConnectProjectComponent', () => { { provide: SFProjectService, useMock: mockedSFProjectService }, { provide: NoticeService, useMock: mockedNoticeService }, { provide: ErrorHandler, useMock: mockedErrorHandler }, - { provide: OnlineStatusService, useClass: TestOnlineStatusService } + { provide: OnlineStatusService, useClass: TestOnlineStatusService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/connect-project/connect-project.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/connect-project/connect-project.component.ts index 4d1f78d5030..882b6d71635 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/connect-project/connect-project.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/connect-project/connect-project.component.ts @@ -1,8 +1,13 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Component, DestroyRef, ErrorHandler, OnInit } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButton } from '@angular/material/button'; +import { MatCard, MatCardContent, MatCardSubtitle, MatCardTitle } from '@angular/material/card'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { MatDivider } from '@angular/material/divider'; +import { MatError } from '@angular/material/form-field'; import { Router } from '@angular/router'; -import { TranslocoService } from '@ngneat/transloco'; +import { TranslocoModule, TranslocoService } from '@ngneat/transloco'; import { AuthService } from 'xforge-common/auth.service'; import { DataLoadingComponent } from 'xforge-common/data-loading-component'; import { I18nService } from 'xforge-common/i18n.service'; @@ -15,7 +20,9 @@ import { SFProjectCreateSettings } from '../core/models/sf-project-create-settin import { SFProjectDoc } from '../core/models/sf-project-doc'; import { ParatextService, SelectableProject } from '../core/paratext.service'; import { SFProjectService } from '../core/sf-project.service'; +import { ProjectSelectComponent } from '../project-select/project-select.component'; import { compareProjectsForSorting, projectLabel } from '../shared/utils'; +import { SyncProgressComponent } from '../sync/sync-progress/sync-progress.component'; interface ConnectProjectFormValues { settings: { checking: boolean; @@ -27,7 +34,21 @@ interface ConnectProjectFormValues { selector: 'app-connect-project', templateUrl: './connect-project.component.html', styleUrls: ['./connect-project.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatCard, + MatCardContent, + SyncProgressComponent, + FormsModule, + ReactiveFormsModule, + MatCardTitle, + MatCardSubtitle, + ProjectSelectComponent, + MatError, + MatDivider, + MatCheckbox, + MatButton + ] }) export class ConnectProjectComponent extends DataLoadingComponent implements OnInit { static readonly errorAlreadyConnectedKey: string = 'error-already-connected'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/core/core.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/core/core.module.ts deleted file mode 100644 index 32e4667f793..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/core/core.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { ProjectService } from 'xforge-common/project.service'; -import { TypeRegistry } from 'xforge-common/type-registry'; -import { SF_TYPE_REGISTRY } from './models/sf-type-registry'; -import { SFProjectService } from './sf-project.service'; - -@NgModule({ - imports: [CommonModule], - providers: [ - { provide: ProjectService, useExisting: SFProjectService }, - { provide: TypeRegistry, useValue: SF_TYPE_REGISTRY } - ] -}) -export class CoreModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/core/models/note-thread-doc.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/core/models/note-thread-doc.spec.ts index 88f2c96f5b2..4d8c9d08dff 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/core/models/note-thread-doc.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/core/models/note-thread-doc.spec.ts @@ -10,7 +10,7 @@ import { NoteType } from 'realtime-server/lib/esm/scriptureforge/models/note-thread'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { NoteThreadDoc, NoteThreadIcon } from './note-thread-doc'; @@ -18,7 +18,7 @@ import { SF_TYPE_REGISTRY } from './sf-type-registry'; describe('NoteThreadDoc', () => { configureTestingModule(() => ({ - imports: [TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)] + providers: [provideTestRealtime(SF_TYPE_REGISTRY)] })); let env: TestEnvironment; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/core/permissions.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/core/permissions.service.spec.ts index c0d76fe05a7..db42efff559 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/core/permissions.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/core/permissions.service.spec.ts @@ -9,7 +9,7 @@ import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/models/text-info-permission'; import { anything, instance, mock, verify, when } from 'ts-mockito'; import { UserDoc } from 'xforge-common/models/user-doc'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; @@ -25,8 +25,8 @@ const mockedProjectService = mock(SFProjectService); const mockedProjectDoc = mock(SFProjectProfileDoc); describe('PermissionsService', () => { configureTestingModule(() => ({ - imports: [TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), { provide: UserService, useMock: mockedUserService }, { provide: SFProjectService, useMock: mockedProjectService } ] diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/core/text-doc.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/core/text-doc.service.spec.ts index 89fd8dbb415..72b9819a4ff 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/core/text-doc.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/core/text-doc.service.spec.ts @@ -7,7 +7,7 @@ import { Chapter, TextInfo } from 'realtime-server/lib/esm/scriptureforge/models import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/models/text-info-permission'; import * as RichText from 'rich-text'; import { mock, when } from 'ts-mockito'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; @@ -22,8 +22,8 @@ const mockUserService = mock(UserService); describe('TextDocService', () => { configureTestingModule(() => ({ - imports: [TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), { provide: SFProjectService, useMock: mockProjectService }, { provide: UserService, useMock: mockUserService } ] diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.html index e5b661d5a12..80c3efedb1f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.html @@ -1,5 +1,5 @@ - +

{{ t("technical_details") }}

@@ -24,5 +24,5 @@

{{ t("exception") }}

- +
diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.spec.ts index 5f70690c18a..6cf0c2bde9a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.spec.ts @@ -1,14 +1,14 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { NgModule } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { EventMetricDialogComponent } from './event-metric-dialog.component'; describe('EventMetricDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule] + imports: [getTestTranslocoModule(), EventMetricDialogComponent], + providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] })); let dialog: MatDialog; @@ -61,9 +61,3 @@ describe('EventMetricDialogComponent', () => { viewContainerFixture = TestBed.createComponent(ChildViewContainerComponent); }); }); - -@NgModule({ - imports: [TestTranslocoModule], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}) -class DialogTestModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.ts index e1f10097b2a..b9bcb5104b1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metric-dialog.component.ts @@ -1,9 +1,14 @@ -import { CommonModule } from '@angular/common'; import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { MatButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogTitle +} from '@angular/material/dialog'; import { TranslocoModule } from '@ngneat/transloco'; import { I18nService } from 'xforge-common/i18n.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { JsonViewerComponent } from '../shared/json-viewer/json-viewer.component'; import { EventMetric } from './event-metric'; @@ -11,7 +16,15 @@ import { EventMetric } from './event-metric'; selector: 'app-event-metric-dialog', templateUrl: './event-metric-dialog.component.html', styleUrls: ['./event-metric-dialog.component.scss'], - imports: [CommonModule, MatDialogModule, TranslocoModule, UICommonModule, JsonViewerComponent] + imports: [ + MatButton, + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatDialogClose, + TranslocoModule, + JsonViewerComponent + ] }) export class EventMetricDialogComponent { constructor( diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.spec.ts index 3b48aff8df2..78835758cde 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.spec.ts @@ -2,7 +2,7 @@ import { DebugElement, getDebugNode } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatDialogRef } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role'; import { BehaviorSubject } from 'rxjs'; import { anything, instance, mock, verify, when } from 'ts-mockito'; @@ -11,9 +11,9 @@ import { AuthService } from 'xforge-common/auth.service'; import { DialogService } from 'xforge-common/dialog.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { QueryResults } from 'xforge-common/query-parameters'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectService } from '../core/sf-project.service'; import { EventMetric, EventScope } from './event-metric'; @@ -28,14 +28,16 @@ const mockedUserService = mock(UserService); describe('EventMetricsLogComponent', () => { configureTestingModule(() => ({ - imports: [NoopAnimationsModule, TestOnlineStatusModule.forRoot(), TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), { provide: AuthService, useMock: mockedAuthService }, { provide: ActivatedProjectService, useMock: mockedActivatedProjectService }, { provide: DialogService, useMock: mockDialogService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: SFProjectService, useMock: mockedProjectService }, - { provide: UserService, useMock: mockedUserService } + { provide: UserService, useMock: mockedUserService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.ts index 9cbd18eb5bf..7307725cdf3 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics-log.component.ts @@ -1,5 +1,20 @@ import { Component, DestroyRef, OnInit } from '@angular/core'; +import { MatButton } from '@angular/material/button'; import { MatDialogConfig } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatPaginator } from '@angular/material/paginator'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + MatTable +} from '@angular/material/table'; import { TranslocoModule } from '@ngneat/transloco'; import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role'; import { BehaviorSubject, combineLatest, switchMap } from 'rxjs'; @@ -11,7 +26,6 @@ import { I18nService } from 'xforge-common/i18n.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { OwnerComponent } from 'xforge-common/owner/owner.component'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { filterNullish, quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { SFProjectService } from '../core/sf-project.service'; import { EventMetric } from './event-metric'; @@ -29,7 +43,23 @@ interface Row { selector: 'app-event-metrics-log', templateUrl: './event-metrics-log.component.html', styleUrls: ['./event-metrics-log.component.scss'], - imports: [OwnerComponent, TranslocoModule, UICommonModule] + imports: [ + OwnerComponent, + TranslocoModule, + MatButton, + MatIcon, + MatTable, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatCell, + MatCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + MatPaginator + ] }) export class EventMetricsLogComponent extends DataLoadingComponent implements OnInit { columnsToDisplay: string[] = ['successful', 'scope', 'eventType', 'author']; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics.component.spec.ts index 6c55aec8499..6b587ba2815 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/event-metrics/event-metrics.component.spec.ts @@ -1,10 +1,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { EventMetricsComponent } from './event-metrics.component'; describe('EventMetricsComponent', () => { configureTestingModule(() => ({ - imports: [TestTranslocoModule] + imports: [getTestTranslocoModule()] })); it('should be created', () => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.component.spec.ts index 0530c5d7b40..0240e965c3e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.component.spec.ts @@ -1,7 +1,7 @@ import { DebugElement, ErrorHandler } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { ActivatedRoute, Router } from '@angular/router'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; import { of } from 'rxjs'; @@ -14,12 +14,11 @@ import { ErrorReportingService } from 'xforge-common/error-reporting.service'; import { I18nService } from 'xforge-common/i18n.service'; import { LocationService } from 'xforge-common/location.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SF_TYPE_REGISTRY } from '../core/models/sf-type-registry'; import { SFProjectService } from '../core/sf-project.service'; import { NoticeComponent } from '../shared/notice/notice.component'; @@ -38,16 +37,10 @@ const mockedErrorHandler = mock(ErrorHandler); describe('JoinComponent', () => { configureTestingModule(() => ({ - declarations: [JoinComponent], - imports: [ - NoopAnimationsModule, - TestTranslocoModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - TestOnlineStatusModule.forRoot(), - UICommonModule, - NoticeComponent - ], + imports: [JoinComponent, getTestTranslocoModule(), NoticeComponent], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), + provideTestOnlineStatus(), { provide: ActivatedRoute, useMock: mockedActivatedRoute }, { provide: AnonymousService, useMock: mockedAnonymousService }, { provide: AuthService, useMock: mockedAuthService }, @@ -58,7 +51,8 @@ describe('JoinComponent', () => { { provide: Router, useMock: mockedRouter }, { provide: ErrorReportingService, useMock: mockErrorReportingService }, { provide: SFProjectService, useMock: mockedSFProjectService }, - { provide: ErrorHandler, useMock: mockedErrorHandler } + { provide: ErrorHandler, useMock: mockedErrorHandler }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.component.ts index 56583838661..5996135d5ff 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.component.ts @@ -1,7 +1,12 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Component, DestroyRef, ErrorHandler } from '@angular/core'; -import { FormControl, Validators } from '@angular/forms'; +import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatButton } from '@angular/material/button'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { ActivatedRoute, Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { combineLatest } from 'rxjs'; import { distinctUntilChanged, filter, map } from 'rxjs/operators'; import { AnonymousService } from 'xforge-common/anonymous.service'; @@ -18,6 +23,7 @@ import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { XFValidators } from 'xforge-common/xfvalidators'; import { ObjectPaths } from '../../type-utils'; import { SFProjectService } from '../core/sf-project.service'; +import { NoticeComponent } from '../shared/notice/notice.component'; export interface AnonymousShareKeyDetails { projectName: string; role: string; @@ -39,7 +45,17 @@ export const KNOWN_ERROR_CODES: ObjectPaths[] = [ selector: 'app-join', templateUrl: './join.component.html', styleUrls: ['./join.component.scss'], - standalone: false + imports: [ + TranslocoModule, + NoticeComponent, + FormsModule, + MatFormField, + MatLabel, + MatInput, + ReactiveFormsModule, + MatButton, + MatProgressSpinner + ] }) export class JoinComponent extends DataLoadingComponent { name: FormControl = new FormControl(''); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.stories.ts index f9c8d410fbb..7cb0baba91e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/join/join.stories.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { HttpErrorResponse } from '@angular/common/http'; import { ActivatedRoute, Router } from '@angular/router'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; @@ -10,11 +9,9 @@ import { AuthService } from 'xforge-common/auth.service'; import { CommandError, CommandErrorCode } from 'xforge-common/command.service'; import { DialogService } from 'xforge-common/dialog.service'; import { GenericDialogComponent } from 'xforge-common/generic-dialog/generic-dialog.component'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { LocationService } from 'xforge-common/location.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { SFProjectService } from '../core/sf-project.service'; import { NoticeComponent } from '../shared/notice/notice.component'; import { JoinComponent } from './join.component'; @@ -70,8 +67,7 @@ const meta: Meta = { }, decorators: [ moduleMetadata({ - imports: [UICommonModule, CommonModule, I18nStoryModule, NoticeComponent], - declarations: [GenericDialogComponent], + imports: [NoticeComponent, GenericDialogComponent], providers: [ { provide: ActivatedRoute, useValue: instance(mockedActivatedRoute) }, { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/machine-api/remote-translation-engine.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/machine-api/remote-translation-engine.spec.ts index ecca87c3f90..c473161c659 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/machine-api/remote-translation-engine.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/machine-api/remote-translation-engine.spec.ts @@ -7,7 +7,7 @@ import { of, throwError } from 'rxjs'; import { anything, instance, mock, when } from 'ts-mockito'; import { I18nService } from 'xforge-common/i18n.service'; import { NoticeService } from 'xforge-common/notice.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { BuildDto } from './build-dto'; import { BuildStates } from './build-states'; import { EngineDto } from './engine-dto'; @@ -20,7 +20,7 @@ import { WordGraphDto } from './word-graph-dto'; describe('RemoteTranslationEngine', () => { configureTestingModule(() => ({ - imports: [TestTranslocoModule] + imports: [getTestTranslocoModule()] })); it('get word graph', async () => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.component.spec.ts index d8577cee90a..670edc0e91d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.component.spec.ts @@ -3,7 +3,7 @@ import { Component, DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { provideAnimations } from '@angular/platform-browser/animations'; -import { Router, RouterModule } from '@angular/router'; +import { provideRouter, Router } from '@angular/router'; import { User } from 'realtime-server/lib/esm/common/models/user'; import { createTestUser } from 'realtime-server/lib/esm/common/models/user-test-data'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; @@ -13,10 +13,9 @@ import { anything, mock, verify, when } from 'ts-mockito'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFUserProjectsService } from 'xforge-common/user-projects.service'; import { UserService } from 'xforge-common/user.service'; import { ParatextProject } from '../core/models/paratext-project'; @@ -24,11 +23,10 @@ import { SFProjectProfileDoc } from '../core/models/sf-project-profile-doc'; import { SFProjectUserConfigDoc } from '../core/models/sf-project-user-config-doc'; import { ParatextService } from '../core/paratext.service'; import { SFProjectService } from '../core/sf-project.service'; -import { SharedModule } from '../shared/shared.module'; +import { provideQuillRegistrations } from '../shared/text/quill-editor-registration/quill-providers'; import { MyProjectsComponent } from './my-projects.component'; @Component({ - template: '', - standalone: false + template: '' }) class EmptyComponent {} @@ -40,18 +38,14 @@ const mockedNoticeService = mock(NoticeService); describe('MyProjectsComponent', () => { configureTestingModule(() => ({ - declarations: [MyProjectsComponent], - imports: [ - UICommonModule, - SharedModule.forRoot(), - RouterModule.forRoot([ + imports: [MyProjectsComponent, getTestTranslocoModule()], + providers: [ + provideRouter([ { path: 'projects/:projectId', component: EmptyComponent }, { path: 'connect-project', component: EmptyComponent } ]), - TestOnlineStatusModule.forRoot(), - TestTranslocoModule - ], - providers: [ + provideQuillRegistrations(), + provideTestOnlineStatus(), provideAnimations(), { provide: SFProjectService, useMock: mockedSFProjectService }, { provide: UserService, useMock: mockedUserService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.component.ts index 657abd6b96c..11930eac878 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.component.ts @@ -1,6 +1,13 @@ +import { AsyncPipe } from '@angular/common'; import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http'; import { Component, DestroyRef, OnInit } from '@angular/core'; +import { MatAnchor, MatButton } from '@angular/material/button'; +import { MatCard } from '@angular/material/card'; +import { MatRipple } from '@angular/material/core'; +import { MatExpansionPanel, MatExpansionPanelHeader } from '@angular/material/expansion'; +import { MatIcon } from '@angular/material/icon'; import { Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { isPTUser } from 'realtime-server/lib/esm/common/models/user'; import { isResource } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { Observable } from 'rxjs'; @@ -8,6 +15,7 @@ import { en, I18nService } from 'xforge-common/i18n.service'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; import { SFUserProjectsService } from 'xforge-common/user-projects.service'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; @@ -19,12 +27,25 @@ import { SFProjectProfileDoc } from '../core/models/sf-project-profile-doc'; import { ParatextService } from '../core/paratext.service'; import { PermissionsService } from '../core/permissions.service'; import { SFProjectService } from '../core/sf-project.service'; +import { NoticeComponent } from '../shared/notice/notice.component'; /** Presents user with list of available projects to open or connect to. */ @Component({ selector: 'app-my-projects', templateUrl: './my-projects.component.html', styleUrls: ['./my-projects.component.scss'], - standalone: false + imports: [ + TranslocoModule, + NoticeComponent, + MatCard, + MatButton, + MatIcon, + MatRipple, + RouterLinkDirective, + MatExpansionPanel, + MatExpansionPanelHeader, + MatAnchor, + AsyncPipe + ] }) export class MyProjectsComponent implements OnInit { /** PT projects that the user can access. */ diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.stories.ts index 53fd587d4d4..ea0c50c00d2 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/my-projects/my-projects.stories.ts @@ -1,7 +1,6 @@ import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { Component } from '@angular/core'; import { provideAnimations } from '@angular/platform-browser/animations'; -import { ActivatedRoute, RouterModule } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { User } from 'realtime-server/lib/esm/common/models/user'; import { createTestUser } from 'realtime-server/lib/esm/common/models/user-test-data'; @@ -12,9 +11,7 @@ import { anything, instance, mock, objectContaining, when } from 'ts-mockito'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; -import { TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFUserProjectsService } from 'xforge-common/user-projects.service'; import { UserService } from 'xforge-common/user.service'; import { ParatextProject } from '../core/models/paratext-project'; @@ -22,12 +19,8 @@ import { SFProjectProfileDoc } from '../core/models/sf-project-profile-doc'; import { ParatextService } from '../core/paratext.service'; import { PermissionsService } from '../core/permissions.service'; import { SFProjectService } from '../core/sf-project.service'; -import { SharedModule } from '../shared/shared.module'; import { MyProjectsComponent } from './my-projects.component'; -@Component({ template: '' }) -class EmptyComponent {} - const mockedActivatedRoute = mock(ActivatedRoute); const mockedUserService = mock(UserService); const mockedSFProjectService = mock(SFProjectService); @@ -190,17 +183,7 @@ const meta: Meta = { }, decorators: [ moduleMetadata({ - imports: [ - UICommonModule, - SharedModule.forRoot(), - RouterModule.forChild([ - { path: 'projects/:projectId', component: EmptyComponent }, - { path: 'connect-project', component: EmptyComponent } - ]), - TestOnlineStatusModule.forRoot(), - TestTranslocoModule - ], - declarations: [MyProjectsComponent], + imports: [getTestTranslocoModule(), MyProjectsComponent], providers: [ provideAnimations(), provideHttpClientTesting(), diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/navigation/navigation.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/navigation/navigation.component.ts index e163f03eef1..375df66ab9f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/navigation/navigation.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/navigation/navigation.component.ts @@ -1,5 +1,10 @@ +import { AsyncPipe } from '@angular/common'; import { Component, EventEmitter, Output } from '@angular/core'; +import { MatBadge } from '@angular/material/badge'; +import { MatIcon } from '@angular/material/icon'; +import { MatListItem, MatNavList } from '@angular/material/list'; import { Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; @@ -9,6 +14,7 @@ import { ActivatedProjectService } from 'xforge-common/activated-project.service import { FeatureFlagService } from 'xforge-common/feature-flags/feature-flag.service'; import { I18nService } from 'xforge-common/i18n.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; import { UserService } from 'xforge-common/user.service'; import { ResumeCheckingService } from '../checking/checking/resume-checking.service'; import { ResumeTranslateService } from '../checking/checking/resume-translate.service'; @@ -20,7 +26,7 @@ import { NmtDraftAuthGuard, SettingsAuthGuard, SyncAuthGuard, UsersAuthGuard } f selector: 'app-navigation', templateUrl: './navigation.component.html', styleUrls: ['./navigation.component.scss'], - standalone: false + imports: [TranslocoModule, MatNavList, MatListItem, RouterLinkDirective, MatIcon, MatBadge, AsyncPipe] }) export class NavigationComponent { canSeeSettings$: Observable = this.activatedProjectService.projectId$.pipe( diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/navigation/navigation.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/navigation/navigation.stories.ts index 946c9c98f61..609f7449c32 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/navigation/navigation.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/navigation/navigation.stories.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { SwUpdate } from '@angular/service-worker'; @@ -13,11 +12,10 @@ import { ActivatedProjectService, TestActivatedProjectService } from 'xforge-com import { AuthGuard } from 'xforge-common/auth.guard'; import { AuthService } from 'xforge-common/auth.service'; import { createTestFeatureFlag, FeatureFlagService } from 'xforge-common/feature-flags/feature-flag.service'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; +import { provideI18nStory } from 'xforge-common/i18n-story'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { UserService } from 'xforge-common/user.service'; import { ResumeCheckingService } from '../checking/checking/resume-checking.service'; import { ResumeTranslateService } from '../checking/checking/resume-translate.service'; @@ -66,8 +64,11 @@ function setUpMocks(args: StoryState): void { TestBed.resetTestingModule(); TestBed.configureTestingModule({ - imports: [I18nStoryModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], - providers: [{ provide: UserService, useValue: instance(mockedUserService) }] + providers: [ + provideI18nStory(), + provideTestRealtime(SF_TYPE_REGISTRY), + { provide: UserService, useValue: instance(mockedUserService) } + ] }); const realtimeService: TestRealtimeService = TestBed.inject(TestRealtimeService); @@ -107,7 +108,6 @@ const meta: Meta = { setUpMocks(args as StoryState); return { moduleMetadata: { - imports: [UICommonModule, CommonModule, I18nStoryModule], providers: [ { provide: AuthService, useValue: instance(mockedAuthService) }, { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/permissions-viewer/permissions-viewer.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/permissions-viewer/permissions-viewer.component.ts index 54df9eea013..640da4524a1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/permissions-viewer/permissions-viewer.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/permissions-viewer/permissions-viewer.component.ts @@ -13,8 +13,7 @@ const permissions = rightsByRole; @Component({ selector: 'app-permissions-viewer', templateUrl: './permissions-viewer.component.html', - styleUrls: ['./permissions-viewer.component.scss'], - standalone: false + styleUrls: ['./permissions-viewer.component.scss'] }) export class PermissionsViewerComponent implements OnInit { // All available roles diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.component.spec.ts index d1554c6c312..d96ddb17676 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.component.spec.ts @@ -1,9 +1,8 @@ import { Component, ViewChild } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { getTestTranslocoModule } from 'xforge-common/test-utils'; import { isSafari } from 'xforge-common/utils'; import { SelectableProject } from '../core/paratext.service'; import { CustomValidatorState, SFValidators } from '../shared/sfvalidators'; @@ -202,7 +201,7 @@ describe('ProjectSelectComponent', () => { [isDisabled]="isDisabled" > `, - standalone: false + imports: [ReactiveFormsModule, ProjectSelectComponent] }) class HostComponent { readonly sourceParatextId = new UntypedFormControl(undefined); @@ -235,8 +234,8 @@ class TestEnvironment { nonSelectableProjects?: SelectableProject[] ) { TestBed.configureTestingModule({ - declarations: [HostComponent, ProjectSelectComponent], - imports: [UICommonModule, TestTranslocoModule, NoopAnimationsModule] + imports: [ReactiveFormsModule, getTestTranslocoModule(), HostComponent], + providers: [provideNoopAnimations()] }); this.fixture = TestBed.createComponent(HostComponent); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.component.ts index a391585e046..710b65a3dc5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.component.ts @@ -1,8 +1,18 @@ +import { AsyncPipe } from '@angular/common'; import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnDestroy, Output, ViewChild } from '@angular/core'; -import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ValidatorFn } from '@angular/forms'; -import { MatAutocomplete, MatAutocompleteTrigger } from '@angular/material/autocomplete'; +import { + ControlValueAccessor, + FormControl, + FormsModule, + NG_VALUE_ACCESSOR, + ReactiveFormsModule, + ValidatorFn +} from '@angular/forms'; +import { MatAutocomplete, MatAutocompleteTrigger, MatOptgroup, MatOption } from '@angular/material/autocomplete'; import { ShowOnDirtyErrorStateMatcher } from '@angular/material/core'; -import { translate } from '@ngneat/transloco'; +import { MatError, MatFormField } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; +import { translate, TranslocoModule } from '@ngneat/transloco'; import { BehaviorSubject, combineLatest, fromEvent, Observable } from 'rxjs'; import { distinctUntilChanged, map, shareReplay, startWith, takeUntil, tap } from 'rxjs/operators'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; @@ -10,6 +20,7 @@ import { hasPropWithValue } from '../../type-utils'; import { SelectableProject } from '../core/paratext.service'; import { SFValidators } from '../shared/sfvalidators'; import { projectLabel } from '../shared/utils'; + // A value accessor is necessary in order to create a custom form control export const PROJECT_SELECT_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, @@ -23,7 +34,19 @@ export const PROJECT_SELECT_VALUE_ACCESSOR: any = { templateUrl: 'project-select.component.html', styleUrls: ['project-select.component.scss'], providers: [PROJECT_SELECT_VALUE_ACCESSOR], - standalone: false + imports: [ + TranslocoModule, + MatFormField, + MatInput, + FormsModule, + MatAutocompleteTrigger, + ReactiveFormsModule, + MatError, + MatAutocomplete, + MatOptgroup, + MatOption, + AsyncPipe + ] }) export class ProjectSelectComponent implements ControlValueAccessor, OnDestroy { @Output() valueChange: EventEmitter = new EventEmitter(true); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.stories.ts index 101d4e99284..6050fbf3ca0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/project-select/project-select.stories.ts @@ -1,21 +1,13 @@ -import { TranslocoModule } from '@ngneat/transloco'; -import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { Meta, StoryObj } from '@storybook/angular'; import { expect, within } from '@storybook/test'; import userEvent from '@testing-library/user-event'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { SelectableProjectWithLanguageCode } from '../core/paratext.service'; import { projectLabel } from '../shared/utils'; import { ProjectSelectComponent } from './project-select.component'; const meta: Meta = { title: 'Utility/ProjectSelect', - component: ProjectSelectComponent, - decorators: [ - moduleMetadata({ - imports: [I18nStoryModule, TranslocoModule, UICommonModule] - }) - ] + component: ProjectSelectComponent }; export default meta; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/project/project.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/project/project.component.spec.ts index 2deb03407cd..037ecaa99fd 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/project/project.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/project/project.component.spec.ts @@ -17,7 +17,7 @@ import { of } from 'rxjs'; import { anything, deepEqual, mock, verify, when } from 'ts-mockito'; import { DialogService } from 'xforge-common/dialog.service'; import { UserDoc } from 'xforge-common/models/user-doc'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; @@ -36,8 +36,8 @@ const mockedDialogService = mock(DialogService); describe('ProjectComponent', () => { configureTestingModule(() => ({ - imports: [TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), { provide: UserService, useMock: mockedUserService }, { provide: ActivatedRoute, useMock: mockedActivatedRoute }, { provide: Router, useMock: mockedRouter }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/project/project.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/project/project.component.ts index 73a3f780d97..ce14463708f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/project/project.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/project/project.component.ts @@ -18,8 +18,7 @@ type TaskType = 'translate' | 'checking'; @Component({ selector: 'app-projects', templateUrl: './project.component.html', - styleUrls: ['./project.component.scss'], - standalone: false + styleUrls: ['./project.component.scss'] }) export class ProjectComponent extends DataLoadingComponent implements OnInit { constructor( diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/scripture-chooser-dialog/scripture-chooser-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/scripture-chooser-dialog/scripture-chooser-dialog.component.spec.ts index 1ba653028f3..3005f4cc894 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/scripture-chooser-dialog/scripture-chooser-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/scripture-chooser-dialog/scripture-chooser-dialog.component.spec.ts @@ -1,20 +1,20 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { DebugElement, NgModule } from '@angular/core'; +import { DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { Canon, VerseRef } from '@sillsdev/scripture'; import { TextInfo } from 'realtime-server/lib/esm/scriptureforge/models/text-info'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { TextsByBookId } from '../core/models/texts-by-book-id'; import { ScriptureChooserDialogComponent, ScriptureChooserDialogData } from './scripture-chooser-dialog.component'; describe('ScriptureChooserDialog', () => { configureTestingModule(() => ({ - imports: [TestModule] + imports: [getTestTranslocoModule(), ScriptureChooserDialogComponent], + providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting(), provideNoopAnimations()] })); let env: TestEnvironment; @@ -397,13 +397,6 @@ describe('ScriptureChooserDialog', () => { expect(env.component.selection.chapter).toBeUndefined(); })); - @NgModule({ - declarations: [ScriptureChooserDialogComponent], - imports: [UICommonModule, TestTranslocoModule, NoopAnimationsModule], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] - }) - class TestModule {} - class TestEnvironment { fixture: ComponentFixture; component: ScriptureChooserDialogComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/scripture-chooser-dialog/scripture-chooser-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/scripture-chooser-dialog/scripture-chooser-dialog.component.ts index 0cf07e3319c..eb7b5b33cb5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/scripture-chooser-dialog/scripture-chooser-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/scripture-chooser-dialog/scripture-chooser-dialog.component.ts @@ -1,5 +1,9 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { MAT_DIALOG_DATA, MatDialogContent, MatDialogRef, MatDialogTitle } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon, VerseRef } from '@sillsdev/scripture'; import { I18nService } from 'xforge-common/i18n.service'; import { TextsByBookId } from '../core/models/texts-by-book-id'; @@ -29,7 +33,7 @@ export interface ScriptureChooserDialogData { selector: 'app-scripture-reference-chooser', templateUrl: './scripture-chooser-dialog.component.html', styleUrls: ['./scripture-chooser-dialog.component.scss'], - standalone: false + imports: [TranslocoModule, MatDialogTitle, MatIconButton, MatIcon, CdkScrollable, MatDialogContent, MatButton] }) export class ScriptureChooserDialogComponent implements OnInit { showing: 'books' | 'chapters' | 'verses' | 'rangeEnd' = 'books'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/draft-jobs.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/draft-jobs.component.ts index 513c0985376..0010f5dff93 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/draft-jobs.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/draft-jobs.component.ts @@ -1,5 +1,23 @@ import { Component, DestroyRef, OnInit } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatOption } from '@angular/material/core'; import { MatDialogConfig } from '@angular/material/dialog'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatSelect } from '@angular/material/select'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + MatTable +} from '@angular/material/table'; +import { MatTooltip } from '@angular/material/tooltip'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role'; import { BehaviorSubject, combineLatest, map, Observable, switchMap } from 'rxjs'; @@ -10,7 +28,6 @@ import { I18nService } from 'xforge-common/i18n.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { OwnerComponent } from 'xforge-common/owner/owner.component'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { SFProjectService } from '../core/sf-project.service'; import { EventMetric } from '../event-metrics/event-metric'; @@ -74,7 +91,28 @@ const DRAFTING_EVENTS = [ selector: 'app-draft-jobs', templateUrl: './draft-jobs.component.html', styleUrls: ['./draft-jobs.component.scss'], - imports: [OwnerComponent, UICommonModule, RouterLink, NoticeComponent] + imports: [ + OwnerComponent, + MatTooltip, + MatIconButton, + MatFormField, + MatLabel, + MatSelect, + MatOption, + MatIcon, + MatTable, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatCell, + MatCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + RouterLink, + NoticeComponent + ] }) export class DraftJobsComponent extends DataLoadingComponent implements OnInit { columnsToDisplay: string[] = [ diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/job-details-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/job-details-dialog.component.ts index a32f69469eb..89d5edc7153 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/job-details-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/job-details-dialog.component.ts @@ -1,11 +1,16 @@ -import { CommonModule } from '@angular/common'; import { Component, Inject, OnInit } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; -import { MatIconModule } from '@angular/material/icon'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatTabsModule } from '@angular/material/tabs'; -import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { MatTab, MatTabGroup } from '@angular/material/tabs'; +import { MatTooltip } from '@angular/material/tooltip'; import { I18nService } from 'xforge-common/i18n.service'; import { L10nNumberPipe } from 'xforge-common/l10n-number.pipe'; import { EventMetric } from '../event-metrics/event-metric'; @@ -41,19 +46,21 @@ const EVENT_TYPE_LABELS: { */ @Component({ selector: 'app-job-details-dialog', - standalone: true, templateUrl: './job-details-dialog.component.html', styleUrls: ['./job-details-dialog.component.scss'], imports: [ - CommonModule, - MatDialogModule, - MatIconModule, - MatProgressSpinnerModule, - MatTabsModule, - MatTooltipModule, + MatButton, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogTitle, + MatIcon, + MatProgressSpinner, + MatTab, + MatTabGroup, + MatTooltip, JsonViewerComponent, NoticeComponent, - MatButtonModule, L10nNumberPipe ] }) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-administration.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-administration.component.spec.ts index 8d74b52d226..2bcf894bbf1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-administration.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-administration.component.spec.ts @@ -1,12 +1,12 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; import { mock, when } from 'ts-mockito'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SF_TYPE_REGISTRY } from '../core/models/sf-type-registry'; import { ServalAdministrationComponent } from './serval-administration.component'; @@ -15,11 +15,13 @@ when(mockedActivatedRoute.queryParams).thenReturn(of({})); describe('ServalAdministrationComponent', () => { configureTestingModule(() => ({ - imports: [NoopAnimationsModule, TestTranslocoModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [getTestTranslocoModule()], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting(), - { provide: ActivatedRoute, useMock: mockedActivatedRoute } + { provide: ActivatedRoute, useMock: mockedActivatedRoute }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-administration.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-administration.component.ts index b6d30f26714..f6b4442e281 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-administration.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-administration.component.ts @@ -1,7 +1,6 @@ import { Component, OnInit } from '@angular/core'; -import { MatTabsModule } from '@angular/material/tabs'; +import { MatTab, MatTabContent, MatTabGroup } from '@angular/material/tabs'; import { ActivatedRoute, Router } from '@angular/router'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { MobileNotSupportedComponent } from '../shared/mobile-not-supported/mobile-not-supported.component'; import { DraftJobsComponent } from './draft-jobs.component'; import { ServalProjectsComponent } from './serval-projects.component'; @@ -14,7 +13,14 @@ import { ServalProjectsComponent } from './serval-projects.component'; selector: 'app-serval-administration', templateUrl: './serval-administration.component.html', styleUrls: ['./serval-administration.component.scss'], - imports: [ServalProjectsComponent, MobileNotSupportedComponent, DraftJobsComponent, MatTabsModule, UICommonModule] + imports: [ + ServalProjectsComponent, + MobileNotSupportedComponent, + DraftJobsComponent, + MatTabGroup, + MatTab, + MatTabContent + ] }) export class ServalAdministrationComponent implements OnInit { selectedTabIndex = 0; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-project.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-project.component.html index 59b81e3d395..9c2d925dfc4 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-project.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-project.component.html @@ -26,9 +26,9 @@

Pre-Translation Configuration

>
- +
diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/settings/delete-project-dialog/delete-project-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/settings/delete-project-dialog/delete-project-dialog.component.spec.ts index 75bc5ee12e4..13747e10607 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/settings/delete-project-dialog/delete-project-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/settings/delete-project-dialog/delete-project-dialog.component.spec.ts @@ -1,16 +1,15 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { NgModule } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { DeleteProjectDialogComponent } from './delete-project-dialog.component'; describe('DeleteProjectDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, NoopAnimationsModule] + imports: [getTestTranslocoModule(), DeleteProjectDialogComponent], + providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting(), provideNoopAnimations()] })); let dialog: MatDialog; @@ -101,10 +100,3 @@ describe('DeleteProjectDialogComponent', () => { viewContainerFixture = TestBed.createComponent(ChildViewContainerComponent); }); }); - -@NgModule({ - declarations: [DeleteProjectDialogComponent], - imports: [UICommonModule, TestTranslocoModule], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}) -class DialogTestModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/settings/delete-project-dialog/delete-project-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/settings/delete-project-dialog/delete-project-dialog.component.ts index f8302fa95f0..f9c0e5be21e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/settings/delete-project-dialog/delete-project-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/settings/delete-project-dialog/delete-project-dialog.component.ts @@ -1,12 +1,41 @@ import { Component, Inject } from '@angular/core'; -import { UntypedFormControl } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogConfig } from '@angular/material/dialog'; +import { UntypedFormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { + MAT_DIALOG_DATA, + MatDialogConfig, + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatDialogClose +} from '@angular/material/dialog'; import { I18nService } from 'xforge-common/i18n.service'; +import { TranslocoModule } from '@ngneat/transloco'; +import { Dir } from '@angular/cdk/bidi'; +import { MatIcon } from '@angular/material/icon'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; +import { MatButton } from '@angular/material/button'; @Component({ templateUrl: 'delete-project-dialog.component.html', styleUrls: ['delete-project-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + Dir, + MatDialogTitle, + MatIcon, + CdkScrollable, + MatDialogContent, + MatFormField, + MatLabel, + MatInput, + FormsModule, + ReactiveFormsModule, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class DeleteProjectDialogComponent { static defaultMatDialogConfig: MatDialogConfig = { autoFocus: true }; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/settings/settings.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/settings/settings.component.spec.ts index 8f71616e2c2..147a4a55390 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/settings/settings.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/settings/settings.component.spec.ts @@ -4,8 +4,8 @@ import { Component, DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ActivatedRoute, Route, RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { ActivatedRoute, provideRouter, Route } from '@angular/router'; import { cloneDeep, merge } from 'lodash-es'; import { TranslocoMarkupModule } from 'ngx-transloco-markup'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; @@ -24,12 +24,11 @@ import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { QueryParameters } from 'xforge-common/query-parameters'; import { noopDestroyRef } from 'xforge-common/realtime.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { WriteStatusComponent } from 'xforge-common/write-status/write-status.component'; import { SFProjectDoc } from '../core/models/sf-project-doc'; @@ -51,8 +50,7 @@ const mockedUserService = mock(UserService); const mockedDialog = mock(MatDialog); @Component({ - template: `
Mock
`, - standalone: false + template: `
Mock
` }) class MockComponent {} @@ -61,17 +59,17 @@ const ROUTES: Route[] = [{ path: 'projects', component: MockComponent }]; describe('SettingsComponent', () => { configureTestingModule(() => ({ imports: [ - RouterModule.forRoot(ROUTES), - UICommonModule, - TestTranslocoModule, + SettingsComponent, + getTestTranslocoModule(), TranslocoMarkupModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - TestOnlineStatusModule.forRoot(), - NoopAnimationsModule, - WriteStatusComponent + WriteStatusComponent, + ProjectSelectComponent, + InfoComponent ], - declarations: [SettingsComponent, ProjectSelectComponent, InfoComponent], providers: [ + provideRouter(ROUTES), + provideTestRealtime(SF_TYPE_REGISTRY), + provideTestOnlineStatus(), { provide: ActivatedRoute, useMock: mockedActivatedRoute }, { provide: AuthService, useMock: mockedAuthService }, { provide: NoticeService, useMock: mockedNoticeService }, @@ -79,7 +77,8 @@ describe('SettingsComponent', () => { { provide: SFProjectService, useMock: mockedSFProjectService }, { provide: UserService, useMock: mockedUserService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, - { provide: MatDialog, useMock: mockedDialog } + { provide: MatDialog, useMock: mockedDialog }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/settings/settings.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/settings/settings.component.ts index ab2787a9959..c308ae7c313 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/settings/settings.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/settings/settings.component.ts @@ -1,8 +1,16 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Component, DestroyRef, OnInit } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButton } from '@angular/material/button'; +import { MatCard, MatCardActions, MatCardContent, MatCardTitle } from '@angular/material/card'; +import { MatCheckbox } from '@angular/material/checkbox'; import { MatDialogConfig } from '@angular/material/dialog'; +import { MatError, MatHint } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatRadioButton, MatRadioGroup } from '@angular/material/radio'; import { ActivatedRoute, Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; +import { TranslocoMarkupComponent } from 'ngx-transloco-markup'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { CheckingAnswerExport } from 'realtime-server/lib/esm/scriptureforge/models/checking-config'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; @@ -20,13 +28,17 @@ import { ElementState } from 'xforge-common/models/element-state'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; +import { WriteStatusComponent } from 'xforge-common/write-status/write-status.component'; import { ParatextProject } from '../core/models/paratext-project'; import { SFProjectDoc } from '../core/models/sf-project-doc'; import { SFProjectSettings } from '../core/models/sf-project-settings'; import { ParatextService, SelectableProject } from '../core/paratext.service'; import { SFProjectService } from '../core/sf-project.service'; +import { ProjectSelectComponent } from '../project-select/project-select.component'; +import { InfoComponent } from '../shared/info/info.component'; import { DeleteProjectDialogComponent } from './delete-project-dialog/delete-project-dialog.component'; /** Allows user to configure high-level settings of how SF will use their Paratext project. */ @@ -34,7 +46,27 @@ import { DeleteProjectDialogComponent } from './delete-project-dialog/delete-pro selector: 'app-settings', templateUrl: './settings.component.html', styleUrls: ['./settings.component.scss'], - standalone: false + imports: [ + TranslocoModule, + FormsModule, + ReactiveFormsModule, + MatCard, + MatCardContent, + MatCardTitle, + MatButton, + MatIcon, + ProjectSelectComponent, + WriteStatusComponent, + MatError, + MatCheckbox, + InfoComponent, + MatHint, + MatRadioGroup, + MatRadioButton, + TranslocoMarkupComponent, + RouterLinkDirective, + MatCardActions + ] }) export class SettingsComponent extends DataLoadingComponent implements OnInit { translationSuggestionsEnabled = new FormControl(false); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.component.spec.ts index 9f8a252afdd..6a4aa0b71a4 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.component.spec.ts @@ -11,11 +11,11 @@ import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { SupportedBrowsersDialogComponent } from 'xforge-common/supported-browsers-dialog/supported-browsers-dialog.component'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { AudioPlayer } from '../audio/audio-player'; import { createMockMediaStream } from '../test-utils'; @@ -32,8 +32,10 @@ const mockedConsole: MockConsole = MockConsole.install(); describe('AudioRecorderDialogComponent', () => { configureTestingModule(() => ({ - imports: [TestTranslocoModule, TestOnlineStatusModule.forRoot(), TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: NoticeService, useMock: mockedNoticeService }, { provide: NAVIGATOR, useMock: mockedNavigator }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.component.ts index 3b74363854f..d50d37d843c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.component.ts @@ -1,4 +1,4 @@ -import { CommonModule } from '@angular/common'; +import { NgClass } from '@angular/common'; import { Component, DestroyRef, @@ -11,7 +11,10 @@ import { ViewChild } from '@angular/core'; import { ControlValueAccessor } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { MAT_DIALOG_DATA, MatDialogContent, MatDialogRef } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { TranslocoModule } from '@ngneat/transloco'; import { interval, Observable, Subscription, timer } from 'rxjs'; import { map, take } from 'rxjs/operators'; @@ -23,11 +26,9 @@ import { BrowserIssue, SupportedBrowsersDialogComponent } from 'xforge-common/supported-browsers-dialog/supported-browsers-dialog.component'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { audioRecordingMimeType, objectId } from 'xforge-common/utils'; import { SingleButtonAudioPlayerComponent } from '../../checking/checking/single-button-audio-player/single-button-audio-player.component'; -import { SharedModule } from '../shared.module'; export interface AudioAttachment { status?: 'denied' | 'processed' | 'recording' | 'reset' | 'stopped' | 'uploaded'; @@ -50,7 +51,16 @@ export interface AudioRecorderDialogResult { selector: 'app-audio-recorder-dialog', templateUrl: './audio-recorder-dialog.component.html', styleUrl: './audio-recorder-dialog.component.scss', - imports: [UICommonModule, CommonModule, SharedModule, TranslocoModule] + imports: [ + MatTooltip, + MatButton, + MatIconButton, + MatIcon, + MatDialogContent, + NgClass, + SingleButtonAudioPlayerComponent, + TranslocoModule + ] }) export class AudioRecorderDialogComponent implements ControlValueAccessor, OnInit, OnDestroy { @ViewChild(SingleButtonAudioPlayerComponent) audioPlayer?: SingleButtonAudioPlayerComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.stories.ts index db12470da29..d7180cabbbb 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio-recorder-dialog/audio-recorder-dialog.stories.ts @@ -3,7 +3,6 @@ import { expect, userEvent } from '@storybook/test'; import { instance, mock, when } from 'ts-mockito'; import { NAVIGATOR } from 'xforge-common/browser-globals'; import { DialogService } from 'xforge-common/dialog.service'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { NoticeService } from 'xforge-common/notice.service'; import { MatDialogLaunchComponent, @@ -95,9 +94,7 @@ export default { } as Meta; const dialogStoryConfig: MatDialogStoryConfig = { - imports: [I18nStoryModule], - providers: [DialogService, NoticeService, { provide: NAVIGATOR, useValue: instance(mockedNavigator) }], - standaloneComponent: true + providers: [DialogService, NoticeService, { provide: NAVIGATOR, useValue: instance(mockedNavigator) }] }; export const ReadyToRecord = matDialogStory(AudioRecorderDialogComponent, dialogStoryConfig); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player-base/audio-player-base.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player-base/audio-player-base.component.spec.ts index 7d998e2e769..8a6e83bd957 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player-base/audio-player-base.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player-base/audio-player-base.component.spec.ts @@ -1,7 +1,7 @@ import { Component, NgZone, ViewChild } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; import { AudioPlayerStub } from '../../../checking/checking-test.utils'; import { AudioPlayer, AudioStatus } from '../audio-player'; @@ -101,9 +101,8 @@ class TestEnvironment { constructor(template: string) { TestBed.configureTestingModule({ - declarations: [HostComponent, AudioTestComponent], - providers: [{ provide: OnlineStatusService, useClass: TestOnlineStatusService }], - imports: [TestOnlineStatusModule.forRoot()] + imports: [HostComponent, AudioTestComponent], + providers: [{ provide: OnlineStatusService, useClass: TestOnlineStatusService }, provideTestOnlineStatus()] }); TestBed.overrideComponent(HostComponent, { set: { template: template } }); this.testOnlineStatusService = TestBed.inject(OnlineStatusService) as TestOnlineStatusService; @@ -121,8 +120,7 @@ class TestEnvironment { @Component({ selector: 'app-audio-player', - template: '

Mock Audio Player

', - standalone: false + template: '

Mock Audio Player

' }) class AudioTestComponent extends AudioPlayerBaseComponent { setAudio(audio: AudioPlayer): void { @@ -137,7 +135,7 @@ class AudioTestComponent extends AudioPlayerBaseComponent { @Component({ selector: 'app-host', template: '', - standalone: false + imports: [AudioTestComponent] }) class HostComponent { @ViewChild(AudioTestComponent) baseComponent!: AudioTestComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player-base/audio-player-base.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player-base/audio-player-base.component.ts index 5cddbdf28a6..2e29c47e70c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player-base/audio-player-base.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player-base/audio-player-base.component.ts @@ -5,8 +5,7 @@ import { SubscriptionDisposable } from 'xforge-common/subscription-disposable'; import { AudioPlayer, AudioStatus } from '../audio-player'; @Component({ - template: ``, - standalone: false + template: `` }) export abstract class AudioPlayerBaseComponent extends SubscriptionDisposable implements OnDestroy { readonly isAudioAvailable$: BehaviorSubject = new BehaviorSubject(false); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player/audio-player.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player/audio-player.component.ts index 22d13709a09..2850b107ab8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player/audio-player.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player/audio-player.component.ts @@ -1,15 +1,20 @@ +import { Dir } from '@angular/cdk/bidi'; import { Component, OnDestroy } from '@angular/core'; -import { MatSliderDragEvent } from '@angular/material/slider'; +import { MatIcon } from '@angular/material/icon'; +import { MatSlider, MatSliderDragEvent, MatSliderThumb } from '@angular/material/slider'; +import { TranslocoModule } from '@ngneat/transloco'; import { Subscription } from 'rxjs'; import { I18nService } from 'xforge-common/i18n.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; +import { InfoComponent } from '../../info/info.component'; import { AudioPlayerBaseComponent } from '../audio-player-base/audio-player-base.component'; +import { AudioTimePipe } from '../audio-time-pipe'; @Component({ selector: 'app-audio-player', templateUrl: './audio-player.component.html', styleUrls: ['./audio-player.component.scss'], - standalone: false + imports: [TranslocoModule, Dir, MatSlider, MatSliderThumb, MatIcon, InfoComponent, AudioTimePipe] }) export class AudioPlayerComponent extends AudioPlayerBaseComponent implements OnDestroy { private _currentTime: number = 0; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player/audio-player.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player/audio-player.stories.ts index 555fd7ba211..c71e690d4a9 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player/audio-player.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-player/audio-player.stories.ts @@ -1,10 +1,7 @@ -import { CommonModule } from '@angular/common'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { of } from 'rxjs'; import { instance, mock, when } from 'ts-mockito'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { AudioTimePipe } from '../audio-time-pipe'; import { AudioPlayerComponent } from './audio-player.component'; @@ -17,14 +14,8 @@ const meta: Meta = { component: AudioPlayerComponent, decorators: [ moduleMetadata({ - imports: [UICommonModule, CommonModule, I18nStoryModule], - declarations: [AudioTimePipe], - providers: [ - { - provide: OnlineStatusService, - useValue: instance(mockedOnlineStatusService) - } - ] + imports: [AudioTimePipe], + providers: [{ provide: OnlineStatusService, useValue: instance(mockedOnlineStatusService) }] }) ], args: { source: './test-audio-player.webm' } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-time-pipe.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-time-pipe.ts index df7b2e6d8cc..4b08c6da111 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-time-pipe.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/audio/audio-time-pipe.ts @@ -1,9 +1,6 @@ import { Pipe, PipeTransform } from '@angular/core'; -@Pipe({ - name: 'audioTime', - standalone: false -}) +@Pipe({ name: 'audioTime' }) export class AudioTimePipe implements PipeTransform { transform(seconds: number, ..._args: any[]): string { const minutesString = Math.floor(seconds / 60); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-chapter-chooser/book-chapter-chooser.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-chapter-chooser/book-chapter-chooser.component.ts index 51b86c0b183..4512d31adb6 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-chapter-chooser/book-chapter-chooser.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-chapter-chooser/book-chapter-chooser.component.ts @@ -1,5 +1,12 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { I18nService } from 'xforge-common/i18n.service'; +import { TranslocoModule } from '@ngneat/transloco'; +import { MatFormField } from '@angular/material/form-field'; +import { MatSelect } from '@angular/material/select'; +import { MatOption } from '@angular/material/autocomplete'; +import { MatIconButton } from '@angular/material/button'; +import { MatTooltip } from '@angular/material/tooltip'; +import { MatIcon } from '@angular/material/icon'; /** * This component is used to choose a book and chapter. Actual navigation on the basis of the selection is the @@ -9,7 +16,7 @@ import { I18nService } from 'xforge-common/i18n.service'; selector: 'app-book-chapter-chooser', templateUrl: './book-chapter-chooser.component.html', styleUrls: ['./book-chapter-chooser.component.scss'], - standalone: false + imports: [TranslocoModule, MatFormField, MatSelect, MatOption, MatIconButton, MatTooltip, MatIcon] }) export class BookChapterChooserComponent { @Input() book?: number; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-chapter-chooser/book-chapter-chooser.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-chapter-chooser/book-chapter-chooser.stories.ts index 034debc2af9..549f72b605f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-chapter-chooser/book-chapter-chooser.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-chapter-chooser/book-chapter-chooser.stories.ts @@ -1,9 +1,6 @@ -import { CommonModule } from '@angular/common'; import { Meta, StoryFn } from '@storybook/angular'; import { expect, userEvent, within } from '@storybook/test'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { arrayOfIntsFromOne } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { getOverlay } from '../../../../.storybook/util/mat-dialog-launch'; import { BookChapterChooserComponent } from './book-chapter-chooser.component'; @@ -22,7 +19,6 @@ const meta: Meta = { export default meta; const Template: StoryFn = args => ({ - moduleMetadata: { imports: [CommonModule, UICommonModule, I18nStoryModule] }, props: args }); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-multi-select/book-multi-select.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-multi-select/book-multi-select.component.spec.ts index 44ae663ee22..be914299c96 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-multi-select/book-multi-select.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-multi-select/book-multi-select.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; import { mock, when } from 'ts-mockito'; import { I18nService } from 'xforge-common/i18n.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { Book } from '../../translate/draft-generation/draft-generation-steps/draft-generation-steps.component'; import { ProgressService, TextProgress } from '../progress-service/progress.service'; import { BookMultiSelectComponent } from './book-multi-select.component'; @@ -18,7 +18,7 @@ describe('BookMultiSelectComponent', () => { let mockSelectedBooks: Book[]; configureTestingModule(() => ({ - imports: [TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ { provide: ProgressService, useMock: mockedProgressService }, { provide: I18nService, useMock: mockedI18nService } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-multi-select/book-multi-select.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-multi-select/book-multi-select.component.ts index 6e2b1a70a1f..53886b3cb50 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-multi-select/book-multi-select.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/book-multi-select/book-multi-select.component.ts @@ -1,10 +1,12 @@ import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; -import { MatChipsModule } from '@angular/material/chips'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { MatChipListbox, MatChipOption } from '@angular/material/chips'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { MatTooltip } from '@angular/material/tooltip'; import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; import { filter, firstValueFrom } from 'rxjs'; import { L10nPercentPipe } from 'xforge-common/l10n-percent.pipe'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { Book } from '../../translate/draft-generation/draft-generation-steps/draft-generation-steps.component'; import { ProgressService } from '../progress-service/progress.service'; @@ -20,7 +22,15 @@ type Scope = 'OT' | 'NT' | 'DC'; @Component({ selector: 'app-book-multi-select', templateUrl: './book-multi-select.component.html', - imports: [UICommonModule, MatChipsModule, TranslocoModule, L10nPercentPipe], + imports: [ + MatCheckbox, + MatChipListbox, + MatChipOption, + MatTooltip, + MatProgressSpinner, + TranslocoModule, + L10nPercentPipe + ], styleUrls: ['./book-multi-select.component.scss'] }) export class BookMultiSelectComponent implements OnChanges { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/copyright-banner/copyright-banner.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/copyright-banner/copyright-banner.component.spec.ts index 586b113ab50..973b4ab7a41 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/copyright-banner/copyright-banner.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/copyright-banner/copyright-banner.component.spec.ts @@ -5,7 +5,7 @@ import { of } from 'rxjs'; import { mock } from 'ts-mockito'; import { DialogService } from 'xforge-common/dialog.service'; import { I18nService } from 'xforge-common/i18n.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { CopyrightBannerComponent } from './copyright-banner.component'; const mockedDialogService = mock(DialogService); @@ -14,7 +14,7 @@ const mockedMatDialog = mock(MatDialog); describe('CopyrightBannerComponent', () => { configureTestingModule(() => ({ - imports: [CopyrightBannerComponent, TestTranslocoModule], + imports: [CopyrightBannerComponent, getTestTranslocoModule()], providers: [ { provide: DialogService, useValue: mockedDialogService }, { provide: I18nService, useValue: mockedi18nService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/custom-icon.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/custom-icons.ts similarity index 77% rename from src/SIL.XForge.Scripture/ClientApp/src/app/shared/custom-icon.module.ts rename to src/SIL.XForge.Scripture/ClientApp/src/app/shared/custom-icons.ts index 0e30b9aa416..7464b1a7981 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/custom-icon.module.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/custom-icons.ts @@ -1,5 +1,5 @@ -import { NgModule } from '@angular/core'; -import { MatIconModule, MatIconRegistry } from '@angular/material/icon'; +import { EnvironmentProviders, inject, provideAppInitializer } from '@angular/core'; +import { MatIconRegistry } from '@angular/material/icon'; import { DomSanitizer } from '@angular/platform-browser'; import { lynxIcons } from './svg-icons/lynx-icons'; @@ -15,16 +15,18 @@ const BIBLICAL_TERMS_ICON = ` 1.845 1.344 1.845 3.404 0 1.43-.629 2.202-.486.601-1.058.601-.315 0-.572-.486-.429-.787-1.187-1.444l-2.145 2.674 ` + `3.604 3.632q1.287 1.301 1.745 2.116.543 1.001.543 2.417z"/>`; -@NgModule({ - imports: [MatIconModule], - exports: [MatIconModule] -}) -export class CustomIconModule { - constructor(iconRegistry: MatIconRegistry, sanitizer: DomSanitizer) { +/** + * This registers custom SVG icons with Material Icon Registry. + */ +export function provideCustomIcons(): EnvironmentProviders { + return provideAppInitializer(() => { + const iconRegistry = inject(MatIconRegistry); + const sanitizer = inject(DomSanitizer); + iconRegistry.addSvgIconLiteral('biblical_terms', sanitizer.bypassSecurityTrustHtml(BIBLICAL_TERMS_ICON)); for (const [name, svg] of Object.entries(lynxIcons)) { iconRegistry.addSvgIconLiteral(name, sanitizer.bypassSecurityTrustHtml(svg)); } - } + }); } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/diagnostic-overlay/diagnostic-overlay.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/diagnostic-overlay/diagnostic-overlay.component.ts index f8e80b2b40a..0f378c6b6aa 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/diagnostic-overlay/diagnostic-overlay.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/diagnostic-overlay/diagnostic-overlay.component.ts @@ -1,11 +1,13 @@ import { OverlayModule } from '@angular/cdk/overlay'; -import { CommonModule } from '@angular/common'; +import { KeyValuePipe } from '@angular/common'; import { Component } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; import { DiagnosticOverlayService } from 'xforge-common/diagnostic-overlay.service'; +import { L10nNumberPipe } from 'xforge-common/l10n-number.pipe'; import { LocalSettingsService } from 'xforge-common/local-settings.service'; import { NoticeService } from 'xforge-common/notice.service'; import { RealtimeService } from 'xforge-common/realtime.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; export interface DiagnosticOverlayData { bookNum: number; @@ -21,7 +23,7 @@ const diagnosticOverlayCollapsedKey = 'DIAGNOSTIC_OVERLAY_COLLAPSED'; selector: 'app-diagnostic-overlay', templateUrl: './diagnostic-overlay.component.html', styleUrl: './diagnostic-overlay.component.scss', - imports: [OverlayModule, CommonModule, UICommonModule] + imports: [OverlayModule, KeyValuePipe, MatIconButton, MatIcon, L10nNumberPipe] }) export class DiagnosticOverlayComponent { isExpanded: boolean = true; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/global-notices/global-notices.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/global-notices/global-notices.component.ts index 07c1014fba8..abe71cf8337 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/global-notices/global-notices.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/global-notices/global-notices.component.ts @@ -1,15 +1,14 @@ -import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { TranslocoModule } from '@ngneat/transloco'; import { I18nService } from 'xforge-common/i18n.service'; import { NoticeComponent } from '../notice/notice.component'; @Component({ selector: 'app-global-notices', - imports: [CommonModule, NoticeComponent, MatIconModule, MatButtonModule, MatTooltipModule, TranslocoModule], + imports: [NoticeComponent, MatIcon, MatIconButton, MatTooltip, TranslocoModule], templateUrl: './global-notices.component.html', styleUrl: './global-notices.component.scss' }) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/info/info.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/info/info.component.ts index 7de4b43ac35..303dc999a6f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/info/info.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/info/info.component.ts @@ -1,11 +1,13 @@ import { Component, Input } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { ICONS_TO_MIRROR_RTL } from '../utils'; @Component({ selector: 'app-info', templateUrl: './info.component.html', styleUrls: ['./info.component.scss'], - standalone: false + imports: [MatTooltip, MatIcon] }) export class InfoComponent { @Input() icon?: string = 'help'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/info/info.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/info/info.stories.ts index 7af8eba9f5c..81f3e8b656c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/info/info.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/info/info.stories.ts @@ -1,6 +1,4 @@ -import { CommonModule } from '@angular/common'; -import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { Meta, StoryObj } from '@storybook/angular'; import { InfoComponent } from './info.component'; const defaultArgs = { @@ -10,8 +8,7 @@ const defaultArgs = { const meta: Meta = { title: 'Utility/Info', component: InfoComponent, - args: defaultArgs, - decorators: [moduleMetadata({ imports: [UICommonModule, CommonModule] })] + args: defaultArgs }; export default meta; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/json-viewer/json-viewer.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/json-viewer/json-viewer.component.spec.ts index f44d5505363..3dea7b6a07e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/json-viewer/json-viewer.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/json-viewer/json-viewer.component.spec.ts @@ -246,7 +246,7 @@ describe('JsonViewerComponent', () => { @Component({ selector: 'app-host', template: '', - standalone: false + imports: [JsonViewerComponent] }) class HostComponent { @ViewChild(JsonViewerComponent, { static: true }) component!: JsonViewerComponent; @@ -257,8 +257,8 @@ class TestEnvironment { constructor(data: any) { TestBed.configureTestingModule({ - declarations: [HostComponent], - imports: [JsonViewerComponent] + declarations: [], + imports: [HostComponent] }); this.fixture = TestBed.createComponent(HostComponent); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/json-viewer/json-viewer.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/json-viewer/json-viewer.component.ts index 6999ae84f20..f67af73b5a1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/json-viewer/json-viewer.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/json-viewer/json-viewer.component.ts @@ -30,8 +30,7 @@ export interface JsonToken { @Component({ selector: 'app-json-viewer', templateUrl: './json-viewer.component.html', - styleUrls: ['./json-viewer.component.scss'], - standalone: true + styleUrls: ['./json-viewer.component.scss'] }) export class JsonViewerComponent { private _data: any = {}; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/ltr-marker.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/ltr-marker.stories.ts index 1894c5f6e4e..4a4a0e005b3 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/ltr-marker.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/ltr-marker.stories.ts @@ -1,8 +1,7 @@ -import { CommonModule } from '@angular/common'; import { Injector } from '@angular/core'; import { Translation, TranslocoService } from '@ngneat/transloco'; -import { Decorator, Meta, moduleMetadata, StoryContext, StoryFn, StoryObj } from '@storybook/angular'; -import { I18nStoryModule, I18nStoryDecorator as OriginalI18nStoryDecorator } from 'xforge-common/i18n-story.module'; +import { Decorator, Meta, StoryContext, StoryFn, StoryObj } from '@storybook/angular'; +import { I18nStoryDecorator as OriginalI18nStoryDecorator } from 'xforge-common/i18n-story'; import { I18nService } from 'xforge-common/i18n.service'; import { LtrMarkerInterceptor } from './ltr-marker.interceptor'; @@ -23,12 +22,7 @@ const createMockTranslocoService = (englishTranslations: Translation): Transloco const meta: Meta = { title: 'App/Transloco/LtrMarkers', - decorators: [ - moduleMetadata({ - imports: [CommonModule, I18nStoryModule] - }), - AdaptedI18nStoryDecorator - ], + decorators: [AdaptedI18nStoryDecorator], argTypes: { englishTranslations: { control: 'object', diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.component.spec.ts index f774d54dcf7..cf94285037d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.component.spec.ts @@ -52,7 +52,7 @@ describe('NoticeComponent', () => { @Component({ selector: 'app-host', template: '', - standalone: false + imports: [NoticeComponent] }) class HostComponent { @ViewChild(NoticeComponent, { static: true }) component!: NoticeComponent; @@ -63,8 +63,7 @@ class TestEnvironment { constructor(template: string) { TestBed.configureTestingModule({ - declarations: [HostComponent], - imports: [NoticeComponent] + imports: [NoticeComponent, HostComponent] }); TestBed.overrideComponent(HostComponent, { set: { template } }); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.component.ts index 45d7b929b0c..ae67462d5a7 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.component.ts @@ -1,5 +1,5 @@ import { Component, HostBinding, Input, OnChanges } from '@angular/core'; -import { MatIconModule } from '@angular/material/icon'; +import { MatIcon } from '@angular/material/icon'; import { ICONS_TO_MIRROR_RTL } from '../utils'; import { NoticeMode, NoticeType } from './notice.types'; @@ -7,7 +7,7 @@ import { NoticeMode, NoticeType } from './notice.types'; selector: 'app-notice', templateUrl: './notice.component.html', styleUrls: ['./notice.component.scss'], - imports: [MatIconModule] + imports: [MatIcon] }) export class NoticeComponent implements OnChanges { @Input() type: NoticeType = 'primary'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.stories.ts index 304e90031a6..300067cd2e6 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/notice/notice.stories.ts @@ -1,4 +1,4 @@ -import { MatButtonModule } from '@angular/material/button'; +import { MatButton } from '@angular/material/button'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { NoticeComponent } from '../../shared/notice/notice.component'; import { NoticeMode, noticeModes } from './notice.types'; @@ -22,7 +22,7 @@ export default { component: NoticeComponent, decorators: [ moduleMetadata({ - imports: [MatButtonModule] + imports: [MatButton] }) ], args: defaultArgs, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/page-not-found/page-not-found.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/page-not-found/page-not-found.component.spec.ts index 6ae67fd73ec..9392c578e23 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/page-not-found/page-not-found.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/page-not-found/page-not-found.component.spec.ts @@ -1,20 +1,30 @@ import { Component, ViewChild } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { MatIconModule } from '@angular/material/icon'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { Router } from '@angular/router'; -import { anything, mock, strictEqual, verify } from 'ts-mockito'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { ActivatedRoute, Router, UrlTree } from '@angular/router'; +import { anything, mock, strictEqual, verify, when } from 'ts-mockito'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { PageNotFoundComponent } from './page-not-found.component'; const mockedRouter = mock(Router); +const mockedActivatedRoute = mock(ActivatedRoute); describe('PageNotFoundComponent', () => { - configureTestingModule(() => ({ - imports: [TestTranslocoModule, MatIconModule, MatProgressBarModule], - declarations: [PageNotFoundComponent, PageNotFoundHostComponent], - providers: [{ provide: Router, useMock: mockedRouter }] - })); + configureTestingModule(() => { + // Return a simple UrlTree-like object + when(mockedRouter.createUrlTree(anything(), anything())).thenReturn({ + toString: () => '/projects' + } as UrlTree); + + return { + imports: [PageNotFoundComponent, getTestTranslocoModule(), MatIcon, MatProgressBar, PageNotFoundHostComponent], + providers: [ + { provide: Router, useMock: mockedRouter }, + { provide: ActivatedRoute, useMock: mockedActivatedRoute } + ] + }; + }); it('should redirect after ten seconds', fakeAsync(() => { new TestEnvironment(); @@ -28,7 +38,7 @@ describe('PageNotFoundComponent', () => { @Component({ template: ``, - standalone: false + imports: [PageNotFoundComponent] }) class PageNotFoundHostComponent { @ViewChild(PageNotFoundComponent) pageNotFoundComponent!: PageNotFoundComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/page-not-found/page-not-found.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/page-not-found/page-not-found.component.ts index 63a66a1049b..385cc07b4a8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/page-not-found/page-not-found.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/page-not-found/page-not-found.component.ts @@ -1,7 +1,12 @@ +import { AsyncPipe } from '@angular/common'; import { Component } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressBar } from '@angular/material/progress-bar'; import { Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { lastValueFrom, timer } from 'rxjs'; import { map, takeWhile } from 'rxjs/operators'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; // All times in milliseconds const redirectDelay = 10_000; @@ -12,7 +17,7 @@ const totalProgressUpdates = redirectDelay / progressUpdateInterval; selector: 'app-page-not-found', templateUrl: './page-not-found.component.html', styleUrls: ['./page-not-found.component.scss'], - standalone: false + imports: [TranslocoModule, MatIcon, MatProgressBar, RouterLinkDirective, AsyncPipe] }) export class PageNotFoundComponent { progress = timer(0, progressUpdateInterval).pipe( diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/progress-service/progress.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/progress-service/progress.service.spec.ts index 3c90f8e6c2d..d727be07e2a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/progress-service/progress.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/progress-service/progress.service.spec.ts @@ -7,7 +7,7 @@ import { BehaviorSubject, of } from 'rxjs'; import { anything, instance, mock, when } from 'ts-mockito'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { NoticeService } from 'xforge-common/notice.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { configureTestingModule } from 'xforge-common/test-utils'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { TextDocId } from '../../core/models/text-doc'; @@ -22,8 +22,8 @@ const mockProjectService = mock(ActivatedProjectService); describe('progress service', () => { configureTestingModule(() => ({ - imports: [TestOnlineStatusModule.forRoot()], providers: [ + provideTestOnlineStatus(), { provide: NoticeService, useMock: mockNoticeService }, { provide: PermissionsService, useMock: mockPermissionService }, { provide: SFProjectService, useMock: mockSFProjectService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/index.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/index.ts index 4c76b2f7c8f..ed4d3323288 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/index.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/index.ts @@ -1,8 +1,10 @@ +export * from './base-services/tab-add-request.service'; export * from './base-services/tab-factory.service'; export * from './base-services/tab-menu.service'; -export * from './sf-tabs.module'; +export * from './sf-tabs-providers'; export * from './sf-tabs.types'; export * from './tab-group.component'; +export * from './tab-header/tab-header.component'; export * from './tab-header/tab-header.directive'; export * from './tab-state/tab-group'; export * from './tab-state/tab-state.service'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/sf-tabs-providers.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/sf-tabs-providers.ts new file mode 100644 index 00000000000..65e16f7dfb2 --- /dev/null +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/sf-tabs-providers.ts @@ -0,0 +1,9 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { NoopTabAddRequestService, TabAddRequestService } from './base-services/tab-add-request.service'; + +/** + * Provides the default TabAddRequestService implementation for SF tabs. + */ +export function provideSFTabs(): EnvironmentProviders { + return makeEnvironmentProviders([{ provide: TabAddRequestService, useClass: NoopTabAddRequestService }]); +} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/sf-tabs.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/sf-tabs.module.ts deleted file mode 100644 index 0a9639d5e06..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/sf-tabs.module.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { DragDropModule } from '@angular/cdk/drag-drop'; -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { TranslocoModule } from '@ngneat/transloco'; -import { CustomIconModule } from '../custom-icon.module'; -import { NoopTabAddRequestService, TabAddRequestService } from './base-services/tab-add-request.service'; -import { TabGroupHeaderComponent } from './tab-group-header/tab-group-header.component'; -import { TabScrollButtonComponent } from './tab-group-header/tab-scroll-button/tab-scroll-button.component'; -import { TabGroupComponent } from './tab-group.component'; -import { TabHeaderComponent } from './tab-header/tab-header.component'; -import { TabHeaderDirective } from './tab-header/tab-header.directive'; -import { TabBodyComponent } from './tab/tab-body/tab-body.component'; -import { TabComponent } from './tab/tab.component'; - -@NgModule({ - declarations: [ - TabGroupComponent, - TabComponent, - TabHeaderComponent, - TabHeaderDirective, - TabGroupHeaderComponent, - TabScrollButtonComponent, - TabBodyComponent - ], - imports: [ - CommonModule, - CustomIconModule, - MatButtonModule, - MatIconModule, - MatMenuModule, - MatTooltipModule, - DragDropModule, - TranslocoModule - ], - exports: [TabGroupComponent, TabComponent, TabHeaderDirective], - providers: [{ provide: TabAddRequestService, useClass: NoopTabAddRequestService }] -}) -export class SFTabsModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-group-header.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-group-header.component.spec.ts index 4f6ccfb32f5..736f45b01d5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-group-header.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-group-header.component.spec.ts @@ -1,9 +1,9 @@ import { CdkDrag, CdkDropList } from '@angular/cdk/drag-drop'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { of } from 'rxjs'; -import { TestTranslocoModule } from 'xforge-common/test-utils'; +import { getTestTranslocoModule } from 'xforge-common/test-utils'; import { TabMenuService } from '../base-services/tab-menu.service'; -import { SFTabsModule } from '../sf-tabs.module'; +import { provideSFTabs } from '../sf-tabs-providers'; import { TabGroupHeaderComponent } from './tab-group-header.component'; describe('TabGroupHeaderComponent', () => { @@ -13,9 +13,8 @@ describe('TabGroupHeaderComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [TabGroupHeaderComponent], - imports: [SFTabsModule, TestTranslocoModule], - providers: [{ provide: TabMenuService, useValue: { getMenuItems: () => of([]) } }] + imports: [getTestTranslocoModule(), TabGroupHeaderComponent], + providers: [provideSFTabs(), { provide: TabMenuService, useValue: { getMenuItems: () => of([]) } }] }); fixture = TestBed.createComponent(TabGroupHeaderComponent); component = fixture.componentInstance; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-group-header.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-group-header.component.ts index 812d11cc91e..a29e829752d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-group-header.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-group-header.component.ts @@ -1,4 +1,5 @@ import { CdkDrag, CdkDragDrop, CdkDropList } from '@angular/cdk/drag-drop'; +import { AsyncPipe, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'; import { AfterViewInit, Component, @@ -14,6 +15,9 @@ import { SimpleChanges, ViewChildren } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { TranslocoModule } from '@ngneat/transloco'; import { BehaviorSubject, debounceTime, @@ -29,11 +33,26 @@ import { TabMenuItem, TabMenuService } from '../../sf-tab-group'; import { TabHeaderPointerEvent, TabLocation, TabMoveEvent } from '../sf-tabs.types'; import { TabHeaderComponent } from '../tab-header/tab-header.component'; import { TabComponent } from '../tab/tab.component'; +import { TabScrollButtonComponent } from './tab-scroll-button/tab-scroll-button.component'; @Component({ selector: 'app-tab-group-header', templateUrl: './tab-group-header.component.html', styleUrls: ['./tab-group-header.component.scss'], - standalone: false + imports: [ + CdkDropList, + CdkDrag, + NgFor, + NgIf, + NgTemplateOutlet, + AsyncPipe, + MatIcon, + MatMenu, + MatMenuItem, + MatMenuTrigger, + TranslocoModule, + TabHeaderComponent, + TabScrollButtonComponent + ] }) export class TabGroupHeaderComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy { @Input() groupId: string = ''; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-scroll-button/tab-scroll-button.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-scroll-button/tab-scroll-button.component.spec.ts index 71844c44fea..c02b30f16ff 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-scroll-button/tab-scroll-button.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-scroll-button/tab-scroll-button.component.spec.ts @@ -1,7 +1,7 @@ import { DOCUMENT } from '@angular/common'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { SFTabsModule } from '../../sf-tabs.module'; +import { provideSFTabs } from '../../sf-tabs-providers'; import { TabScrollButtonComponent } from './tab-scroll-button.component'; describe('TabScrollButtonComponent', () => { @@ -10,7 +10,8 @@ describe('TabScrollButtonComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [SFTabsModule] + imports: [TabScrollButtonComponent], + providers: [provideSFTabs()] }); fixture = TestBed.createComponent(TabScrollButtonComponent); component = fixture.componentInstance; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-scroll-button/tab-scroll-button.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-scroll-button/tab-scroll-button.component.ts index 3627a0b0bda..5807856fe1e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-scroll-button/tab-scroll-button.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group-header/tab-scroll-button/tab-scroll-button.component.ts @@ -2,11 +2,13 @@ import { DOCUMENT } from '@angular/common'; import { Component, DestroyRef, EventEmitter, HostBinding, Inject, Input, OnInit, Output } from '@angular/core'; import { BehaviorSubject, distinctUntilChanged, fromEvent, merge } from 'rxjs'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; +import { MatButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'app-tab-scroll-button', templateUrl: './tab-scroll-button.component.html', styleUrls: ['./tab-scroll-button.component.scss'], - standalone: false + imports: [MatButton, MatIcon] }) export class TabScrollButtonComponent implements OnInit { @Input() disabled = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.spec.ts index abdefff5420..824d3b6f888 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.spec.ts @@ -2,11 +2,10 @@ import { QueryList } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; import { v4 as uuid } from 'uuid'; -import { TestTranslocoModule } from 'xforge-common/test-utils'; +import { getTestTranslocoModule } from 'xforge-common/test-utils'; import { TabMenuService } from '../../shared/sf-tab-group'; import { TabAddRequestService } from './base-services/tab-add-request.service'; import { TabFactoryService } from './base-services/tab-factory.service'; -import { SFTabsModule } from './sf-tabs.module'; import { TabGroupComponent } from './tab-group.component'; import { TabInfo, TabStateService } from './tab-state/tab-state.service'; import { TabComponent } from './tab/tab.component'; @@ -18,8 +17,7 @@ describe('TabGroupComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [SFTabsModule, TestTranslocoModule], - declarations: [TabGroupComponent, TabComponent], + imports: [getTestTranslocoModule(), TabGroupComponent, TabComponent], providers: [ { provide: TabFactoryService, useValue: { createTab: () => {} } }, { provide: TabMenuService, useValue: { getMenuItems: () => of([]) } }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.ts index 413f7485606..ba4c9281cd8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.component.ts @@ -1,3 +1,4 @@ +import { NgTemplateOutlet } from '@angular/common'; import { Component, ContentChildren, @@ -12,6 +13,7 @@ import { take } from 'rxjs'; import { TabAddRequestService } from './base-services/tab-add-request.service'; import { TabFactoryService } from './base-services/tab-factory.service'; import { TabHeaderPointerEvent, TabMoveEvent } from './sf-tabs.types'; +import { TabGroupHeaderComponent } from './tab-group-header/tab-group-header.component'; import { TabStateService } from './tab-state/tab-state.service'; import { TabBodyComponent } from './tab/tab-body/tab-body.component'; import { TabComponent } from './tab/tab.component'; @@ -20,7 +22,7 @@ import { TabComponent } from './tab/tab.component'; selector: 'app-tab-group [groupId]', templateUrl: './tab-group.component.html', styleUrls: ['./tab-group.component.scss'], - standalone: false + imports: [TabGroupHeaderComponent, TabBodyComponent, NgTemplateOutlet] }) export class TabGroupComponent implements OnChanges { @Input() groupId: string = ''; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.stories.ts index d9d0001466e..6487e670e58 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-group.stories.ts @@ -1,11 +1,14 @@ +import { AsyncPipe, KeyValuePipe } from '@angular/common'; import { Component, Input, OnChanges } from '@angular/core'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { Observable, of } from 'rxjs'; import { v4 as uuid } from 'uuid'; import { - SFTabsModule, + TabComponent, TabFactoryService, TabGroup, + TabGroupComponent, + TabHeaderDirective, TabInfo, TabMenuItem, TabMenuService, @@ -43,7 +46,7 @@ import { } `, - standalone: false + imports: [AsyncPipe, KeyValuePipe, TabGroupComponent, TabComponent, TabHeaderDirective] }) class SFTabGroupStoriesComponent implements OnChanges { @Input() tabGroups: TabGroup>[] = []; @@ -62,8 +65,7 @@ export default { component: SFTabGroupStoriesComponent, decorators: [ moduleMetadata({ - imports: [SFTabsModule], - declarations: [SFTabGroupStoriesComponent], + imports: [TabGroupComponent, TabComponent, TabHeaderDirective, SFTabGroupStoriesComponent], providers: [ TabStateService>, { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.component.spec.ts index ec39112820b..610e5ae93e0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.component.spec.ts @@ -2,7 +2,7 @@ import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatTooltipHarness } from '@angular/material/tooltip/testing'; -import { SFTabsModule } from '../sf-tabs.module'; +import { provideSFTabs } from '../sf-tabs-providers'; import { TabHeaderComponent } from './tab-header.component'; describe('TabHeaderComponent', () => { @@ -12,7 +12,8 @@ describe('TabHeaderComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [SFTabsModule] + imports: [TabHeaderComponent], + providers: [provideSFTabs()] }); fixture = TestBed.createComponent(TabHeaderComponent); harnessLoader = TestbedHarnessEnvironment.loader(fixture); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.component.ts index 48f168ce880..c5c1a7cdbf0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.component.ts @@ -1,11 +1,14 @@ import { Component, EventEmitter, HostBinding, HostListener, Inject, Input, Output } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { SF_TABS_CONFIG, SFTabsConfig } from '../sf-tabs-config'; @Component({ selector: 'app-tab-header', templateUrl: './tab-header.component.html', styleUrls: ['./tab-header.component.scss'], - standalone: false + imports: [MatTooltip, MatIconButton, MatIcon] }) export class TabHeaderComponent { @HostBinding('class.closeable') diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.directive.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.directive.spec.ts index 3629222b441..98f7092eae8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.directive.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.directive.spec.ts @@ -5,7 +5,7 @@ import { TabHeaderDirective } from './tab-header.directive'; @Component({ template: `
`, - standalone: false + imports: [TabHeaderDirective] }) class TestComponent {} @@ -15,7 +15,7 @@ describe('TabHeaderDirective', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [TabHeaderDirective, TestComponent] + imports: [TestComponent] }); fixture = TestBed.createComponent(TestComponent); directiveElement = fixture.debugElement.query(By.directive(TabHeaderDirective)); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.directive.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.directive.ts index ac15d0e61bb..ae1987d0406 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.directive.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab-header/tab-header.directive.ts @@ -1,8 +1,5 @@ /* eslint-disable @angular-eslint/directive-selector */ import { Directive } from '@angular/core'; -@Directive({ - selector: '[sf-tab-header]', - standalone: false -}) +@Directive({ selector: '[sf-tab-header]' }) export class TabHeaderDirective {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab/tab-body/tab-body.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab/tab-body/tab-body.component.ts index 03a317d050b..9c3162c479f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab/tab-body/tab-body.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab/tab-body/tab-body.component.ts @@ -3,8 +3,7 @@ import { Component, HostBinding, Input } from '@angular/core'; @Component({ selector: 'app-tab-body', templateUrl: './tab-body.component.html', - styleUrls: ['./tab-body.component.scss'], - standalone: false + styleUrls: ['./tab-body.component.scss'] }) export class TabBodyComponent { @HostBinding('class.active') diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab/tab.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab/tab.component.ts index 03938765ddf..5e04067f5e2 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab/tab.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/sf-tab-group/tab/tab.component.ts @@ -5,8 +5,7 @@ import { TabHeaderDirective } from '../tab-header/tab-header.directive'; @Component({ selector: 'app-tab', templateUrl: './tab.component.html', - styleUrls: ['./tab.component.scss'], - standalone: false + styleUrls: ['./tab.component.scss'] }) export class TabComponent { @Input() closeable: boolean = true; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.component.spec.ts index 6c8deddb4e8..7a8dc23b82c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.component.spec.ts @@ -2,11 +2,10 @@ import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core import { ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; import { mock, when } from 'ts-mockito'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { ShareButtonComponent } from './share-button.component'; @@ -14,13 +13,12 @@ const mockedActivatedRoute = mock(ActivatedRoute); describe('ShareButtonComponent', () => { configureTestingModule(() => ({ - imports: [ - TestTranslocoModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - TestOnlineStatusModule.forRoot(), - UICommonModule - ], - providers: [{ provide: ActivatedRoute, useMock: mockedActivatedRoute }] + imports: [getTestTranslocoModule()], + providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), + provideTestOnlineStatus(), + { provide: ActivatedRoute, useMock: mockedActivatedRoute } + ] })); it('dialog should open when clicked', fakeAsync(() => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.component.ts index 70c5d2d645b..1741ab79af5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.component.ts @@ -1,5 +1,9 @@ import { Component, Input, OnInit } from '@angular/core'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { ActivatedRoute } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; import { map } from 'rxjs/operators'; import { DialogService } from 'xforge-common/dialog.service'; @@ -8,7 +12,7 @@ import { ShareDialogComponent, ShareDialogData } from './share-dialog.component' @Component({ selector: 'app-share-button', templateUrl: './share-button.component.html', - standalone: false + imports: [TranslocoModule, MatIconButton, MatTooltip, MatIcon, MatButton] }) export class ShareButtonComponent implements OnInit { @Input() defaultRole?: SFProjectRole; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.stories.ts index f99d5296e01..8873f97b2b5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-button.stories.ts @@ -1,12 +1,9 @@ -import { CommonModule } from '@angular/common'; import { ActivatedRoute } from '@angular/router'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { userEvent, within } from '@storybook/test'; import { of } from 'rxjs'; import { anything, instance, mock, reset, verify, when } from 'ts-mockito'; import { DialogService } from 'xforge-common/dialog.service'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { ShareButtonComponent } from './share-button.component'; const mockedActivatedRoute = mock(ActivatedRoute); @@ -24,7 +21,6 @@ type Story = StoryObj; const Template: Story = { decorators: [ moduleMetadata({ - imports: [UICommonModule, CommonModule, I18nStoryModule], providers: [ { provide: ActivatedRoute, useValue: instance(mockedActivatedRoute) }, { provide: DialogService, useValue: instance(mockedDialogService) } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-control.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-control.component.spec.ts index 593cdf92fac..0be5cd96a35 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-control.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-control.component.spec.ts @@ -1,8 +1,8 @@ -import { Component, DebugElement, NgModule, ViewChild } from '@angular/core'; +import { Component, DebugElement, ViewChild } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { provideRouter } from '@angular/router'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { CheckingConfig } from 'realtime-server/lib/esm/scriptureforge/models/checking-config'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; @@ -11,17 +11,17 @@ import { anything, capture, mock, verify, when } from 'ts-mockito'; import { CommandError, CommandErrorCode } from 'xforge-common/command.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SF_DEFAULT_SHARE_ROLE, SF_DEFAULT_TRANSLATE_SHARE_ROLE } from '../../core/models/sf-project-role-info'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { SFProjectService } from '../../core/sf-project.service'; -import { SharedModule } from '../shared.module'; +import { provideQuillRegistrations } from '../text/quill-editor-registration/quill-providers'; import { ShareControlComponent } from './share-control.component'; const mockedProjectService = mock(SFProjectService); @@ -30,19 +30,17 @@ const mockedUserService = mock(UserService); describe('ShareControlComponent', () => { configureTestingModule(() => ({ - declarations: [TestHostComponent], - imports: [ - TestModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - NoopAnimationsModule, - TestOnlineStatusModule.forRoot(), - SharedModule.forRoot() - ], + imports: [TestHostComponent, getTestTranslocoModule()], providers: [ + provideRouter([]), + provideQuillRegistrations(), + provideTestRealtime(SF_TYPE_REGISTRY), + provideTestOnlineStatus(), { provide: SFProjectService, useMock: mockedProjectService }, { provide: NoticeService, useMock: mockedNoticeService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, - { provide: UserService, useMock: mockedUserService } + { provide: UserService, useMock: mockedUserService }, + provideNoopAnimations() ] })); @@ -258,16 +256,11 @@ describe('ShareControlComponent', () => { })); }); -@NgModule({ - imports: [RouterModule.forRoot([]), TestTranslocoModule] -}) -class TestModule {} - @Component({ template: ` `, - standalone: false + imports: [ShareControlComponent] }) class TestHostComponent { @ViewChild(ShareControlComponent) component!: ShareControlComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-control.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-control.component.ts index 5fef99f3241..bb100a3d333 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-control.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-control.component.ts @@ -1,5 +1,18 @@ import { Component, DestroyRef, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; -import { FormControl, FormGroup, FormGroupDirective, Validators } from '@angular/forms'; +import { + FormControl, + FormGroup, + FormGroupDirective, + FormsModule, + ReactiveFormsModule, + Validators +} from '@angular/forms'; +import { MatOption } from '@angular/material/autocomplete'; +import { MatButton } from '@angular/material/button'; +import { MatError, MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; +import { MatSelect, MatSelectTrigger } from '@angular/material/select'; +import { TranslocoModule } from '@ngneat/transloco'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; @@ -14,12 +27,26 @@ import { XFValidators } from 'xforge-common/xfvalidators'; import { SF_DEFAULT_SHARE_ROLE, SF_DEFAULT_TRANSLATE_SHARE_ROLE } from '../../core/models/sf-project-role-info'; import { SFProjectService } from '../../core/sf-project.service'; import { ShareBaseComponent } from './share-base.component'; +import { ShareButtonComponent } from './share-button.component'; /** UI to share project access with new users, such as by sending an invitation email. */ @Component({ selector: 'app-share-control', templateUrl: './share-control.component.html', styleUrls: ['./share-control.component.scss'], - standalone: false + imports: [ + TranslocoModule, + FormsModule, + ReactiveFormsModule, + MatFormField, + MatLabel, + MatInput, + MatError, + MatSelect, + MatSelectTrigger, + MatOption, + MatButton, + ShareButtonComponent + ] }) export class ShareControlComponent extends ShareBaseComponent { /** Fires when an invitation is sent. */ diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-dialog.component.spec.ts index 5cbbec58e4c..8886c6c8f48 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-dialog.component.spec.ts @@ -1,4 +1,4 @@ -import { DebugElement, NgModule } from '@angular/core'; +import { DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; @@ -13,11 +13,11 @@ import { Locale } from 'xforge-common/models/i18n-locale'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SF_DEFAULT_SHARE_ROLE, SF_DEFAULT_TRANSLATE_SHARE_ROLE } from '../../core/models/sf-project-role-info'; @@ -38,8 +38,10 @@ enum TestUsers { describe('ShareDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, TestOnlineStatusModule.forRoot(), TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: SFProjectService, useMock: mockedProjectService }, { provide: NAVIGATOR, useMock: mockedNavigator }, { provide: NoticeService, useMock: mockedNoticeService }, @@ -341,11 +343,6 @@ interface TestEnvironmentArgs { translateShareEnabled?: boolean; } -@NgModule({ - imports: [TestTranslocoModule] -}) -class DialogTestModule {} - class TestEnvironment { isDialogOpen = true; readonly fixture: ComponentFixture; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-dialog.component.ts index b779410906e..219b6816376 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/share/share-dialog.component.ts @@ -1,5 +1,21 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { NgClass } from '@angular/common'; import { Component, DestroyRef, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatListOption, MatSelectionList } from '@angular/material/list'; +import { MatMenu, MatMenuTrigger } from '@angular/material/menu'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; +import { TranslocoMarkupComponent } from 'ngx-transloco-markup'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; @@ -14,6 +30,7 @@ import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { environment } from '../../../environments/environment'; import { SF_DEFAULT_SHARE_ROLE, SF_DEFAULT_TRANSLATE_SHARE_ROLE } from '../../core/models/sf-project-role-info'; import { SFProjectService } from '../../core/sf-project.service'; +import { NoticeComponent } from '../notice/notice.component'; import { ShareBaseComponent } from './share-base.component'; export interface ShareDialogData { projectId: string; @@ -28,7 +45,25 @@ export enum ShareLinkType { @Component({ templateUrl: './share-dialog.component.html', styleUrls: ['./share-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + MatIconButton, + MatDialogClose, + MatIcon, + CdkScrollable, + MatDialogContent, + MatMenuTrigger, + MatTooltip, + MatMenu, + MatSelectionList, + MatListOption, + TranslocoMarkupComponent, + NgClass, + NoticeComponent, + MatDialogActions, + MatButton + ] }) export class ShareDialogComponent extends ShareBaseComponent { // this is duplicated with the strings to ease their translation diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/shared.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/shared.module.ts deleted file mode 100644 index 8bbbbb6e84f..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/shared.module.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { inject, ModuleWithProviders, NgModule, provideAppInitializer } from '@angular/core'; -import { TranslocoModule } from '@ngneat/transloco'; -import { QuillModule } from 'ngx-quill'; -import { TranslocoMarkupModule } from 'ngx-transloco-markup'; -import { UICommonModule } from 'xforge-common/ui-common.module'; -import { CheckingQuestionComponent } from '../checking/checking/checking-answers/checking-question/checking-question.component'; -import { SingleButtonAudioPlayerComponent } from '../checking/checking/single-button-audio-player/single-button-audio-player.component'; -import { LynxInsightsModule } from '../translate/editor/lynx/insights/lynx-insights.module'; -import { BookChapterChooserComponent } from './book-chapter-chooser/book-chapter-chooser.component'; -import { InfoComponent } from './info/info.component'; -import { NoticeComponent } from './notice/notice.component'; -import { ShareButtonComponent } from './share/share-button.component'; -import { ShareControlComponent } from './share/share-control.component'; -import { ShareDialogComponent } from './share/share-dialog.component'; -import { QuillFormatRegistryService } from './text/quill-editor-registration/quill-format-registry.service'; -import { registerScriptureFormats } from './text/quill-editor-registration/quill-registrations'; -import { TextDocIdPipe } from './text/text-doc-id.pipe'; -import { TextComponent } from './text/text.component'; - -const componentExports = [ - BookChapterChooserComponent, - InfoComponent, - ShareButtonComponent, - ShareControlComponent, - ShareDialogComponent, - TextComponent, - CheckingQuestionComponent, - SingleButtonAudioPlayerComponent, - TextDocIdPipe -]; - -@NgModule({ - imports: [ - CommonModule, - QuillModule, - UICommonModule, - TranslocoModule, - NoticeComponent, - TranslocoMarkupModule, - LynxInsightsModule - ], - declarations: componentExports, - exports: [...componentExports, NoticeComponent] -}) -export class SharedModule { - static forRoot(): ModuleWithProviders { - return { - ngModule: SharedModule, - providers: [ - provideAppInitializer(() => { - const initializerFn = ((formatRegistry: QuillFormatRegistryService) => () => { - registerScriptureFormats(formatRegistry); - })(inject(QuillFormatRegistryService)); - return initializerFn(); - }) - ] - }; - } -} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/quill-editor-registration/quill-providers.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/quill-editor-registration/quill-providers.ts new file mode 100644 index 00000000000..62ed1727d4b --- /dev/null +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/quill-editor-registration/quill-providers.ts @@ -0,0 +1,13 @@ +import { EnvironmentProviders, inject, provideAppInitializer } from '@angular/core'; +import { QuillFormatRegistryService } from './quill-format-registry.service'; +import { registerScriptureFormats } from './quill-registrations'; + +/** + * Provides app initialization registering of custom Quill formats. + */ +export function provideQuillRegistrations(): EnvironmentProviders { + return provideAppInitializer(() => { + const formatRegistry = inject(QuillFormatRegistryService); + registerScriptureFormats(formatRegistry); + }); +} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/quill-editor-registration/quill-registrations.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/quill-editor-registration/quill-registrations.spec.ts index b795282326a..20f14a38668 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/quill-editor-registration/quill-registrations.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/quill-editor-registration/quill-registrations.spec.ts @@ -3,12 +3,12 @@ import Quill from 'quill'; import QuillCursors from 'quill-cursors'; import QuillInlineBlot from 'quill/blots/inline'; import QuillScrollBlot from 'quill/blots/scroll'; -import { SharedModule } from '../../shared.module'; import { DragAndDrop } from '../drag-and-drop'; import { DisableHtmlClipboard } from './quill-clipboard'; import { QuillFormatRegistryService } from './quill-format-registry.service'; import { ChapterEmbed, NotNormalizedText, ParaBlock, ScrollBlot } from './quill-formats/quill-blots'; import { FixSelectionHistory } from './quill-history'; +import { provideQuillRegistrations } from './quill-providers'; import { registerScriptureFormats } from './quill-registrations'; describe('QuillRegistrations', () => { @@ -19,8 +19,7 @@ describe('QuillRegistrations', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [SharedModule.forRoot()], - providers: [QuillFormatRegistryService] + providers: [provideQuillRegistrations(), QuillFormatRegistryService] }); formatRegistry = TestBed.inject(QuillFormatRegistryService); quillRegisterSpy = spyOn(Quill, 'register'); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-doc-id.pipe.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-doc-id.pipe.ts index 98daaea6553..07bcb5d5506 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-doc-id.pipe.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-doc-id.pipe.ts @@ -2,10 +2,7 @@ import { Pipe, PipeTransform } from '@angular/core'; import { TextType } from 'realtime-server/lib/esm/scriptureforge/models/text-data'; import { TextDocId } from '../../core/models/text-doc'; -@Pipe({ - name: 'textDocId', - standalone: false -}) +@Pipe({ name: 'textDocId' }) export class TextDocIdPipe implements PipeTransform { transform( projectId: string | undefined, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-note-dialog/text-note-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-note-dialog/text-note-dialog.component.spec.ts index a88422b06a1..a976ba017ed 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-note-dialog/text-note-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-note-dialog/text-note-dialog.component.spec.ts @@ -1,20 +1,20 @@ -import { DebugElement, NgModule } from '@angular/core'; +import { DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { ChildViewContainerComponent, configureTestingModule, - matDialogCloseDelay, - TestTranslocoModule + getTestTranslocoModule, + matDialogCloseDelay } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { NoteDialogData, TextNoteDialogComponent, TextNoteType } from './text-note-dialog.component'; describe('TextNoteDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, NoopAnimationsModule] + imports: [getTestTranslocoModule(false), TextNoteDialogComponent], + providers: [provideNoopAnimations()] })); let env: TestEnvironment; @@ -58,12 +58,6 @@ describe('TextNoteDialogComponent', () => { })); }); -@NgModule({ - imports: [UICommonModule, TestTranslocoModule], - declarations: [TextNoteDialogComponent] -}) -class DialogTestModule {} - class TestEnvironment { fixture: ComponentFixture; component: TextNoteDialogComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-note-dialog/text-note-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-note-dialog/text-note-dialog.component.ts index a78ae7ecbca..ecbff889583 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-note-dialog/text-note-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text-note-dialog/text-note-dialog.component.ts @@ -1,7 +1,11 @@ import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogTitle, MatDialogClose, MatDialogContent } from '@angular/material/dialog'; import { TranslocoService } from '@ngneat/transloco'; import { LocaleDirection } from 'xforge-common/models/i18n-locale'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { Dir } from '@angular/cdk/bidi'; export enum TextNoteType { Footnote = 'f', @@ -20,7 +24,7 @@ export interface NoteDialogData { @Component({ templateUrl: './text-note-dialog.component.html', styleUrls: ['./text-note-dialog.component.scss'], - standalone: false + imports: [MatDialogTitle, MatIconButton, MatDialogClose, MatIcon, CdkScrollable, MatDialogContent, Dir] }) export class TextNoteDialogComponent { constructor( diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text.component.spec.ts index a52af6e81ca..26d3bafbc1b 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text.component.spec.ts @@ -18,9 +18,9 @@ import { DialogService } from 'xforge-common/dialog.service'; import { MockConsole } from 'xforge-common/mock-console'; import { UserDoc } from 'xforge-common/models/user-doc'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; @@ -29,8 +29,8 @@ import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { TextDoc, TextDocId } from '../../core/models/text-doc'; import { SFProjectService } from '../../core/sf-project.service'; -import { SharedModule } from '../shared.module'; import { getCombinedVerseTextDoc, getEmptyChapterDoc, getPoetryVerseTextDoc, getTextDoc } from '../test-utils'; +import { provideQuillRegistrations } from './quill-editor-registration/quill-providers'; import { getAttributesAtPosition } from './quill-util'; import { TextNoteDialogComponent, TextNoteType } from './text-note-dialog/text-note-dialog.component'; import { @@ -49,9 +49,11 @@ const mockedDialogService = mock(DialogService); describe('TextComponent', () => { configureTestingModule(() => ({ - declarations: [HostComponent], - imports: [SharedModule.forRoot(), TestOnlineStatusModule.forRoot(), TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [HostComponent], providers: [ + provideQuillRegistrations(), + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: SFProjectService, useMock: mockedProjectService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: TranslocoService, useMock: mockedTranslocoService }, @@ -1689,7 +1691,7 @@ class MockQuill extends Quill { [enablePresence]="enablePresence" (presenceChange)="onPresenceChange($event)" >`, - standalone: false + imports: [TextComponent] }) class HostComponent { @ViewChild(TextComponent) textComponent!: TextComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text.component.ts index ce51dcd0fe1..07d339fda09 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/text/text.component.ts @@ -1,4 +1,5 @@ -import { DOCUMENT } from '@angular/common'; +import { Dir } from '@angular/cdk/bidi'; +import { DOCUMENT, NgClass } from '@angular/common'; import { AfterViewInit, ChangeDetectorRef, @@ -13,6 +14,7 @@ import { import { TranslocoService } from '@ngneat/transloco'; import { Canon, VerseRef } from '@sillsdev/scripture'; import { isEqual, merge } from 'lodash-es'; +import { QuillEditorComponent } from 'ngx-quill'; import Quill, { Delta, EmitterSource, Range } from 'quill'; import QuillCursors from 'quill-cursors'; import { AuthType, getAuthType } from 'realtime-server/lib/esm/common/models/user'; @@ -38,6 +40,7 @@ import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { TextDoc, TextDocId } from '../../core/models/text-doc'; import { SFProjectService } from '../../core/sf-project.service'; import { TextDocService } from '../../core/text-doc.service'; +import { LynxInsightEditorObjectsComponent } from '../../translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component'; import { MultiCursorViewer } from '../../translate/editor/multi-viewer/multi-viewer.component'; import { attributeFromMouseEvent, @@ -96,8 +99,8 @@ export interface EmbedsByVerse { selector: 'app-text', templateUrl: './text.component.html', styleUrls: ['./text.component.scss'], - providers: [TextViewModel], // New instance for each text component - standalone: false + providers: [TextViewModel], + imports: [LynxInsightEditorObjectsComponent, QuillEditorComponent, NgClass, Dir] }) export class TextComponent implements AfterViewInit, OnDestroy { @Input() enablePresence: boolean = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/working-animated-indicator/working-animated-indicator.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/working-animated-indicator/working-animated-indicator.component.ts index 7d0a907b409..c99e89bf0a0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/working-animated-indicator/working-animated-indicator.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/working-animated-indicator/working-animated-indicator.component.ts @@ -1,10 +1,10 @@ import { Component } from '@angular/core'; -import { MatIconModule } from '@angular/material/icon'; +import { MatIcon } from '@angular/material/icon'; @Component({ selector: 'app-working-animated-indicator', templateUrl: './working-animated-indicator.component.html', styleUrls: ['./working-animated-indicator.component.scss'], - imports: [MatIconModule] + imports: [MatIcon] }) export class WorkingAnimatedIndicatorComponent {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/working-animated-indicator/working-animated-indicator.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/working-animated-indicator/working-animated-indicator.stories.ts index 3e9f5d380fc..ab1c8d9c4fe 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/shared/working-animated-indicator/working-animated-indicator.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/shared/working-animated-indicator/working-animated-indicator.stories.ts @@ -1,4 +1,4 @@ -import { MatIconModule } from '@angular/material/icon'; +import { MatIcon } from '@angular/material/icon'; import { componentWrapperDecorator, Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { WorkingAnimatedIndicatorComponent } from './working-animated-indicator.component'; @@ -7,7 +7,7 @@ export default { component: WorkingAnimatedIndicatorComponent, decorators: [ moduleMetadata({ - imports: [MatIconModule] + imports: [MatIcon] }), componentWrapperDecorator( (story: string) => ` diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync-progress/sync-progress.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync-progress/sync-progress.component.spec.ts index ada531f0db9..8c9f4327977 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync-progress/sync-progress.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync-progress/sync-progress.component.spec.ts @@ -7,12 +7,11 @@ import { firstValueFrom } from 'rxjs'; import { anything, mock, verify, when } from 'ts-mockito'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFProjectDoc } from '../../core/models/sf-project-doc'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { ProjectNotificationService } from '../../core/project-notification.service'; @@ -26,14 +25,10 @@ const mockedErrorReportingService = mock(ErrorReportingService); describe('SyncProgressComponent', () => { configureTestingModule(() => ({ - declarations: [HostComponent, SyncProgressComponent], - imports: [ - TestOnlineStatusModule.forRoot(), - UICommonModule, - TestTranslocoModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) - ], + imports: [SyncProgressComponent, getTestTranslocoModule(), HostComponent], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: ProjectNotificationService, useMock: mockedProjectNotificationService }, { provide: SFProjectService, useMock: mockedProjectService }, { provide: ErrorReportingService, useMock: mockedErrorReportingService }, @@ -137,7 +132,7 @@ describe('SyncProgressComponent', () => { @Component({ template: ``, - standalone: false + imports: [SyncProgressComponent] }) class HostComponent { projectDoc?: SFProjectDoc; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync-progress/sync-progress.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync-progress/sync-progress.component.ts index 40926f90497..fa2160e7920 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync-progress/sync-progress.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync-progress/sync-progress.component.ts @@ -1,5 +1,7 @@ +import { AsyncPipe } from '@angular/common'; import { Component, DestroyRef, EventEmitter, Input, Output } from '@angular/core'; -import { ProgressBarMode } from '@angular/material/progress-bar'; +import { MatProgressBar, ProgressBarMode } from '@angular/material/progress-bar'; +import { TranslocoModule } from '@ngneat/transloco'; import { OtJson0Op } from 'ot-json0'; import { isParatextRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; import { BehaviorSubject, map, merge, Observable } from 'rxjs'; @@ -35,7 +37,7 @@ enum SyncPhase { selector: 'app-sync-progress', templateUrl: './sync-progress.component.html', styleUrl: '../sync.component.scss', - standalone: false + imports: [TranslocoModule, MatProgressBar, AsyncPipe] }) export class SyncProgressComponent { @Input() showSyncStatus: boolean = true; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync.component.spec.ts index 5e8ee71fcf7..a2daed84bf5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync.component.spec.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { DebugElement, ErrorHandler } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; @@ -14,12 +13,11 @@ import { CommandError, CommandErrorCode } from 'xforge-common/command.service'; import { DialogService } from 'xforge-common/dialog.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFProjectDoc } from '../core/models/sf-project-doc'; import { SF_TYPE_REGISTRY } from '../core/models/sf-type-registry'; import { ParatextService } from '../core/paratext.service'; @@ -42,16 +40,10 @@ const mockedCookieService = mock(CookieService); describe('SyncComponent', () => { configureTestingModule(() => ({ - declarations: [SyncComponent, SyncProgressComponent], - imports: [ - CommonModule, - UICommonModule, - TestTranslocoModule, - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - NoticeComponent - ], + imports: [SyncComponent, SyncProgressComponent, getTestTranslocoModule(), NoticeComponent], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: AuthService, useMock: mockedAuthService }, { provide: ActivatedRoute, useMock: mockedActivatedRoute }, { provide: ErrorHandler, useMock: mockedErrorHandler }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync.component.ts index c91790ae38c..e4dce7a12f0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/sync/sync.component.ts @@ -1,5 +1,11 @@ import { Component, DestroyRef, OnInit } from '@angular/core'; +import { MatButton } from '@angular/material/button'; +import { MatCard } from '@angular/material/card'; +import { MatHint } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatTooltip } from '@angular/material/tooltip'; import { ActivatedRoute } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { firstValueFrom } from 'rxjs'; import { map, tap } from 'rxjs/operators'; @@ -15,6 +21,8 @@ import { environment } from '../../environments/environment'; import { SFProjectDoc } from '../core/models/sf-project-doc'; import { ParatextService } from '../core/paratext.service'; import { SFProjectService } from '../core/sf-project.service'; +import { NoticeComponent } from '../shared/notice/notice.component'; +import { SyncProgressComponent } from './sync-progress/sync-progress.component'; /** Reports as to whether a given project is actively syncing right now. */ export function isSFProjectSyncing(project: SFProjectProfile): boolean { return project.sync.queuedCount > 0; @@ -28,7 +36,7 @@ enum SyncErrorCodes { selector: 'app-sync', templateUrl: './sync.component.html', styleUrls: ['./sync.component.scss'], - standalone: false + imports: [TranslocoModule, NoticeComponent, MatCard, MatButton, MatIcon, SyncProgressComponent, MatHint, MatTooltip] }) export class SyncComponent extends DataLoadingComponent implements OnInit { isAppOnline: boolean = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/text-chooser-dialog/text-chooser-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/text-chooser-dialog/text-chooser-dialog.component.spec.ts index 1a19d2529f0..1405e8010b3 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/text-chooser-dialog/text-chooser-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/text-chooser-dialog/text-chooser-dialog.component.spec.ts @@ -1,7 +1,6 @@ -import { NgModule } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { VerseRef } from '@sillsdev/scripture'; import { CookieService } from 'ngx-cookie-service'; import { Delta } from 'quill'; @@ -16,16 +15,15 @@ import { firstValueFrom, of } from 'rxjs'; import { anything, instance, mock, spy, when } from 'ts-mockito'; import { DOCUMENT } from 'xforge-common/browser-globals'; import { UserDoc } from 'xforge-common/models/user-doc'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { ChildViewContainerComponent, configureTestingModule } from 'xforge-common/test-utils'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; -import { CheckingModule } from '../checking/checking.module'; import { SFProjectProfileDoc } from '../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../core/models/sf-type-registry'; import { TextDoc } from '../core/models/text-doc'; -import { SharedModule } from '../shared/shared.module'; +import { provideQuillRegistrations } from '../shared/text/quill-editor-registration/quill-providers'; import { TextChooserDialogComponent, TextChooserDialogData, TextSelection } from './text-chooser-dialog.component'; const mockedDocument = mock(Document); @@ -33,17 +31,15 @@ const mockedUserService = mock(UserService); describe('TextChooserDialogComponent', () => { configureTestingModule(() => ({ - imports: [ - DialogTestModule, - NoopAnimationsModule, - SharedModule.forRoot(), - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) - ], + imports: [getTestTranslocoModule()], providers: [ + provideQuillRegistrations(), + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: DOCUMENT, useMock: mockedDocument }, { provide: CookieService, useMock: mock(CookieService) }, - { provide: UserService, useMock: mockedUserService } + { provide: UserService, useMock: mockedUserService }, + provideNoopAnimations() ] })); @@ -336,11 +332,6 @@ describe('TextChooserDialogComponent', () => { })); }); -@NgModule({ - imports: [CheckingModule] -}) -class DialogTestModule {} - interface SimpleRange { start: number; end: number; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/text-chooser-dialog/text-chooser-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/text-chooser-dialog/text-chooser-dialog.component.ts index e22620703f2..e445d5d0b46 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/text-chooser-dialog/text-chooser-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/text-chooser-dialog/text-chooser-dialog.component.ts @@ -1,5 +1,18 @@ +import { Dir } from '@angular/cdk/bidi'; +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component, DestroyRef, ElementRef, Inject, Optional, ViewChild } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; +import { MatButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogConfig, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { TranslocoModule } from '@ngneat/transloco'; import { VerseRef } from '@sillsdev/scripture'; import { toVerseRef, VerseRefData } from 'realtime-server/lib/esm/scriptureforge/models/verse-ref-data'; import { fromEvent } from 'rxjs'; @@ -37,7 +50,18 @@ export interface TextSelection { @Component({ templateUrl: './text-chooser-dialog.component.html', styleUrls: ['./text-chooser-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + MatIcon, + TextComponent, + Dir, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class TextChooserDialogComponent { @ViewChild(TextComponent, { read: ElementRef }) scriptureText?: ElementRef; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-term-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-term-dialog.component.spec.ts index d50fcd7e5c8..0d9cb91de71 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-term-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-term-dialog.component.spec.ts @@ -1,7 +1,6 @@ -import { NgModule } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { VerseRef } from '@sillsdev/scripture'; import { cloneDeep } from 'lodash-es'; import { BiblicalTerm } from 'realtime-server/lib/esm/scriptureforge/models/biblical-term'; @@ -15,15 +14,14 @@ import { } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-user-config'; import { mock, when } from 'ts-mockito'; import { I18nService } from 'xforge-common/i18n.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { ChildViewContainerComponent, configureTestingModule, - matDialogCloseDelay, - TestTranslocoModule + getTestTranslocoModule, + matDialogCloseDelay } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { BiblicalTermDoc } from '../../core/models/biblical-term-doc'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SFProjectUserConfigDoc } from '../../core/models/sf-project-user-config-doc'; @@ -34,8 +32,12 @@ const mockedI18nService = mock(I18nService); describe('BiblicalTermDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, NoopAnimationsModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], - providers: [{ provide: I18nService, useMock: mockedI18nService }] + imports: [getTestTranslocoModule(), BiblicalTermDialogComponent], + providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), + { provide: I18nService, useMock: mockedI18nService }, + provideNoopAnimations() + ] })); it('should display the biblical term', fakeAsync(() => { @@ -185,12 +187,6 @@ describe('BiblicalTermDialogComponent', () => { })); }); -@NgModule({ - imports: [UICommonModule, TestTranslocoModule], - declarations: [BiblicalTermDialogComponent] -}) -class DialogTestModule {} - class TestEnvironment { readonly fixture: ComponentFixture; component?: BiblicalTermDialogComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-term-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-term-dialog.component.ts index d170ccb6db1..72c5117d461 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-term-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-term-dialog.component.ts @@ -1,8 +1,22 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { CdkTextareaAutosize } from '@angular/cdk/text-field'; import { Component, Inject } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatError, MatFormField, MatHint, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; +import { TranslocoModule } from '@ngneat/transloco'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; +import { AutofocusDirective } from 'xforge-common/autofocus.directive'; import { I18nService } from 'xforge-common/i18n.service'; import { BiblicalTermDoc } from '../../core/models/biblical-term-doc'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; @@ -18,7 +32,24 @@ export interface BiblicalTermDialogData { @Component({ templateUrl: './biblical-term-dialog.component.html', styleUrls: ['./biblical-term-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + MatFormField, + FormsModule, + ReactiveFormsModule, + MatLabel, + MatInput, + CdkTextareaAutosize, + AutofocusDirective, + MatHint, + MatError, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class BiblicalTermDialogComponent { definition: string = ''; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-terms.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-terms.component.spec.ts index 3cdcad0c3f2..22454e182f5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-terms.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-terms.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { VerseRef } from '@sillsdev/scripture'; import { obj } from 'realtime-server/lib/esm/common/utils/obj-path'; import { BiblicalTerm, getBiblicalTermDocId } from 'realtime-server/lib/esm/scriptureforge/models/biblical-term'; @@ -30,12 +30,11 @@ import { Locale } from 'xforge-common/models/i18n-locale'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { QueryParameters } from 'xforge-common/query-parameters'; import { noopDestroyRef } from 'xforge-common/realtime.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { BiblicalTermDoc } from '../../core/models/biblical-term-doc'; import { NoteThreadDoc } from '../../core/models/note-thread-doc'; @@ -55,19 +54,16 @@ const mockedUserService = mock(UserService); describe('BiblicalTermsComponent', () => { configureTestingModule(() => ({ - imports: [ - NoopAnimationsModule, - TestOnlineStatusModule.forRoot(), - TestTranslocoModule, - UICommonModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) - ], + imports: [getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: I18nService, useMock: mockedI18nService }, { provide: MatDialog, useMock: mockedMatDialog }, { provide: SFProjectService, useMock: mockedProjectService }, { provide: UserService, useMock: mockedUserService }, - { provide: OnlineStatusService, useClass: TestOnlineStatusService } + { provide: OnlineStatusService, useClass: TestOnlineStatusService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-terms.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-terms.component.ts index 56d75bf3914..1d2a50b273a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-terms.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/biblical-terms/biblical-terms.component.ts @@ -1,6 +1,27 @@ -import { CommonModule } from '@angular/common'; +import { NgFor, SlicePipe } from '@angular/common'; import { Component, DestroyRef, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { Sort } from '@angular/material/sort'; +import { FormsModule } from '@angular/forms'; +import { MatIconButton } from '@angular/material/button'; +import { MatOption } from '@angular/material/core'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { MatSelect } from '@angular/material/select'; +import { MatSort, MatSortHeader, Sort } from '@angular/material/sort'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatNoDataRow, + MatRow, + MatRowDef, + MatTable +} from '@angular/material/table'; +import { MatTooltip } from '@angular/material/tooltip'; import { TranslocoModule } from '@ngneat/transloco'; import { Canon, VerseRef } from '@sillsdev/scripture'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; @@ -24,7 +45,6 @@ import { I18nService } from 'xforge-common/i18n.service'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { objectId } from 'xforge-common/utils'; @@ -174,7 +194,35 @@ class Row { selector: 'app-biblical-terms', templateUrl: './biblical-terms.component.html', styleUrls: ['./biblical-terms.component.scss'], - imports: [CommonModule, TranslocoModule, UICommonModule] + imports: [ + NgFor, + FormsModule, + TranslocoModule, + MatTooltip, + SlicePipe, + MatIconButton, + MatFormField, + MatLabel, + MatSelect, + MatOption, + MatMenu, + MatMenuItem, + MatMenuTrigger, + MatIcon, + MatTable, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatCell, + MatCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + MatNoDataRow, + MatSort, + MatSortHeader + ] }) export class BiblicalTermsComponent extends DataLoadingComponent implements OnDestroy, OnInit { categories: string[] = []; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/confirm-sources/confirm-sources.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/confirm-sources/confirm-sources.component.ts index 1f3e65973b9..bde4cb17ff1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/confirm-sources/confirm-sources.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/confirm-sources/confirm-sources.component.ts @@ -1,6 +1,5 @@ import { Component, DestroyRef } from '@angular/core'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatIconModule } from '@angular/material/icon'; +import { MatIcon } from '@angular/material/icon'; import { TranslocoModule } from '@ngneat/transloco'; import { TrainingData } from 'realtime-server/lib/esm/scriptureforge/models/training-data'; import { merge, Subscription } from 'rxjs'; @@ -20,7 +19,7 @@ import { TrainingDataService } from '../training-data/training-data.service'; @Component({ selector: 'app-confirm-sources', - imports: [TranslocoModule, MatCheckboxModule, MatIconModule], + imports: [TranslocoModule, MatIcon], templateUrl: './confirm-sources.component.html', styleUrl: './confirm-sources.component.scss' }) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/confirm-sources/confirm-sources.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/confirm-sources/confirm-sources.stories.ts index a66ba5752ba..9c7615bedb4 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/confirm-sources/confirm-sources.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/confirm-sources/confirm-sources.stories.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { TranslocoModule } from '@ngneat/transloco'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; @@ -73,7 +72,7 @@ const meta: Meta = { component: ConfirmSourcesComponent, decorators: [ moduleMetadata({ - imports: [CommonModule, TranslocoModule, LanguageCodesConfirmationComponent], + imports: [TranslocoModule, LanguageCodesConfirmationComponent], providers: [ { provide: DraftSourcesService, useValue: instance(mockDraftService) }, { provide: ActivatedProjectService, useValue: instance(mockActivatedProject) }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.html index 5c17d00c168..8b549ff53c8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.html @@ -36,16 +36,20 @@

{{ t("select_alternate_project") }}

{{ t("i_understand_overwrite_book", { projectName, bookName }) }} - {{ - t("confirm_overwrite") - }} + {{ t("confirm_overwrite") }} @if (projectHasMissingChapters) { {{ t("i_understand_missing_chapters_are_created", { projectName, bookName }) }} - {{ - t("confirm_create_chapters") - }} + {{ t("confirm_create_chapters") }} } } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.spec.ts index 38015efe0bb..106cdb673b2 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.spec.ts @@ -4,17 +4,17 @@ import { Component } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { Route, RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { provideRouter, Route } from '@angular/router'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/models/text-info-permission'; import { of } from 'rxjs'; import { anything, mock, verify, when } from 'ts-mockito'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFUserProjectsService } from 'xforge-common/user-projects.service'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; @@ -31,8 +31,7 @@ const mockedDialogRef = mock(MatDialogRef); const mockedTextDocService = mock(TextDocService); @Component({ - template: `
Mock
`, - standalone: false + template: `
Mock
` }) class MockComponent {} @@ -42,13 +41,11 @@ let env: TestEnvironment; describe('DraftApplyDialogComponent', () => { configureTestingModule(() => ({ - imports: [ - TestTranslocoModule, - RouterModule.forRoot(ROUTES), - NoopAnimationsModule, - TestOnlineStatusModule.forRoot() - ], + imports: [getTestTranslocoModule()], providers: [ + provideRouter(ROUTES), + provideTestOnlineStatus(), + provideNoopAnimations(), { provide: SFUserProjectsService, useMock: mockedUserProjectsService }, { provide: SFProjectService, useMock: mockedProjectService }, { provide: UserService, useMock: mockedUserService }, @@ -283,7 +280,11 @@ class TestEnvironment { } get confirmOverwriteErrorMessage(): HTMLElement { - return this.fixture.nativeElement.querySelector('.form-error.visible'); + return this.fixture.nativeElement.querySelector('.form-error.overwrite-content-error.visible'); + } + + get confirmCreateChaptersErrorMessage(): HTMLElement { + return this.fixture.nativeElement.querySelector('.form-error.create-chapters-error.visible'); } set onlineStatus(online: boolean) { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.ts index c713db7e524..49c774cb93b 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.ts @@ -1,7 +1,18 @@ -import { CommonModule } from '@angular/common'; +import { AsyncPipe, NgClass } from '@angular/common'; import { Component, Inject, OnInit, ViewChild } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatButton } from '@angular/material/button'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatError } from '@angular/material/form-field'; +import { MatProgressBar } from '@angular/material/progress-bar'; import { TranslocoModule } from '@ngneat/transloco'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { Chapter, TextInfo } from 'realtime-server/lib/esm/scriptureforge/models/text-info'; @@ -9,19 +20,18 @@ import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/model import { BehaviorSubject, map } from 'rxjs'; import { I18nService } from 'xforge-common/i18n.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; import { SFUserProjectsService } from 'xforge-common/user-projects.service'; import { UserService } from 'xforge-common/user.service'; import { filterNullish } from 'xforge-common/util/rxjs-util'; -import { XForgeCommonModule } from 'xforge-common/xforge-common.module'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { TextDoc, TextDocId } from '../../../core/models/text-doc'; import { ParatextService } from '../../../core/paratext.service'; import { SFProjectService } from '../../../core/sf-project.service'; import { TextDocService } from '../../../core/text-doc.service'; import { ProjectSelectComponent } from '../../../project-select/project-select.component'; +import { NoticeComponent } from '../../../shared/notice/notice.component'; import { CustomValidatorState as CustomErrorState, SFValidators } from '../../../shared/sfvalidators'; -import { SharedModule } from '../../../shared/shared.module'; import { compareProjectsForSorting } from '../../../shared/utils'; export interface DraftApplyDialogResult { @@ -36,7 +46,24 @@ export interface DraftApplyDialogConfig { @Component({ selector: 'app-draft-apply-dialog', - imports: [UICommonModule, XForgeCommonModule, TranslocoModule, CommonModule, SharedModule], + imports: [ + RouterLinkDirective, + MatButton, + MatCheckbox, + MatProgressBar, + MatDialogContent, + MatDialogClose, + MatDialogActions, + MatDialogTitle, + MatError, + FormsModule, + ReactiveFormsModule, + TranslocoModule, + AsyncPipe, + NgClass, + NoticeComponent, + ProjectSelectComponent + ], templateUrl: './draft-apply-dialog.component.html', styleUrl: './draft-apply-dialog.component.scss' }) @@ -150,9 +177,9 @@ export class DraftApplyDialogComponent implements OnInit { }); } - addToProject(): void { + async addToProject(): Promise { this.addToProjectClicked = true; - this.validateProject(); + await this.validateProject(); if (!this.isAppOnline || !this.isFormValid || this.targetProjectId == null || !this.canEditProject) { return; } @@ -169,7 +196,7 @@ export class DraftApplyDialogComponent implements OnInit { this.canEditProject = false; this.targetBookExists = false; this.targetProject$.next(undefined); - this.validateProject(); + void this.validateProject(); return; } @@ -198,18 +225,21 @@ export class DraftApplyDialogComponent implements OnInit { } else { this.targetProject$.next(undefined); } - this.validateProject(); + void this.validateProject(); } close(): void { this.dialogRef.close(); } - private validateProject(): void { - // setTimeout prevents a "changed after checked" exception (may be removable after SF-3014) - setTimeout(() => { - this.isValid = this.getCustomErrorState() === CustomErrorState.None; - this.projectSelect?.customValidate(SFValidators.customValidator(this.getCustomErrorState())); + private async validateProject(): Promise { + await new Promise(resolve => { + // setTimeout prevents a "changed after checked" exception (may be removable after SF-3014) + setTimeout(() => { + this.isValid = this.getCustomErrorState() === CustomErrorState.None; + this.projectSelect?.customValidate(SFValidators.customValidator(this.getCustomErrorState())); + resolve(); + }); }); } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.stories.ts index 3573701ae13..bfcf4893daa 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.stories.ts @@ -1,6 +1,5 @@ -import { Component } from '@angular/core'; import { MatDialogRef } from '@angular/material/dialog'; -import { ActivatedRoute, RouterModule } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { Meta } from '@storybook/angular'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; import { BehaviorSubject } from 'rxjs'; @@ -14,9 +13,6 @@ import { SFProjectService } from '../../../core/sf-project.service'; import { TextDocService } from '../../../core/text-doc.service'; import { DraftApplyDialogComponent } from './draft-apply-dialog.component'; -@Component({ template: '' }) -class EmptyComponent {} - const mockedUserProjectService = mock(SFUserProjectsService); const mockedI18nService = mock(I18nService); const mockedDialogRef = mock(MatDialogRef); @@ -44,8 +40,6 @@ const meta: Meta = { export default meta; export const DraftApplyDialog = matDialogStory(DraftApplyDialogComponent, { - standaloneComponent: true, - imports: [RouterModule.forChild([{ path: 'projects', component: EmptyComponent }])], providers: [ { provide: ActivatedRoute, useValue: instance(mockActivatedRoute) }, { provide: SFUserProjectsService, useValue: instance(mockedUserProjectService) }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component.spec.ts index 40562eb67ac..a6bad1158aa 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component.spec.ts @@ -4,7 +4,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { BehaviorSubject } from 'rxjs'; import { anything, mock, when } from 'ts-mockito'; import { I18nService } from 'xforge-common/i18n.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { DraftApplyProgress, DraftApplyProgressDialogComponent } from './draft-apply-progress-dialog.component'; const mockI18nService = mock(I18nService); @@ -21,7 +21,7 @@ describe('DraftApplyProgressDialogComponent', () => { }); configureTestingModule(() => ({ - imports: [TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ { provide: I18nService, useMock: mockI18nService }, { provide: MatDialogRef, useMock: mockMatDialogRef }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component.ts index 3497fc47d4c..d4adb94c790 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component.ts @@ -1,10 +1,11 @@ -import { CommonModule } from '@angular/common'; import { Component, DestroyRef, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatButton } from '@angular/material/button'; +import { MAT_DIALOG_DATA, MatDialogActions, MatDialogContent, MatDialogRef } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressBar } from '@angular/material/progress-bar'; import { TranslocoModule } from '@ngneat/transloco'; import { Observable } from 'rxjs'; import { I18nService } from 'xforge-common/i18n.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; export interface DraftApplyProgress { bookNum: number; @@ -16,7 +17,7 @@ export interface DraftApplyProgress { @Component({ selector: 'app-draft-apply-progress', - imports: [CommonModule, UICommonModule, TranslocoModule], + imports: [MatButton, MatIcon, MatProgressBar, MatDialogContent, MatDialogActions, TranslocoModule], templateUrl: './draft-apply-progress-dialog.component.html', styleUrl: './draft-apply-progress-dialog.component.scss' }) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-download-button/draft-download-button.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-download-button/draft-download-button.component.spec.ts index c8ed50f868a..4653e4b5d60 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-download-button/draft-download-button.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-download-button/draft-download-button.component.spec.ts @@ -4,7 +4,7 @@ import { of, throwError } from 'rxjs'; import { anything, mock, verify, when } from 'ts-mockito'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { NoticeService } from 'xforge-common/notice.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { DraftGenerationService } from '../draft-generation.service'; import { DraftDownloadButtonComponent } from './draft-download-button.component'; @@ -15,7 +15,7 @@ const mockNoticeService: NoticeService = mock(NoticeService); describe('DraftDownloadButtonComponent', () => { configureTestingModule(() => ({ - imports: [TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ { provide: ActivatedProjectService, useMock: mockActivatedProjectService }, { provide: DraftGenerationService, useMock: mockDraftGenerationService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-download-button/draft-download-button.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-download-button/draft-download-button.component.ts index 7b01f212779..e9a9fe7a108 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-download-button/draft-download-button.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-download-button/draft-download-button.component.ts @@ -1,8 +1,7 @@ -import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { TranslocoModule } from '@ngneat/transloco'; import { Subscription } from 'rxjs'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; @@ -15,7 +14,7 @@ import { DraftGenerationService } from '../draft-generation.service'; selector: 'app-draft-download-button', templateUrl: './draft-download-button.component.html', styleUrls: ['./draft-download-button.component.scss'], - imports: [CommonModule, MatButtonModule, MatIconModule, MatProgressSpinnerModule, TranslocoModule] + imports: [MatButton, MatIcon, MatProgressSpinner, TranslocoModule] }) export class DraftDownloadButtonComponent { /** diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation-steps/draft-generation-steps.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation-steps/draft-generation-steps.component.spec.ts index e24c3b7e8bf..3e22dc7fd27 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation-steps/draft-generation-steps.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation-steps/draft-generation-steps.component.spec.ts @@ -5,7 +5,7 @@ import { provideHttpClientTesting } from '@angular/common/http/testing'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; import { BehaviorSubject, of } from 'rxjs'; import { anything, mock, verify, when } from 'ts-mockito'; @@ -15,8 +15,8 @@ import { createTestFeatureFlag, FeatureFlagService } from 'xforge-common/feature import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { ParatextProject } from '../../../core/models/paratext-project'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; @@ -48,8 +48,9 @@ describe('DraftGenerationStepsComponent', () => { when(mockActivatedProjectService.projectId).thenReturn('project01'); configureTestingModule(() => ({ - imports: [TestTranslocoModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), NoopAnimationsModule], + imports: [getTestTranslocoModule()], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), { provide: ActivatedProjectService, useMock: mockActivatedProjectService }, { provide: DraftSourcesService, useMock: mockDraftSourceService }, { provide: SFProjectService, useMock: mockProjectService }, @@ -62,7 +63,8 @@ describe('DraftGenerationStepsComponent', () => { { provide: UserService, useMock: mockUserService }, { provide: DialogService, useMock: mockDialogService }, provideHttpClient(withInterceptorsFromDi()), - provideHttpClientTesting() + provideHttpClientTesting(), + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation-steps/draft-generation-steps.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation-steps/draft-generation-steps.component.ts index cdd4386bd0e..968c07939a6 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation-steps/draft-generation-steps.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation-steps/draft-generation-steps.component.ts @@ -1,5 +1,23 @@ import { Component, DestroyRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'; -import { MatStepper } from '@angular/material/stepper'; +import { FormsModule } from '@angular/forms'; +import { MatButton } from '@angular/material/button'; +import { MatCard } from '@angular/material/card'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { MatStep, MatStepLabel, MatStepper, MatStepperIcon, MatStepperPrevious } from '@angular/material/stepper'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + MatTable +} from '@angular/material/table'; import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; import { isEqual } from 'lodash-es'; @@ -22,7 +40,6 @@ import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { ParatextProject } from '../../../core/models/paratext-project'; @@ -31,8 +48,8 @@ import { TrainingDataDoc } from '../../../core/models/training-data-doc'; import { ParatextService } from '../../../core/paratext.service'; import { SFProjectService } from '../../../core/sf-project.service'; import { BookMultiSelectComponent } from '../../../shared/book-multi-select/book-multi-select.component'; +import { NoticeComponent } from '../../../shared/notice/notice.component'; import { ProgressService, TextProgress } from '../../../shared/progress-service/progress.service'; -import { SharedModule } from '../../../shared/shared.module'; import { booksFromScriptureRange, projectLabel } from '../../../shared/utils'; import { NllbLanguageService } from '../../nllb-language.service'; import { ConfirmSourcesComponent } from '../confirm-sources/confirm-sources.component'; @@ -77,8 +94,28 @@ interface ProjectPendingUpdate { templateUrl: './draft-generation-steps.component.html', styleUrls: ['./draft-generation-steps.component.scss'], imports: [ - SharedModule, - UICommonModule, + FormsModule, + NoticeComponent, + MatButton, + MatCheckbox, + MatIcon, + MatCard, + MatProgressSpinner, + MatStepper, + MatStep, + MatStepLabel, + MatStepperIcon, + MatStepperPrevious, + MatTable, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatCell, + MatCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, TranslocoModule, TranslocoMarkupModule, BookMultiSelectComponent, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.spec.ts index 1d329c4ea87..b3d82b87d2a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.spec.ts @@ -1,7 +1,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatDialogRef, MatDialogState } from '@angular/material/dialog'; -import { RouterModule } from '@angular/router'; +import { provideRouter } from '@angular/router'; import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role'; import { createTestUser } from 'realtime-server/lib/esm/common/models/user-test-data'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; @@ -18,9 +18,9 @@ import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestTranslocoModule } from 'xforge-common/test-utils'; +import { getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { TrainingDataDoc } from '../../core/models/training-data-doc'; @@ -78,8 +78,10 @@ describe('DraftGenerationComponent', () => { } TestBed.configureTestingModule({ - imports: [TestOnlineStatusModule.forRoot(), RouterModule.forRoot([]), TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ + provideRouter([]), + provideTestOnlineStatus(), { provide: AuthService, useValue: mockAuthService }, { provide: DraftGenerationService, useValue: mockDraftGenerationService }, { provide: DraftSourcesService, useValue: mockDraftSourcesService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.ts index e55719368a5..09eaa9be0f9 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.ts @@ -1,10 +1,23 @@ -import { CommonModule } from '@angular/common'; +import { AsyncPipe } from '@angular/common'; import { HttpErrorResponse } from '@angular/common/http'; import { Component, DestroyRef, OnInit, ViewChild } from '@angular/core'; +import { MatAnchor, MatButton } from '@angular/material/button'; +import { + MatCard, + MatCardActions, + MatCardContent, + MatCardHeader, + MatCardSubtitle, + MatCardTitle +} from '@angular/material/card'; import { MatDialogRef, MatDialogState } from '@angular/material/dialog'; +import { MatExpansionPanel, MatExpansionPanelContent, MatExpansionPanelHeader } from '@angular/material/expansion'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressBar } from '@angular/material/progress-bar'; import { MatTabGroup } from '@angular/material/tabs'; -import { ActivatedRoute, Router, RouterModule } from '@angular/router'; +import { ActivatedRoute, RouterLink as NgRouterLink, Router } from '@angular/router'; import { TranslocoModule } from '@ngneat/transloco'; +import { NgCircleProgressModule } from 'ng-circle-progress'; import { TranslocoMarkupModule } from 'ngx-transloco-markup'; import { RouterLink } from 'ngx-transloco-markup-router-link'; import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role'; @@ -19,10 +32,10 @@ import { DialogService } from 'xforge-common/dialog.service'; import { ExternalUrlService } from 'xforge-common/external-url.service'; import { FeatureFlagService } from 'xforge-common/feature-flags/feature-flag.service'; import { I18nService } from 'xforge-common/i18n.service'; +import { L10nNumberPipe } from 'xforge-common/l10n-number.pipe'; import { L10nPercentPipe } from 'xforge-common/l10n-percent.pipe'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { filterNullish, quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { issuesEmailTemplate } from 'xforge-common/utils'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; @@ -31,7 +44,7 @@ import { SFProjectService } from '../../core/sf-project.service'; import { BuildDto } from '../../machine-api/build-dto'; import { BuildStates } from '../../machine-api/build-states'; import { ServalProjectComponent } from '../../serval-administration/serval-project.component'; -import { SharedModule } from '../../shared/shared.module'; +import { NoticeComponent } from '../../shared/notice/notice.component'; import { projectLabel } from '../../shared/utils'; import { WorkingAnimatedIndicatorComponent } from '../../shared/working-animated-indicator/working-animated-indicator.component'; import { NllbLanguageService } from '../nllb-language.service'; @@ -54,12 +67,26 @@ import { SupportedBackTranslationLanguagesDialogComponent } from './supported-ba templateUrl: './draft-generation.component.html', styleUrls: ['./draft-generation.component.scss'], imports: [ - CommonModule, - UICommonModule, - RouterModule, + AsyncPipe, + MatAnchor, + MatButton, + MatIcon, + MatCard, + MatCardHeader, + MatCardTitle, + MatCardSubtitle, + MatCardContent, + MatCardActions, + MatProgressBar, + MatExpansionPanel, + MatExpansionPanelHeader, + MatExpansionPanelContent, + NgRouterLink, TranslocoModule, TranslocoMarkupModule, - SharedModule, + NoticeComponent, + NgCircleProgressModule, + L10nNumberPipe, L10nPercentPipe, WorkingAnimatedIndicatorComponent, DraftGenerationStepsComponent, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.service.spec.ts index 236b00f711d..83b52b4b29b 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.service.spec.ts @@ -16,9 +16,9 @@ import { first } from 'rxjs/operators'; import { anything, mock, verify } from 'ts-mockito'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { TextDocSource } from '../../core/models/text-doc'; import { BuildDto } from '../../machine-api/build-dto'; @@ -34,8 +34,9 @@ describe('DraftGenerationService', () => { let testOnlineStatusService: TestOnlineStatusService; configureTestingModule(() => ({ - imports: [TestOnlineStatusModule.forRoot(), TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), { provide: NoticeService, useMock: mockNoticeService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService } ] diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts index 6d25de5df3f..3f59c5d2b12 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { provideRouter } from '@angular/router'; import { createTestUserProfile } from 'realtime-server/lib/esm/common/models/user-test-data'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; @@ -12,8 +12,8 @@ import { createTestFeatureFlag, FeatureFlagService } from 'xforge-common/feature import { I18nService } from 'xforge-common/i18n.service'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { UserProfileDoc } from 'xforge-common/models/user-profile-doc'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../../../core/models/sf-type-registry'; @@ -44,13 +44,10 @@ describe('DraftHistoryEntryComponent', () => { let fixture: ComponentFixture; configureTestingModule(() => ({ - imports: [ - NoopAnimationsModule, - TestTranslocoModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - RouterModule.forRoot([]) - ], + imports: [getTestTranslocoModule()], providers: [ + provideRouter([]), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: DraftGenerationService, useMock: mockedDraftGenerationService }, { provide: I18nService, useMock: mockedI18nService }, { provide: SFProjectService, useMock: mockedSFProjectService }, @@ -58,7 +55,8 @@ describe('DraftHistoryEntryComponent', () => { { provide: TrainingDataService, useMock: mockedTrainingDataService }, { provide: ActivatedProjectService, useMock: mockedActivatedProjectService }, { provide: FeatureFlagService, useMock: mockedFeatureFlagsService }, - { provide: DraftOptionsService, useMock: mockedDraftOptionsService } + { provide: DraftOptionsService, useMock: mockedDraftOptionsService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts index 37ac7bd207b..9a798d25b10 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts @@ -1,10 +1,26 @@ -import { CommonModule } from '@angular/common'; +import { NgClass } from '@angular/common'; import { Component, DestroyRef, Input } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTableModule } from '@angular/material/table'; -import { RouterModule } from '@angular/router'; +import { MatButton } from '@angular/material/button'; +import { + MatExpansionPanel, + MatExpansionPanelDescription, + MatExpansionPanelHeader, + MatExpansionPanelTitle +} from '@angular/material/expansion'; +import { MatIcon } from '@angular/material/icon'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + MatTable +} from '@angular/material/table'; +import { RouterLink } from '@angular/router'; import { TranslocoModule } from '@ngneat/transloco'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { FeatureFlagService } from 'xforge-common/feature-flags/feature-flag.service'; @@ -46,15 +62,27 @@ interface TrainingConfigurationRow { @Component({ selector: 'app-draft-history-entry', imports: [ - CommonModule, + NgClass, DraftDownloadButtonComponent, DraftPreviewBooksComponent, - MatButtonModule, - MatExpansionModule, - MatIconModule, - MatTableModule, + MatButton, + MatExpansionPanel, + MatExpansionPanelDescription, + MatExpansionPanelHeader, + MatExpansionPanelTitle, + MatIcon, + MatTable, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatCell, + MatCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, TranslocoModule, - RouterModule + RouterLink ], templateUrl: './draft-history-entry.component.html', styleUrl: './draft-history-entry.component.scss' diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-list.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-list.component.spec.ts index eee27546727..d2b081f4524 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-list.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-list.component.spec.ts @@ -1,13 +1,13 @@ import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { provideRouter } from '@angular/router'; import { BehaviorSubject, of } from 'rxjs'; import { anything, mock, when } from 'ts-mockito'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { createTestFeatureFlag, FeatureFlagService } from 'xforge-common/feature-flags/feature-flag.service'; import { I18nService } from 'xforge-common/i18n.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SF_TYPE_REGISTRY } from '../../../core/models/sf-type-registry'; import { ProjectNotificationService } from '../../../core/project-notification.service'; @@ -27,20 +27,18 @@ const mockedFeatureFlagsService = mock(FeatureFlagService); describe('DraftHistoryListComponent', () => { configureTestingModule(() => ({ - imports: [ - NoopAnimationsModule, - TestTranslocoModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - RouterModule.forRoot([]) - ], + imports: [getTestTranslocoModule()], providers: [ + provideRouter([]), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: ActivatedProjectService, useMock: mockedActivatedProjectService }, { provide: DraftGenerationService, useMock: mockedDraftGenerationService }, { provide: I18nService, useMock: mockedI18nService }, { provide: ProjectNotificationService, useMock: mockedProjectNotificationService }, { provide: SFProjectService, useMock: mockedSFProjectService }, { provide: UserService, useMock: mockedUserService }, - { provide: FeatureFlagService, useMock: mockedFeatureFlagsService } + { provide: FeatureFlagService, useMock: mockedFeatureFlagsService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-list.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-list.component.ts index 1d2f98341a9..dc39d52e7ef 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-list.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-list.component.ts @@ -1,5 +1,4 @@ import { Component, DestroyRef } from '@angular/core'; -import { MatIconModule } from '@angular/material/icon'; import { TranslocoModule, TranslocoService } from '@ngneat/transloco'; import ObjectID from 'bson-objectid'; import { take } from 'rxjs'; @@ -16,7 +15,7 @@ import { DraftHistoryEntryComponent } from './draft-history-entry/draft-history- @Component({ selector: 'app-draft-history-list', - imports: [MatIconModule, DraftHistoryEntryComponent, TranslocoModule, NoticeComponent], + imports: [DraftHistoryEntryComponent, TranslocoModule, NoticeComponent], templateUrl: './draft-history-list.component.html', styleUrl: './draft-history-list.component.scss' }) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-information/draft-information.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-information/draft-information.component.ts index dd55be3c3c5..02fa705dada 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-information/draft-information.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-information/draft-information.component.ts @@ -1,13 +1,10 @@ -import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; import { SystemRole } from 'realtime-server/lib/esm/common/models/system-role'; import { AuthService } from 'xforge-common/auth.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { BuildDto } from '../../../machine-api/build-dto'; @Component({ selector: 'app-draft-information', - imports: [UICommonModule, CommonModule], templateUrl: './draft-information.component.html' }) export class DraftInformationComponent { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.spec.ts index d94394f518f..0439a900099 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.spec.ts @@ -3,7 +3,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatDialogRef } from '@angular/material/dialog'; import { MatMenuHarness } from '@angular/material/menu/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { Router } from '@angular/router'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; @@ -13,7 +13,7 @@ import { anything, capture, instance, mock, verify, when } from 'ts-mockito'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { DialogService } from 'xforge-common/dialog.service'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { SFProjectService } from '../../../core/sf-project.service'; @@ -37,7 +37,7 @@ describe('DraftPreviewBooks', () => { let env: TestEnvironment; configureTestingModule(() => ({ - imports: [TestTranslocoModule, NoopAnimationsModule], + imports: [getTestTranslocoModule()], providers: [ { provide: ActivatedProjectService, useMock: mockedActivatedProjectService }, { provide: SFProjectService, useMock: mockedProjectService }, @@ -46,7 +46,8 @@ describe('DraftPreviewBooks', () => { { provide: DialogService, useMock: mockedDialogService }, { provide: TextDocService, useMock: mockedTextService }, { provide: ErrorReportingService, useMock: mockedErrorReportingService }, - { provide: Router, useMock: mockedRouter } + { provide: Router, useMock: mockedRouter }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.ts index f2bfbd5fca5..39d5fcce0fa 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.ts @@ -1,7 +1,10 @@ -import { CommonModule } from '@angular/common'; +import { AsyncPipe } from '@angular/common'; import { Component, Input } from '@angular/core'; +import { MatButtonToggle, MatButtonToggleGroup } from '@angular/material/button-toggle'; import { MatDialogRef } from '@angular/material/dialog'; -import { Router, RouterModule } from '@angular/router'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { Router } from '@angular/router'; import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; @@ -11,7 +14,6 @@ import { BehaviorSubject, firstValueFrom, map, Observable, tap } from 'rxjs'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { DialogService } from 'xforge-common/dialog.service'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { UserService } from 'xforge-common/user.service'; import { filterNullish } from 'xforge-common/util/rxjs-util'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; @@ -43,7 +45,16 @@ export interface BookWithDraft { selector: 'app-draft-preview-books', templateUrl: './draft-preview-books.component.html', styleUrls: ['./draft-preview-books.component.scss'], - imports: [CommonModule, UICommonModule, RouterModule, TranslocoModule] + imports: [ + AsyncPipe, + MatButtonToggle, + MatMenu, + MatMenuItem, + MatMenuTrigger, + MatIcon, + MatButtonToggleGroup, + TranslocoModule + ] }) export class DraftPreviewBooksComponent { @Input() build: BuildDto | undefined; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.component.spec.ts index 0cc06dfe590..168f959dc73 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.component.spec.ts @@ -2,7 +2,7 @@ import { OverlayContainer } from '@angular/cdk/overlay'; import { DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { SFProject } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { createTestProject } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; import { TrainingData } from 'realtime-server/lib/esm/scriptureforge/models/training-data'; @@ -20,11 +20,11 @@ import { FileType } from 'xforge-common/models/file-offline-data'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFUserProjectsService } from 'xforge-common/user-projects.service'; import { hasData, notNull, WithData } from '../../../../type-utils'; import { ParatextProject } from '../../../core/models/paratext-project'; @@ -72,14 +72,10 @@ when(mockTrainingDataQuery.remoteDocChanges$).thenReturn(of()); describe('DraftSourcesComponent', () => { configureTestingModule(() => ({ - imports: [ - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - NoopAnimationsModule, - TestTranslocoModule - ], - declarations: [], + imports: [getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: ParatextService, useMock: mockedParatextService }, { provide: ActivatedProjectService, useMock: mockedActivatedProjectService }, { provide: NoticeService, useMock: mockedNoticeService }, @@ -92,7 +88,8 @@ describe('DraftSourcesComponent', () => { { provide: DialogService, useMock: mockedDialogService }, { provide: TrainingDataService, useMock: mockTrainingDataService }, { provide: ErrorReportingService, useMock: mock(ErrorReportingService) }, - { provide: FileService, useMock: mockedFileService } + { provide: FileService, useMock: mockedFileService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.component.ts index 7c9be1ddea1..8cec385661d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.component.ts @@ -1,12 +1,11 @@ -import { CommonModule } from '@angular/common'; +import { KeyValuePipe, NgTemplateOutlet } from '@angular/common'; import { Component, DestroyRef, EventEmitter } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCardModule } from '@angular/material/card'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatRippleModule } from '@angular/material/core'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatIconModule } from '@angular/material/icon'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatButton } from '@angular/material/button'; +import { MatCard, MatCardActions, MatCardContent, MatCardHeader, MatCardTitle } from '@angular/material/card'; +import { MatRipple } from '@angular/material/core'; +import { MatError } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { Router } from '@angular/router'; import { TranslocoModule } from '@ngneat/transloco'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; @@ -26,12 +25,12 @@ import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { SFUserProjectsService } from 'xforge-common/user-projects.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; -import { XForgeCommonModule } from 'xforge-common/xforge-common.module'; import { hasData, notNull } from '../../../../type-utils'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { TrainingDataDoc } from '../../../core/models/training-data-doc'; import { ParatextService, SelectableProject, SelectableProjectWithLanguageCode } from '../../../core/paratext.service'; import { SFProjectService } from '../../../core/sf-project.service'; +import { ProjectSelectComponent } from '../../../project-select/project-select.component'; import { ConfirmOnLeave } from '../../../shared/project-router.guard'; import { projectLabel } from '../../../shared/utils'; import { isSFProjectSyncing } from '../../../sync/sync.component'; @@ -43,6 +42,7 @@ import { import { LanguageCodesConfirmationComponent } from '../language-codes-confirmation/language-codes-confirmation.component'; import { TrainingDataMultiSelectComponent } from '../training-data/training-data-multi-select.component'; import { TrainingDataService } from '../training-data/training-data.service'; + /** Status for a project, which may or may not be at SF. */ export interface ProjectStatus { shortName: string; @@ -55,18 +55,22 @@ export interface ProjectStatus { @Component({ selector: 'app-draft-sources', imports: [ - MatButtonModule, - MatFormFieldModule, - MatIconModule, - XForgeCommonModule, - MatRippleModule, - MatCardModule, - CommonModule, + NgTemplateOutlet, + KeyValuePipe, + MatButton, + MatIcon, + MatRipple, + MatCard, + MatCardActions, + MatCardHeader, + MatCardContent, + MatCardTitle, + MatError, TranslocoModule, - MatCheckboxModule, - MatProgressSpinnerModule, + MatProgressSpinner, LanguageCodesConfirmationComponent, - TrainingDataMultiSelectComponent + TrainingDataMultiSelectComponent, + ProjectSelectComponent ], templateUrl: './draft-sources.component.html', styleUrl: './draft-sources.component.scss' diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.stories.ts index 03216b7c20f..34fde1fb2d2 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-sources/draft-sources.stories.ts @@ -1,5 +1,4 @@ import { DestroyRef } from '@angular/core'; -import { MatDialogModule } from '@angular/material/dialog'; import { Router } from '@angular/router'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { expect, userEvent, waitFor, within } from '@storybook/test'; @@ -156,7 +155,6 @@ export default { component: DraftSourcesComponent, decorators: [ moduleMetadata({ - imports: [MatDialogModule], providers: [ { provide: ActivatedProjectService, useValue: instance(mockedActivatedProjectService) }, { provide: DestroyRef, useValue: instance(mockedDestroyRef) }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.spec.ts index d0cbddd0995..3f2e560dd75 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.spec.ts @@ -2,7 +2,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { Location } from '@angular/common'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatRadioButtonHarness } from '@angular/material/radio/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { ActivatedRoute } from '@angular/router'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; import { TextInfo } from 'realtime-server/lib/esm/scriptureforge/models/text-info'; @@ -19,10 +19,10 @@ import { I18nService } from 'xforge-common/i18n.service'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../../core/models/sf-type-registry'; @@ -31,7 +31,7 @@ import { BuildDto } from '../../../machine-api/build-dto'; import { BuildStates } from '../../../machine-api/build-states'; import { QuotationAnalysis } from '../../../machine-api/quotation-denormalization'; import { ServalAdministrationService } from '../../../serval-administration/serval-administration.service'; -import { SharedModule } from '../../../shared/shared.module'; +import { provideQuillRegistrations } from '../../../shared/text/quill-editor-registration/quill-providers'; import { EDITOR_READY_TIMEOUT } from '../../../shared/text/text.component'; import { DraftGenerationService } from '../draft-generation.service'; import { DraftHandlingService } from '../draft-handling.service'; @@ -51,15 +51,11 @@ const mockedDialogService = mock(DialogService); describe('DraftUsfmFormatComponent', () => { configureTestingModule(() => ({ - imports: [ - DraftUsfmFormatComponent, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - NoopAnimationsModule, - TestTranslocoModule, - TestOnlineStatusModule.forRoot(), - SharedModule.forRoot() - ], + imports: [DraftUsfmFormatComponent, getTestTranslocoModule()], providers: [ + provideQuillRegistrations(), + provideTestRealtime(SF_TYPE_REGISTRY), + provideTestOnlineStatus(), { provide: DraftHandlingService, useMock: mockedDraftHandlingService }, { provide: DraftGenerationService, useMock: mockedDraftGenerationService }, { provide: ActivatedProjectService, useMock: mockedActivatedProjectService }, @@ -71,7 +67,8 @@ describe('DraftUsfmFormatComponent', () => { { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: I18nService, useMock: mockI18nService }, { provide: NoticeService, useMock: mockedNoticeService }, - { provide: DialogService, useMock: mockedDialogService } + { provide: DialogService, useMock: mockedDialogService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.ts index f43fdfbd966..4d06bf530d4 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.ts @@ -1,14 +1,11 @@ -import { CommonModule, Location } from '@angular/common'; +import { Location } from '@angular/common'; import { AfterViewInit, Component, DestroyRef, EventEmitter, ViewChild } from '@angular/core'; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCardModule } from '@angular/material/card'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatIconModule } from '@angular/material/icon'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatRadioModule } from '@angular/material/radio'; -import { MatSelectModule } from '@angular/material/select'; +import { MatButton } from '@angular/material/button'; +import { MatCard, MatCardContent, MatCardHeader, MatCardTitle } from '@angular/material/card'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { MatRadioButton, MatRadioGroup } from '@angular/material/radio'; import { ActivatedRoute } from '@angular/router'; import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; @@ -32,8 +29,9 @@ import { TextDocId } from '../../../core/models/text-doc'; import { SFProjectService } from '../../../core/sf-project.service'; import { QuotationAnalysis } from '../../../machine-api/quotation-denormalization'; import { ServalAdministrationService } from '../../../serval-administration/serval-administration.service'; +import { BookChapterChooserComponent } from '../../../shared/book-chapter-chooser/book-chapter-chooser.component'; +import { NoticeComponent } from '../../../shared/notice/notice.component'; import { ConfirmOnLeave } from '../../../shared/project-router.guard'; -import { SharedModule } from '../../../shared/shared.module'; import { TextComponent } from '../../../shared/text/text.component'; import { DraftGenerationService } from '../draft-generation.service'; import { DraftHandlingService } from '../draft-handling.service'; @@ -41,19 +39,21 @@ import { DraftHandlingService } from '../draft-handling.service'; @Component({ selector: 'app-draft-usfm-format', imports: [ - MatButtonModule, - MatCardModule, - MatCheckboxModule, - MatIconModule, - MatProgressSpinnerModule, - MatSelectModule, - CommonModule, + MatButton, + MatCard, + MatCardHeader, + MatCardContent, + MatCardTitle, + MatIcon, + MatProgressSpinner, FormsModule, ReactiveFormsModule, - SharedModule, + BookChapterChooserComponent, + NoticeComponent, + TextComponent, TranslocoModule, - MatFormFieldModule, - MatRadioModule + MatRadioGroup, + MatRadioButton ], templateUrl: './draft-usfm-format.component.html', styleUrl: './draft-usfm-format.component.scss' diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.component.spec.ts index bb2f9d55347..0040028f0fb 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.component.spec.ts @@ -6,8 +6,7 @@ import { anything, mock, when } from 'ts-mockito'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { AuthService } from 'xforge-common/auth.service'; import { I18nService } from 'xforge-common/i18n.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { NoticeComponent } from '../../../shared/notice/notice.component'; import { DraftSourcesAsSelectableProjectArrays } from '../draft-utils'; @@ -22,7 +21,7 @@ describe('LanguageCodesConfirmationComponent', () => { const mockAuthService = mock(AuthService); configureTestingModule(() => ({ - imports: [TestTranslocoModule, UICommonModule, NoticeComponent, TranslocoMarkupComponent], + imports: [getTestTranslocoModule(), NoticeComponent, TranslocoMarkupComponent], providers: [ { provide: I18nService, useMock: mockI18nService }, { provide: ActivatedProjectService, useMock: mockActivatedProject }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.component.ts index 23231ee1074..b12ac01f8a6 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.component.ts @@ -1,10 +1,8 @@ -import { CommonModule } from '@angular/common'; import { Component, DestroyRef, EventEmitter, Input, Output } from '@angular/core'; -import { MatCheckboxChange } from '@angular/material/checkbox'; +import { MatCheckbox, MatCheckboxChange } from '@angular/material/checkbox'; import { TranslocoModule } from '@ngneat/transloco'; import { TranslocoMarkupComponent } from 'ngx-transloco-markup'; import { I18nKeyForComponent, I18nService } from 'xforge-common/i18n.service'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { issuesEmailTemplate } from 'xforge-common/utils'; import { environment } from '../../../../environments/environment'; @@ -14,7 +12,7 @@ import { DraftSourcesAsSelectableProjectArrays, normalizeLanguageCodeToISO639_3 @Component({ selector: 'app-language-codes-confirmation', - imports: [CommonModule, TranslocoModule, TranslocoMarkupComponent, UICommonModule, NoticeComponent], + imports: [TranslocoModule, TranslocoMarkupComponent, MatCheckbox, NoticeComponent], templateUrl: './language-codes-confirmation.component.html', styleUrl: './language-codes-confirmation.component.scss' }) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.stories.ts index 40256aec549..c728bc1b216 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/language-codes-confirmation/language-codes-confirmation.stories.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { TranslocoModule } from '@ngneat/transloco'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { expect, within } from '@storybook/test'; @@ -50,7 +49,7 @@ const meta: Meta = { component: LanguageCodesConfirmationComponent, decorators: [ moduleMetadata({ - imports: [CommonModule, TranslocoModule, TranslocoMarkupComponent, LanguageCodesConfirmationComponent], + imports: [TranslocoModule, TranslocoMarkupComponent, LanguageCodesConfirmationComponent], providers: [ { provide: ActivatedProjectService, useValue: instance(mockActivatedProject) }, { provide: AuthService, useValue: instance(mockAuthService) }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/supported-back-translation-languages-dialog/supported-back-translation-languages-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/supported-back-translation-languages-dialog/supported-back-translation-languages-dialog.component.spec.ts index 262a596a81f..f776a2551dd 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/supported-back-translation-languages-dialog/supported-back-translation-languages-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/supported-back-translation-languages-dialog/supported-back-translation-languages-dialog.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { mock, when } from 'ts-mockito'; import { I18nService } from 'xforge-common/i18n.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { NllbLanguage } from '../../nllb-languages'; import { SupportedBackTranslationLanguagesDialogComponent } from './supported-back-translation-languages-dialog.component'; @@ -13,7 +13,7 @@ describe('SupportedBackTranslationLanguagesDialogComponent', () => { const language: NllbLanguage = { iso639_1: 'xy', iso639_2t: 'xyz', iso639_2b: 'xyz', name: 'TestLanguageName' }; configureTestingModule(() => ({ - imports: [TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [{ provide: I18nService, useMock: mockI18nService }] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/supported-back-translation-languages-dialog/supported-back-translation-languages-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/supported-back-translation-languages-dialog/supported-back-translation-languages-dialog.component.ts index 8aad605d458..4337b62185c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/supported-back-translation-languages-dialog/supported-back-translation-languages-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/supported-back-translation-languages-dialog/supported-back-translation-languages-dialog.component.ts @@ -1,14 +1,13 @@ import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatDialogModule } from '@angular/material/dialog'; -import { MatIconModule } from '@angular/material/icon'; +import { MatDialogContent, MatDialogTitle } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; import { TranslocoModule } from '@ngneat/transloco'; import { I18nService } from 'xforge-common/i18n.service'; import { NLLB_LANGUAGES, NllbLanguage, NllbLanguageDict } from '../../nllb-languages'; @Component({ selector: 'app-supported-back-translation-languages-dialog', - imports: [MatIconModule, MatDialogModule, MatButtonModule, TranslocoModule], + imports: [MatIcon, MatDialogTitle, MatDialogContent, TranslocoModule], templateUrl: './supported-back-translation-languages-dialog.component.html', styleUrls: ['./supported-back-translation-languages-dialog.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-multi-select.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-multi-select.component.spec.ts index 49b6ad75473..8828f2addf5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-multi-select.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-multi-select.component.spec.ts @@ -9,7 +9,7 @@ import { ActivatedProjectService } from 'xforge-common/activated-project.service import { DialogService } from 'xforge-common/dialog.service'; import { I18nService } from 'xforge-common/i18n.service'; import { Locale } from 'xforge-common/models/i18n-locale'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { TrainingDataMultiSelectComponent } from './training-data-multi-select.component'; @@ -47,7 +47,7 @@ describe('TrainingDataMultiSelectComponent', () => { let mockTrainingData: TrainingData[]; configureTestingModule(() => ({ - imports: [TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ { provide: ActivatedProjectService, useMock: mockActivatedProjectService }, { provide: DialogService, useMock: mockDialogService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-multi-select.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-multi-select.component.ts index a83925ae746..ae15c6a26b4 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-multi-select.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-multi-select.component.ts @@ -1,9 +1,8 @@ -import { CommonModule } from '@angular/common'; import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; +import { MatButton, MatIconButton } from '@angular/material/button'; import { MatDialogConfig } from '@angular/material/dialog'; -import { MatIconModule } from '@angular/material/icon'; -import { MatListModule } from '@angular/material/list'; +import { MatIcon } from '@angular/material/icon'; +import { MatList, MatListItem } from '@angular/material/list'; import { TranslocoModule } from '@ngneat/transloco'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; @@ -12,7 +11,6 @@ import { TrainingData } from 'realtime-server/lib/esm/scriptureforge/models/trai import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { DialogService } from 'xforge-common/dialog.service'; import { UserService } from 'xforge-common/user.service'; -import { SharedModule } from '../../../shared/shared.module'; import { TrainingDataUploadDialogComponent, TrainingDataUploadDialogData @@ -21,7 +19,7 @@ import { @Component({ selector: 'app-training-data-multi-select', templateUrl: './training-data-multi-select.component.html', - imports: [CommonModule, MatButtonModule, MatIconModule, SharedModule, TranslocoModule, MatListModule], + imports: [MatButton, MatIcon, MatIconButton, MatList, MatListItem, TranslocoModule], styleUrls: ['./training-data-multi-select.component.scss'] }) export class TrainingDataMultiSelectComponent { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-upload-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-upload-dialog.component.spec.ts index 695569771bf..18840b0e8fe 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-upload-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-upload-dialog.component.spec.ts @@ -1,7 +1,7 @@ import { OverlayContainer } from '@angular/cdk/overlay'; import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { NgModule, NgZone } from '@angular/core'; +import { NgZone } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { ngfModule } from 'angular-file'; @@ -9,7 +9,7 @@ import { TrainingData } from 'realtime-server/lib/esm/scriptureforge/models/trai import { anything, mock, when } from 'ts-mockito'; import { FileService } from 'xforge-common/file.service'; import { FileType } from 'xforge-common/models/file-offline-data'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { TrainingDataDoc } from '../../../core/models/training-data-doc'; import { TrainingDataFileUpload, TrainingDataUploadDialogComponent } from './training-data-upload-dialog.component'; @@ -21,8 +21,10 @@ const mockedUserService = mock(UserService); describe('TrainingDataUploadDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule], + imports: [ngfModule, getTestTranslocoModule()], providers: [ + provideHttpClient(withInterceptorsFromDi()), + provideHttpClientTesting(), { provide: FileService, useMock: mockedFileService }, { provide: TrainingDataService, useMock: mockedTrainingDataService }, { provide: UserService, useMock: mockedUserService } @@ -98,12 +100,6 @@ describe('TrainingDataUploadDialogComponent', () => { }); }); -@NgModule({ - imports: [ngfModule, TestTranslocoModule], - providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}) -class DialogTestModule {} - class TestEnvironment { static uploadFiles: File[] = [new File([], 'test.csv')]; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-upload-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-upload-dialog.component.ts index 206e4775210..20298e23f95 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-upload-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data-upload-dialog.component.ts @@ -1,10 +1,17 @@ -import { CommonModule } from '@angular/common'; +import { NgClass } from '@angular/common'; import { AfterViewInit, Component, ElementRef, Inject, ViewChild } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCheckbox, MatCheckboxModule } from '@angular/material/checkbox'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { MatIconModule } from '@angular/material/icon'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatButton } from '@angular/material/button'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { TranslocoModule } from '@ngneat/transloco'; import { TrainingData } from 'realtime-server/lib/esm/scriptureforge/models/training-data'; import { DialogService } from 'xforge-common/dialog.service'; @@ -14,7 +21,7 @@ import { FileType } from 'xforge-common/models/file-offline-data'; import { UserService } from 'xforge-common/user.service'; import { objectId } from 'xforge-common/utils'; import { TrainingDataDoc } from '../../../core/models/training-data-doc'; -import { SharedModule } from '../../../shared/shared.module'; +import { InfoComponent } from '../../../shared/info/info.component'; export interface TrainingDataUploadDialogData { projectId: string; @@ -31,13 +38,16 @@ export interface TrainingDataFileUpload { selector: 'app-training-data-upload-dialog', templateUrl: './training-data-upload-dialog.component.html', imports: [ - CommonModule, - MatButtonModule, - MatCheckboxModule, - MatDialogModule, - MatIconModule, - MatProgressSpinnerModule, - SharedModule, + NgClass, + MatButton, + MatCheckbox, + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatDialogClose, + MatIcon, + MatProgressSpinner, + InfoComponent, TranslocoModule ], styleUrls: ['./training-data-upload-dialog.component.scss'] diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data.service.spec.ts index c5c426880e8..498019beb6a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/training-data/training-data.service.spec.ts @@ -6,7 +6,7 @@ import { FileType } from 'xforge-common/models/file-offline-data'; import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { Snapshot } from 'xforge-common/models/snapshot'; import { noopDestroyRef } from 'xforge-common/realtime.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { TypeRegistry } from 'xforge-common/type-registry'; @@ -45,8 +45,10 @@ describe('TrainingDataService', () => { const mockedFileService = mock(FileService); configureTestingModule(() => ({ - imports: [TestRealtimeModule.forRoot(new TypeRegistry([TrainingDataDoc], [FileType.TrainingData], []))], - providers: [{ provide: FileService, useMock: mockedFileService }] + providers: [ + provideTestRealtime(new TypeRegistry([TrainingDataDoc], [FileType.TrainingData], [])), + { provide: FileService, useMock: mockedFileService } + ] })); beforeEach(() => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts index 13eb68e6508..21a50dab81f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts @@ -1,9 +1,9 @@ import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; -import { MatIconModule } from '@angular/material/icon'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { MatSelectChange, MatSelectModule } from '@angular/material/select'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { MatSelect, MatSelectChange } from '@angular/material/select'; +import { MatTooltip } from '@angular/material/tooltip'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { cloneDeep } from 'lodash-es'; import { TranslocoMarkupModule } from 'ngx-transloco-markup'; import { Delta } from 'quill'; @@ -20,16 +20,16 @@ import { createTestFeatureFlag, FeatureFlagService } from 'xforge-common/feature import { I18nService } from 'xforge-common/i18n.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../../core/models/sf-type-registry'; import { Revision } from '../../../core/paratext.service'; import { BuildDto } from '../../../machine-api/build-dto'; import { BuildStates } from '../../../machine-api/build-states'; -import { SharedModule } from '../../../shared/shared.module'; +import { provideQuillRegistrations } from '../../../shared/text/quill-editor-registration/quill-providers'; import { EDITOR_READY_TIMEOUT } from '../../../shared/text/text.component'; import { DraftSegmentMap } from '../../draft-generation/draft-generation'; import { DraftGenerationService } from '../../draft-generation/draft-generation.service'; @@ -53,20 +53,20 @@ describe('EditorDraftComponent', () => { const buildProgress$ = new BehaviorSubject(undefined); configureTestingModule(() => ({ - declarations: [EditorDraftComponent, HistoryRevisionFormatPipe], imports: [ - MatProgressBarModule, - MatSelectModule, - MatIconModule, - MatTooltipModule, - NoopAnimationsModule, - SharedModule.forRoot(), - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - TestTranslocoModule, + HistoryRevisionFormatPipe, + EditorDraftComponent, + MatProgressBar, + MatSelect, + MatIcon, + MatTooltip, + getTestTranslocoModule(), TranslocoMarkupModule ], providers: [ + provideQuillRegistrations(), + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: ActivatedProjectService, useMock: mockActivatedProjectService }, { provide: DraftGenerationService, useMock: mockDraftGenerationService }, { provide: DraftHandlingService, useMock: mockDraftHandlingService }, @@ -75,7 +75,8 @@ describe('EditorDraftComponent', () => { { provide: DialogService, useMock: mockDialogService }, { provide: NoticeService, useMock: mockNoticeService }, { provide: ErrorReportingService, useMock: mockErrorReportingService }, - { provide: FeatureFlagService, useMock: mockFeatureFlagService } + { provide: FeatureFlagService, useMock: mockFeatureFlagService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts index 00c642d9e78..4b95d52362f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts @@ -1,7 +1,16 @@ +import { AsyncPipe, NgClass } from '@angular/common'; import { AfterViewInit, Component, DestroyRef, EventEmitter, Input, OnChanges, ViewChild } from '@angular/core'; -import { MatSelectChange } from '@angular/material/select'; +import { MatOption } from '@angular/material/autocomplete'; +import { MatButton } from '@angular/material/button'; +import { MatFormField } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { MatSelect, MatSelectChange, MatSelectTrigger } from '@angular/material/select'; +import { MatTooltip } from '@angular/material/tooltip'; import { Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; +import { TranslocoMarkupComponent } from 'ngx-transloco-markup'; import { Delta } from 'quill'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { DeltaOperation } from 'rich-text'; @@ -39,15 +48,36 @@ import { TextDocId } from '../../../core/models/text-doc'; import { Revision } from '../../../core/paratext.service'; import { SFProjectService } from '../../../core/sf-project.service'; import { BuildStates } from '../../../machine-api/build-states'; +import { NoticeComponent } from '../../../shared/notice/notice.component'; import { TextComponent } from '../../../shared/text/text.component'; import { DraftGenerationService } from '../../draft-generation/draft-generation.service'; import { DraftHandlingService } from '../../draft-generation/draft-handling.service'; import { DraftOptionsService } from '../../draft-generation/draft-options.service'; +import { DraftPreviewBooksComponent } from '../../draft-generation/draft-preview-books/draft-preview-books.component'; +import { HistoryRevisionFormatPipe } from '../editor-history/history-chooser/history-revision-format.pipe'; + @Component({ selector: 'app-editor-draft', templateUrl: './editor-draft.component.html', styleUrls: ['./editor-draft.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatProgressBar, + NoticeComponent, + DraftPreviewBooksComponent, + TranslocoMarkupComponent, + MatFormField, + MatSelect, + MatSelectTrigger, + MatOption, + MatButton, + MatIcon, + MatTooltip, + TextComponent, + NgClass, + AsyncPipe, + HistoryRevisionFormatPipe + ] }) export class EditorDraftComponent implements AfterViewInit, OnChanges { @Input() projectId?: string; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/editor-history.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/editor-history.component.spec.ts index 7937b73ce32..14e1d65c586 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/editor-history.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/editor-history.component.spec.ts @@ -6,11 +6,14 @@ import { TextData } from 'realtime-server/lib/esm/scriptureforge/models/text-dat import { Subject } from 'rxjs'; import { anything, mock, when } from 'ts-mockito'; import { I18nService } from 'xforge-common/i18n.service'; +import { FileType } from 'xforge-common/models/file-offline-data'; import { Snapshot } from 'xforge-common/models/snapshot'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { configureTestingModule } from 'xforge-common/test-utils'; +import { TypeRegistry } from 'xforge-common/type-registry'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { TextDoc, TextDocId } from '../../../core/models/text-doc'; import { Revision } from '../../../core/paratext.service'; @@ -30,10 +33,11 @@ describe('EditorHistoryComponent', () => { const showDiffChange$ = new Subject(); configureTestingModule(() => ({ - imports: [TestOnlineStatusModule.forRoot()], - declarations: [EditorHistoryComponent], + imports: [EditorHistoryComponent], schemas: [NO_ERRORS_SCHEMA], // Ignore undeclared child components providers: [ + provideTestRealtime(new TypeRegistry([TextDoc], [FileType.Audio], [])), + provideTestOnlineStatus(), { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: SFProjectService, useMock: mockSFProjectService }, { provide: I18nService, useMock: mockI18nService } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/editor-history.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/editor-history.component.ts index fe3ea54228d..a833dcb216e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/editor-history.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/editor-history.component.ts @@ -1,3 +1,4 @@ +import { AsyncPipe } from '@angular/common'; import { AfterViewInit, Component, @@ -9,6 +10,8 @@ import { Output, ViewChild } from '@angular/core'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { TranslocoModule } from '@ngneat/transloco'; import { Delta } from 'quill'; import { combineLatest, startWith, tap } from 'rxjs'; import { FontService } from 'xforge-common/font.service'; @@ -19,6 +22,7 @@ import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc import { TextDoc } from '../../../core/models/text-doc'; import { Revision } from '../../../core/paratext.service'; import { SFProjectService } from '../../../core/sf-project.service'; +import { NoticeComponent } from '../../../shared/notice/notice.component'; import { TextComponent } from '../../../shared/text/text.component'; import { EditorHistoryService } from './editor-history.service'; import { HistoryChooserComponent, RevisionSelectEvent } from './history-chooser/history-chooser.component'; @@ -26,7 +30,7 @@ import { HistoryChooserComponent, RevisionSelectEvent } from './history-chooser/ selector: 'app-editor-history', templateUrl: './editor-history.component.html', styleUrls: ['./editor-history.component.scss'], - standalone: false + imports: [MatProgressBar, NoticeComponent, HistoryChooserComponent, TextComponent, AsyncPipe, TranslocoModule] }) export class EditorHistoryComponent implements OnChanges, OnInit, AfterViewInit { private _projectId?: string | undefined; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-chooser.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-chooser.component.spec.ts index 444f85d76dc..64db6e6b94a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-chooser.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-chooser.component.spec.ts @@ -1,6 +1,6 @@ import { SimpleChange } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/models/text-info-permission'; @@ -10,12 +10,11 @@ import { DialogService } from 'xforge-common/dialog.service'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFProjectProfileDoc } from '../../../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../../../core/models/sf-type-registry'; import { ParatextService } from '../../../../core/paratext.service'; @@ -33,22 +32,18 @@ const mockedErrorReportingService = mock(ErrorReportingService); describe('HistoryChooserComponent', () => { configureTestingModule(() => ({ - imports: [ - NoopAnimationsModule, - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - TestTranslocoModule, - UICommonModule - ], - declarations: [HistoryChooserComponent, HistoryRevisionFormatPipe], + imports: [HistoryChooserComponent, HistoryRevisionFormatPipe, getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: DialogService, useMock: mockedDialogService }, { provide: NoticeService, useMock: mockedNoticeService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: ParatextService, useMock: mockedParatextService }, { provide: SFProjectService, useMock: mockedProjectService }, { provide: TextDocService, useMock: mockedTextDocService }, - { provide: ErrorReportingService, useMock: mockedErrorReportingService } + { provide: ErrorReportingService, useMock: mockedErrorReportingService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-chooser.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-chooser.component.ts index 1e618a11c54..e2a9af58779 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-chooser.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-chooser.component.ts @@ -1,5 +1,12 @@ +import { AsyncPipe, NgClass } from '@angular/common'; import { AfterViewInit, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; -import { MatSelectChange } from '@angular/material/select'; +import { MatOption } from '@angular/material/autocomplete'; +import { MatButton } from '@angular/material/button'; +import { MatFormField } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatSelect, MatSelectChange, MatSelectTrigger } from '@angular/material/select'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; import { Delta } from 'quill'; import { TextData } from 'realtime-server/lib/esm/scriptureforge/models/text-data'; @@ -14,6 +21,7 @@ import { Subject, tap } from 'rxjs'; +import { BlurOnClickDirective } from 'xforge-common/blur-on-click.directive'; import { isNetworkError } from 'xforge-common/command.service'; import { DialogService } from 'xforge-common/dialog.service'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; @@ -27,6 +35,7 @@ import { TextDocId } from '../../../../core/models/text-doc'; import { ParatextService, Revision } from '../../../../core/paratext.service'; import { SFProjectService } from '../../../../core/sf-project.service'; import { TextDocService } from '../../../../core/text-doc.service'; +import { HistoryRevisionFormatPipe } from './history-revision-format.pipe'; export interface RevisionSelectEvent { revision: Revision; @@ -37,7 +46,20 @@ export interface RevisionSelectEvent { selector: 'app-history-chooser', templateUrl: './history-chooser.component.html', styleUrls: ['./history-chooser.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatFormField, + MatSelect, + MatSelectTrigger, + MatOption, + MatIcon, + MatButton, + BlurOnClickDirective, + MatTooltip, + NgClass, + AsyncPipe, + HistoryRevisionFormatPipe + ] }) export class HistoryChooserComponent implements AfterViewInit, OnChanges { @Input() projectId?: string; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-revision-format.pipe.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-revision-format.pipe.ts index 7d5685958c5..c903f2315e2 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-revision-format.pipe.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-history/history-chooser/history-revision-format.pipe.ts @@ -4,8 +4,7 @@ import { Revision } from '../../../../core/paratext.service'; @Pipe({ name: 'revisionFormat', - pure: false, - standalone: false + pure: false }) export class HistoryRevisionFormatPipe implements PipeTransform { constructor(private readonly i18n: I18nService) {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-resource/editor-resource.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-resource/editor-resource.component.spec.ts index f71cf5ac524..abe25e0129a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-resource/editor-resource.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-resource/editor-resource.component.spec.ts @@ -4,7 +4,7 @@ import { Subject } from 'rxjs'; import { anything, mock, verify, when } from 'ts-mockito'; import { DialogService } from 'xforge-common/dialog.service'; import { FontService } from 'xforge-common/font.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { SFProjectService } from '../../../core/sf-project.service'; import { CopyrightBannerComponent } from '../../../shared/copyright-banner/copyright-banner.component'; @@ -27,7 +27,7 @@ describe('EditorResourceComponent', () => { { provide: FontService, useMock: mockFontService }, { provide: DialogService, useMock: mockDialogService } ], - imports: [CopyrightBannerComponent, TestTranslocoModule] + imports: [CopyrightBannerComponent, getTestTranslocoModule()] })); beforeEach(async () => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-resource/editor-resource.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-resource/editor-resource.component.ts index f4ee6d2a1ba..e6d7aefb80f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-resource/editor-resource.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-resource/editor-resource.component.ts @@ -6,11 +6,13 @@ import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc import { SFProjectService } from '../../../core/sf-project.service'; import { TextComponent } from '../../../shared/text/text.component'; import { formatFontSizeToRems } from '../../../shared/utils'; +import { CopyrightBannerComponent } from '../../../shared/copyright-banner/copyright-banner.component'; +import { TextDocIdPipe } from '../../../shared/text/text-doc-id.pipe'; @Component({ selector: 'app-editor-resource', templateUrl: './editor-resource.component.html', styleUrl: '../editor.component.scss', - standalone: false + imports: [CopyrightBannerComponent, TextComponent, TextDocIdPipe] }) export class EditorResourceComponent implements AfterViewInit, OnChanges { @Input() projectId?: string; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.spec.ts index dfe098ed899..3427e7fe4d9 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.spec.ts @@ -8,8 +8,8 @@ import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; import { MatTooltipHarness } from '@angular/material/tooltip/testing'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ActivatedRoute, Params, Route, Router, RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { ActivatedRoute, Params, provideRouter, Route, Router } from '@angular/router'; import { createRange, InteractiveTranslatorFactory, @@ -75,12 +75,11 @@ import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { noopDestroyRef } from 'xforge-common/realtime.service'; import { TestBreakpointObserver } from 'xforge-common/test-breakpoint-observer'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { isBlink } from 'xforge-common/utils'; import { BiblicalTermDoc } from '../../core/models/biblical-term-doc'; @@ -100,9 +99,18 @@ import { BuildStates } from '../../machine-api/build-states'; import { HttpClient } from '../../machine-api/http-client'; import { RemoteTranslationEngine } from '../../machine-api/remote-translation-engine'; import { CopyrightBannerComponent } from '../../shared/copyright-banner/copyright-banner.component'; -import { SFTabsModule, TabFactoryService, TabGroup, TabMenuService } from '../../shared/sf-tab-group'; -import { SharedModule } from '../../shared/shared.module'; +import { provideCustomIcons } from '../../shared/custom-icons'; +import { + provideSFTabs, + TabComponent, + TabFactoryService, + TabGroup, + TabGroupComponent, + TabHeaderDirective, + TabMenuService +} from '../../shared/sf-tab-group'; import { getCombinedVerseTextDoc, paratextUsersFromRoles } from '../../shared/test-utils'; +import { provideQuillRegistrations } from '../../shared/text/quill-editor-registration/quill-providers'; import { PRESENCE_EDITOR_ACTIVE_TIMEOUT } from '../../shared/text/text.component'; import { XmlUtils } from '../../shared/utils'; import { BiblicalTermsComponent } from '../biblical-terms/biblical-terms.component'; @@ -113,7 +121,9 @@ import { TrainingProgressComponent } from '../training-progress/training-progres import { EditorDraftComponent } from './editor-draft/editor-draft.component'; import { HistoryRevisionFormatPipe } from './editor-history/history-chooser/history-revision-format.pipe'; import { EditorComponent, UPDATE_SUGGESTIONS_TIMEOUT } from './editor.component'; -import { LynxInsightsModule } from './lynx/insights/lynx-insights.module'; +import { LynxInsightEditorObjectsComponent } from './lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component'; +import { LynxInsightsPanelComponent } from './lynx/insights/lynx-insights-panel/lynx-insights-panel.component'; +import { provideLynxInsights } from './lynx/insights/lynx-insights-providers'; import { LynxWorkspaceService } from './lynx/insights/lynx-workspace.service'; import { NoteDialogComponent, NoteDialogData, NoteDialogResult } from './note-dialog/note-dialog.component'; import { SuggestionsComponent } from './suggestions.component'; @@ -162,30 +172,32 @@ class MockConsole { describe('EditorComponent', () => { configureTestingModule(() => ({ - declarations: [ - EditorComponent, + imports: [ SuggestionsComponent, - TrainingProgressComponent, + HistoryRevisionFormatPipe, + EditorComponent, EditorDraftComponent, - HistoryRevisionFormatPipe - ], - imports: [ + TrainingProgressComponent, BiblicalTermsComponent, CopyrightBannerComponent, DraftPreviewBooksComponent, - NoopAnimationsModule, - RouterModule.forRoot(ROUTES), - SharedModule.forRoot(), - UICommonModule, - TestTranslocoModule, - TranslocoMarkupModule, - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - SFTabsModule, - LynxInsightsModule.forRoot(), - AngularSplitModule + TabGroupComponent, + TabComponent, + TabHeaderDirective, + LynxInsightEditorObjectsComponent, + LynxInsightsPanelComponent, + AngularSplitModule, + getTestTranslocoModule(), + TranslocoMarkupModule ], providers: [ + provideRouter(ROUTES), + provideQuillRegistrations(), + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), + provideSFTabs(), + provideLynxInsights(), + provideCustomIcons(), { provide: AuthService, useMock: mockedAuthService }, { provide: SFProjectService, useMock: mockedSFProjectService }, { provide: UserService, useMock: mockedUserService }, @@ -206,7 +218,8 @@ describe('EditorComponent', () => { { provide: TabMenuService, useValue: EditorTabMenuService }, { provide: PermissionsService, useMock: mockedPermissionsService }, { provide: LynxWorkspaceService, useMock: mockedLynxWorkspaceService }, - { provide: FeatureFlagService, useMock: mockedFeatureFlagService } + { provide: FeatureFlagService, useMock: mockedFeatureFlagService }, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.ts index c16a0a47bcb..6881977806c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor.component.ts @@ -1,5 +1,7 @@ +import { Dir } from '@angular/cdk/bidi'; import { BreakpointObserver } from '@angular/cdk/layout'; import { ComponentType } from '@angular/cdk/portal'; +import { AsyncPipe, KeyValuePipe, NgClass } from '@angular/common'; import { AfterViewInit, ChangeDetectorRef, @@ -14,10 +16,16 @@ import { ViewChild, ViewChildren } from '@angular/core'; -import { UntypedFormControl, Validators } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule, UntypedFormControl, Validators } from '@angular/forms'; import { MatBottomSheet, MatBottomSheetRef } from '@angular/material/bottom-sheet'; +import { MatButton, MatIconButton, MatMiniFabButton } from '@angular/material/button'; import { MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatInput } from '@angular/material/input'; +import { MatTooltip } from '@angular/material/tooltip'; import { ActivatedRoute, Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { InteractiveTranslator, InteractiveTranslatorFactory, @@ -28,6 +36,7 @@ import { TranslationSuggester } from '@sillsdev/machine'; import { Canon, VerseRef } from '@sillsdev/scripture'; +import { AngularSplitModule } from 'angular-split'; import { isEqual } from 'lodash-es'; import Quill, { Bounds, Delta, Range } from 'quill'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; @@ -81,6 +90,7 @@ import { throttleTime } from 'rxjs/operators'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; +import { BlurOnClickDirective } from 'xforge-common/blur-on-click.directive'; import { CONSOLE, ConsoleInterface } from 'xforge-common/browser-globals'; import { DataLoadingComponent } from 'xforge-common/data-loading-component'; import { DialogService } from 'xforge-common/dialog.service'; @@ -113,10 +123,23 @@ import { TextDocService } from '../../core/text-doc.service'; import { TranslationEngineService } from '../../core/translation-engine.service'; import { BuildDto } from '../../machine-api/build-dto'; import { RemoteTranslationEngine } from '../../machine-api/remote-translation-engine'; -import { TabFactoryService, TabGroup, TabMenuService, TabStateService } from '../../shared/sf-tab-group'; -import { TabAddRequestService } from '../../shared/sf-tab-group/base-services/tab-add-request.service'; +import { BookChapterChooserComponent } from '../../shared/book-chapter-chooser/book-chapter-chooser.component'; +import { CopyrightBannerComponent } from '../../shared/copyright-banner/copyright-banner.component'; +import { NoticeComponent } from '../../shared/notice/notice.component'; +import { + TabAddRequestService, + TabFactoryService, + TabGroup, + TabMenuService, + TabStateService +} from '../../shared/sf-tab-group'; +import { TabGroupComponent } from '../../shared/sf-tab-group/tab-group.component'; +import { TabHeaderDirective } from '../../shared/sf-tab-group/tab-header/tab-header.directive'; +import { TabComponent } from '../../shared/sf-tab-group/tab/tab.component'; +import { ShareButtonComponent } from '../../shared/share/share-button.component'; import { getRetainCount } from '../../shared/text/quill-util'; import { Segment } from '../../shared/text/segment'; +import { TextDocIdPipe } from '../../shared/text/text-doc-id.pipe'; import { EmbedsByVerse, FeaturedVerseRefInfo, @@ -135,13 +158,19 @@ import { verseRefFromMouseEvent, XmlUtils } from '../../shared/utils'; +import { BiblicalTermsComponent } from '../biblical-terms/biblical-terms.component'; import { DraftGenerationService } from '../draft-generation/draft-generation.service'; import { DraftOptionsService } from '../draft-generation/draft-options.service'; +import { TrainingProgressComponent } from '../training-progress/training-progress.component'; +import { EditorDraftComponent } from './editor-draft/editor-draft.component'; +import { EditorHistoryComponent } from './editor-history/editor-history.component'; import { EditorHistoryService } from './editor-history/editor-history.service'; +import { EditorResourceComponent } from './editor-resource/editor-resource.component'; import { LynxInsightStateService } from './lynx/insights/lynx-insight-state.service'; -import { MultiCursorViewer } from './multi-viewer/multi-viewer.component'; +import { LynxInsightsPanelComponent } from './lynx/insights/lynx-insights-panel/lynx-insights-panel.component'; +import { MultiCursorViewer, MultiViewerComponent } from './multi-viewer/multi-viewer.component'; import { NoteDialogComponent, NoteDialogData, NoteDialogResult } from './note-dialog/note-dialog.component'; -import { Suggestion } from './suggestions.component'; +import { Suggestion, SuggestionsComponent } from './suggestions.component'; import { EditorTabAddRequestService } from './tabs/editor-tab-add-request.service'; import { EditorTabFactoryService } from './tabs/editor-tab-factory.service'; import { EditorTabMenuService } from './tabs/editor-tab-menu.service'; @@ -217,7 +246,42 @@ const UNSUPPORTED_LANGUAGE_CODES = [ { provide: TabMenuService, useClass: EditorTabMenuService }, { provide: TabAddRequestService, useClass: EditorTabAddRequestService } ], - standalone: false + imports: [ + AsyncPipe, + Dir, + KeyValuePipe, + NgClass, + FormsModule, + ReactiveFormsModule, + MatButton, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatMiniFabButton, + MatTooltip, + AngularSplitModule, + TranslocoModule, + BlurOnClickDirective, + BookChapterChooserComponent, + CopyrightBannerComponent, + MultiViewerComponent, + NoticeComponent, + ShareButtonComponent, + TextComponent, + TabComponent, + TabGroupComponent, + TabHeaderDirective, + BiblicalTermsComponent, + EditorDraftComponent, + EditorHistoryComponent, + EditorResourceComponent, + LynxInsightsPanelComponent, + SuggestionsComponent, + TextDocIdPipe, + TrainingProgressComponent + ] }) export class EditorComponent extends DataLoadingComponent implements OnDestroy, OnInit, AfterViewInit { addingMobileNote: boolean = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-action-prompt/lynx-insight-action-prompt.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-action-prompt/lynx-insight-action-prompt.component.ts index b5fc0a1996d..c5d8b702911 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-action-prompt/lynx-insight-action-prompt.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-action-prompt/lynx-insight-action-prompt.component.ts @@ -1,5 +1,6 @@ import { Directionality } from '@angular/cdk/bidi'; import { Component, DestroyRef, ElementRef, Input, OnInit, Renderer2 } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; import { Bounds } from 'quill'; import { combineLatest, @@ -25,7 +26,7 @@ import { getMostNestedInsight } from '../lynx-insight-util'; selector: 'app-lynx-insight-action-prompt', templateUrl: './lynx-insight-action-prompt.component.html', styleUrl: './lynx-insight-action-prompt.component.scss', - standalone: false + imports: [MatIcon] }) export class LynxInsightActionPromptComponent implements OnInit { @Input() set editor(value: LynxableEditor | undefined) { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component.spec.ts index 35b76ba19fa..2f4e411f1a6 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component.spec.ts @@ -1,14 +1,21 @@ import { Component, DestroyRef, NO_ERRORS_SCHEMA, ViewChild } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { Delta } from 'quill'; +import { LynxInsightFilter, LynxInsightType } from 'realtime-server/lib/esm/scriptureforge/models/lynx-insight'; import { BehaviorSubject } from 'rxjs'; import { anything, instance, mock, verify, when } from 'ts-mockito'; import { ActivatedBookChapterService, RouteBookChapter } from 'xforge-common/activated-book-chapter.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { TextDocId } from '../../../../../core/models/text-doc'; +import { provideCustomIcons } from '../../../../../shared/custom-icons'; import { EditorReadyService } from '../base-services/editor-ready.service'; import { InsightRenderService } from '../base-services/insight-render.service'; -import { LynxableEditor, LynxTextModelConverter } from '../lynx-editor'; +import { + LynxableEditor, + LynxEditorAdapterFactory, + LynxTextModelConverter, + TestLynxEditorAdapterFactory +} from '../lynx-editor'; import { LynxInsight, LynxInsightDisplayState, LynxInsightRange } from '../lynx-insight'; import { LynxInsightOverlayService } from '../lynx-insight-overlay.service'; import { LynxInsightStateService } from '../lynx-insight-state.service'; @@ -28,15 +35,17 @@ const mockTextModelConverter = mock(); describe('LynxInsightEditorObjectsComponent', () => { configureTestingModule(() => ({ - declarations: [HostComponent, LynxInsightEditorObjectsComponent], + imports: [HostComponent, LynxInsightEditorObjectsComponent], providers: [ + provideCustomIcons(), { provide: InsightRenderService, useMock: mockInsightRenderService }, { provide: LynxInsightStateService, useMock: mockInsightStateService }, { provide: EditorReadyService, useMock: mockEditorReadyService }, { provide: LynxInsightOverlayService, useMock: mockOverlayService }, { provide: LynxWorkspaceService, useMock: mockLynxWorkspaceService }, { provide: ActivatedBookChapterService, useMock: mockActivatedBookChapterService }, - { provide: DestroyRef, useMock: mockDestroyRef } + { provide: DestroyRef, useMock: mockDestroyRef }, + { provide: LynxEditorAdapterFactory, useClass: TestLynxEditorAdapterFactory } ], schemas: [NO_ERRORS_SCHEMA] })); @@ -353,7 +362,7 @@ describe('LynxInsightEditorObjectsComponent', () => { > `, - standalone: false + imports: [LynxInsightEditorObjectsComponent] }) class HostComponent { @ViewChild(LynxInsightEditorObjectsComponent) component!: LynxInsightEditorObjectsComponent; @@ -378,6 +387,9 @@ class TestEnvironment { private filteredInsightsSubject: BehaviorSubject; private displayStateSubject: BehaviorSubject; private activatedBookChapterSubject: BehaviorSubject; + private filterSubject: BehaviorSubject; + private filteredInsightCountsByTypeSubject: BehaviorSubject>; + private taskRunningStatusSubject: BehaviorSubject; constructor(args: TestEnvArgs = {}) { const textModelConverter = instance(mockTextModelConverter); @@ -398,10 +410,19 @@ class TestEnvironment { chapter: 1 }); + // Add mocks for LynxInsightStatusIndicatorComponent observables + this.filterSubject = new BehaviorSubject({ types: [] }); + this.filteredInsightCountsByTypeSubject = new BehaviorSubject({ info: 0, warning: 0, error: 0 }); + this.taskRunningStatusSubject = new BehaviorSubject(false); + // Create mock editor const mockRoot = document.createElement('div'); const actualEditor = { root: mockRoot, + getEditor: () => actualEditor, + getScrollingContainer: () => mockRoot, + getBounds: () => ({ top: 0 }), + getRoot: () => mockRoot, on: (eventName: string, handler: (...args: any[]) => void) => { if (!this.eventHandlers.has(eventName)) { this.eventHandlers.set(eventName, []); @@ -425,7 +446,10 @@ class TestEnvironment { when(mockEditorReadyService.listenEditorReadyState(anything())).thenReturn(this.editorReadySubject); when(mockInsightStateService.filteredChapterInsights$).thenReturn(this.filteredInsightsSubject); when(mockInsightStateService.displayState$).thenReturn(this.displayStateSubject); + when(mockInsightStateService.filter$).thenReturn(this.filterSubject); + when(mockInsightStateService.filteredInsightCountsByType$).thenReturn(this.filteredInsightCountsByTypeSubject); when(mockActivatedBookChapterService.activatedBookChapter$).thenReturn(this.activatedBookChapterSubject); + when(mockLynxWorkspaceService.taskRunningStatus$).thenReturn(this.taskRunningStatusSubject); when(mockInsightStateService.updateDisplayState(anything())).thenReturn(); when(mockInsightStateService.clearDisplayState()).thenReturn(); when(mockInsightRenderService.render(anything(), anything())).thenResolve(); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component.ts index 0140f5ec3ac..4fef722f799 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-editor-objects/lynx-insight-editor-objects.component.ts @@ -25,11 +25,18 @@ import { LynxInsightOverlayService } from '../lynx-insight-overlay.service'; import { LynxInsightStateService } from '../lynx-insight-state.service'; import { LynxWorkspaceService } from '../lynx-workspace.service'; import { LynxInsightBlot } from '../quill-services/blots/lynx-insight-blot'; +import { LynxInsightStatusIndicatorComponent } from '../lynx-insight-status-indicator/lynx-insight-status-indicator.component'; +import { LynxInsightScrollPositionIndicatorComponent } from '../lynx-insight-scroll-position-indicator/lynx-insight-scroll-position-indicator.component'; +import { LynxInsightActionPromptComponent } from '../lynx-insight-action-prompt/lynx-insight-action-prompt.component'; @Component({ selector: 'app-lynx-insight-editor-objects', templateUrl: './lynx-insight-editor-objects.component.html', - standalone: false + imports: [ + LynxInsightStatusIndicatorComponent, + LynxInsightScrollPositionIndicatorComponent, + LynxInsightActionPromptComponent + ] }) export class LynxInsightEditorObjectsComponent implements OnChanges, OnInit, OnDestroy { readonly insightSelector = `.${LynxInsightBlot.superClassName}`; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-overlay/lynx-insight-overlay.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-overlay/lynx-insight-overlay.component.spec.ts index 3e9d840a1b5..063eff39488 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-overlay/lynx-insight-overlay.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-overlay/lynx-insight-overlay.component.spec.ts @@ -3,8 +3,7 @@ import { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testi import { By } from '@angular/platform-browser'; import { anything, instance, mock, verify, when } from 'ts-mockito'; import { I18nService } from 'xforge-common/i18n.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { TextDocId } from '../../../../../core/models/text-doc'; import { LynxEditor, LynxTextModelConverter } from '../lynx-editor'; import { EDITOR_INSIGHT_DEFAULTS, LynxInsight, LynxInsightAction, LynxInsightConfig } from '../lynx-insight'; @@ -37,7 +36,7 @@ const defaultInsightConfig: LynxInsightConfig = { [editor]="editor" [textModelConverter]="textModelConverter" >`, - standalone: false + imports: [LynxInsightOverlayComponent] }) class HostComponent { @ViewChild('overlay') component!: LynxInsightOverlayComponent; @@ -48,8 +47,7 @@ class HostComponent { describe('LynxInsightOverlayComponent', () => { configureTestingModule(() => ({ - imports: [UICommonModule, TestTranslocoModule], - declarations: [HostComponent, LynxInsightOverlayComponent], + imports: [LynxInsightOverlayComponent, getTestTranslocoModule(), HostComponent], providers: [ { provide: LynxInsightStateService, useMock: mockLynxInsightStateService }, { provide: LynxInsightOverlayService, useMock: mockLynxInsightOverlayService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-overlay/lynx-insight-overlay.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-overlay/lynx-insight-overlay.component.ts index 5a61da8b855..4ea288359da 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-overlay/lynx-insight-overlay.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-overlay/lynx-insight-overlay.component.ts @@ -1,6 +1,10 @@ -import { DOCUMENT } from '@angular/common'; +import { Dir } from '@angular/cdk/bidi'; +import { DOCUMENT, NgClass } from '@angular/common'; import { Component, DestroyRef, ElementRef, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core'; -import { MAT_TOOLTIP_DEFAULT_OPTIONS } from '@angular/material/tooltip'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { MAT_TOOLTIP_DEFAULT_OPTIONS, MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { Delta } from 'quill'; import { fromEvent } from 'rxjs'; import { I18nService } from 'xforge-common/i18n.service'; @@ -16,7 +20,7 @@ import { LynxWorkspaceService } from '../lynx-workspace.service'; templateUrl: './lynx-insight-overlay.component.html', styleUrl: './lynx-insight-overlay.component.scss', providers: [{ provide: MAT_TOOLTIP_DEFAULT_OPTIONS, useValue: { showDelay: 500 } }], - standalone: false + imports: [TranslocoModule, NgClass, MatIcon, MatTooltip, MatMenuTrigger, Dir, MatMenu, MatMenuItem] }) export class LynxInsightOverlayComponent implements OnInit { showMoreInfo = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-scroll-position-indicator/lynx-insight-scroll-position-indicator.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-scroll-position-indicator/lynx-insight-scroll-position-indicator.component.ts index c6339462b99..523c46417ca 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-scroll-position-indicator/lynx-insight-scroll-position-indicator.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-scroll-position-indicator/lynx-insight-scroll-position-indicator.component.ts @@ -1,3 +1,4 @@ +import { NgClass } from '@angular/common'; import { Component, DestroyRef, Input, OnInit } from '@angular/core'; import { LynxInsightType } from 'realtime-server/lib/esm/scriptureforge/models/lynx-insight'; import { combineLatest, debounceTime, filter, fromEvent, map, startWith, switchMap } from 'rxjs'; @@ -17,7 +18,7 @@ interface LynxInsightScrollPosition { selector: 'app-lynx-insight-scroll-position-indicator', templateUrl: './lynx-insight-scroll-position-indicator.component.html', styleUrl: './lynx-insight-scroll-position-indicator.component.scss', - standalone: false + imports: [NgClass] }) export class LynxInsightScrollPositionIndicatorComponent implements OnInit { @Input() set editor(value: LynxableEditor | undefined) { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-status-indicator/lynx-insight-status-indicator.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-status-indicator/lynx-insight-status-indicator.component.spec.ts index aa470985eb8..1a7c46c52fc 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-status-indicator/lynx-insight-status-indicator.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-status-indicator/lynx-insight-status-indicator.component.spec.ts @@ -1,12 +1,12 @@ import { Component, DebugElement, ViewChild } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatIconModule } from '@angular/material/icon'; +import { MatIcon } from '@angular/material/icon'; import { By } from '@angular/platform-browser'; import { LynxInsightType } from 'realtime-server/lib/esm/scriptureforge/models/lynx-insight'; import { BehaviorSubject } from 'rxjs'; import { mock, verify, when } from 'ts-mockito'; import { configureTestingModule } from 'xforge-common/test-utils'; -import { CustomIconModule } from '../../../../../shared/custom-icon.module'; +import { provideCustomIcons } from '../../../../../shared/custom-icons'; import { LynxInsightStateService } from '../lynx-insight-state.service'; import { LynxWorkspaceService } from '../lynx-workspace.service'; import { LynxInsightStatusIndicatorComponent } from './lynx-insight-status-indicator.component'; @@ -16,9 +16,9 @@ const mockLynxWorkspaceService = mock(LynxWorkspaceService); describe('LynxInsightStatusIndicatorComponent', () => { configureTestingModule(() => ({ - declarations: [HostComponent, LynxInsightStatusIndicatorComponent], - imports: [MatIconModule, CustomIconModule], + imports: [LynxInsightStatusIndicatorComponent, MatIcon, HostComponent], providers: [ + provideCustomIcons(), { provide: LynxInsightStateService, useMock: mockLynxInsightStateService }, { provide: LynxWorkspaceService, useMock: mockLynxWorkspaceService } ] @@ -190,7 +190,7 @@ describe('LynxInsightStatusIndicatorComponent', () => { @Component({ template: '', - standalone: false + imports: [LynxInsightStatusIndicatorComponent] }) class HostComponent { @ViewChild(LynxInsightStatusIndicatorComponent) component!: LynxInsightStatusIndicatorComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-status-indicator/lynx-insight-status-indicator.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-status-indicator/lynx-insight-status-indicator.component.ts index 17500769606..d5b7b06a054 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-status-indicator/lynx-insight-status-indicator.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insight-status-indicator/lynx-insight-status-indicator.component.ts @@ -1,4 +1,6 @@ +import { AsyncPipe, NgClass } from '@angular/common'; import { Component, HostListener } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; import { LynxInsightType } from 'realtime-server/lib/esm/scriptureforge/models/lynx-insight'; import { map, Observable } from 'rxjs'; import { LynxInsightStateService } from '../lynx-insight-state.service'; @@ -13,14 +15,13 @@ interface InsightCount { selector: 'app-lynx-insight-status-indicator', templateUrl: './lynx-insight-status-indicator.component.html', styleUrl: './lynx-insight-status-indicator.component.scss', - standalone: false + imports: [MatIcon, NgClass, AsyncPipe] }) export class LynxInsightStatusIndicatorComponent { - isFilterHidingInsights$: Observable = this.editorInsightState.filter$.pipe( + readonly isFilterHidingInsights$: Observable = this.editorInsightState.filter$.pipe( map(filter => filter.types.length === 0) ); - private insightTypeOrder: LynxInsightType[] = ['info', 'warning', 'error']; readonly insightCountsByType$: Observable = this.editorInsightState.filteredInsightCountsByType$.pipe( map(counts => this.insightTypeOrder @@ -30,6 +31,7 @@ export class LynxInsightStatusIndicatorComponent { ); readonly isLoading$: Observable = this.lynxWorkspaceService.taskRunningStatus$; + private insightTypeOrder: LynxInsightType[] = ['info', 'warning', 'error']; constructor( private readonly editorInsightState: LynxInsightStateService, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel-header/lynx-insights-panel-header.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel-header/lynx-insights-panel-header.component.ts index f06d2b4fe6b..8469ed35d40 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel-header/lynx-insights-panel-header.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel-header/lynx-insights-panel-header.component.ts @@ -1,5 +1,10 @@ import { Component, DestroyRef, OnInit, ViewChild } from '@angular/core'; -import { MatMenuTrigger } from '@angular/material/menu'; +import { MatButton } from '@angular/material/button'; +import { MatDivider } from '@angular/material/divider'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { MatTab, MatTabGroup, MatTabLabel } from '@angular/material/tabs'; +import { TranslocoModule } from '@ngneat/transloco'; import { LynxInsightFilter, LynxInsightFilterScope, @@ -9,6 +14,7 @@ import { LynxInsightType, LynxInsightTypes } from 'realtime-server/lib/esm/scriptureforge/models/lynx-insight'; +import { IncludesPipe } from 'xforge-common/includes.pipe'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { LynxInsightStateService } from '../../lynx-insight-state.service'; @@ -16,7 +22,19 @@ import { LynxInsightStateService } from '../../lynx-insight-state.service'; selector: 'app-lynx-insights-panel-header', templateUrl: './lynx-insights-panel-header.component.html', styleUrl: './lynx-insights-panel-header.component.scss', - standalone: false + imports: [ + TranslocoModule, + MatButton, + MatMenuTrigger, + MatIcon, + MatTabGroup, + MatTab, + MatTabLabel, + MatMenu, + MatMenuItem, + MatDivider, + IncludesPipe + ] }) export class LynxInsightsPanelHeaderComponent implements OnInit { @ViewChild(MatMenuTrigger) menuTrigger?: MatMenuTrigger; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel.component.spec.ts index 8e952512cc0..71034a21f2f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel.component.spec.ts @@ -8,14 +8,14 @@ import { TestBed, tick } from '@angular/core/testing'; -import { MatButtonModule } from '@angular/material/button'; -import { MatDividerModule } from '@angular/material/divider'; -import { MatIconModule } from '@angular/material/icon'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatTabsModule } from '@angular/material/tabs'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { MatTreeModule } from '@angular/material/tree'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { MatButton } from '@angular/material/button'; +import { MatDivider } from '@angular/material/divider'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu } from '@angular/material/menu'; +import { MatTab, MatTabGroup } from '@angular/material/tabs'; +import { MatTooltip } from '@angular/material/tooltip'; +import { MatTree } from '@angular/material/tree'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { Router } from '@angular/router'; import { Range } from 'quill'; import Delta from 'quill-delta'; @@ -26,10 +26,9 @@ import { ActivatedBookChapterService, RouteBookChapter } from 'xforge-common/act import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { I18nService } from 'xforge-common/i18n.service'; import { IncludesPipe } from 'xforge-common/includes.pipe'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { TextDoc, TextDocId } from '../../../../../core/models/text-doc'; import { SFProjectService } from '../../../../../core/sf-project.service'; -import { CustomIconModule } from '../../../../../shared/custom-icon.module'; import { EditorSegmentService } from '../base-services/editor-segment.service'; import { EDITOR_INSIGHT_DEFAULTS, LynxInsight, LynxInsightConfig } from '../lynx-insight'; import { LynxInsightStateService } from '../lynx-insight-state.service'; @@ -110,21 +109,22 @@ describe('LynxInsightsPanelComponent', () => { configureTestingModule(() => ({ imports: [ - MatTreeModule, - MatIconModule, - MatButtonModule, - MatTooltipModule, - MatMenuModule, - MatTabsModule, - MatDividerModule, + MatTree, + MatIcon, + MatButton, + MatTooltip, + MatMenu, + MatTabGroup, + MatTab, + MatDivider, IncludesPipe, - NoopAnimationsModule, - TestTranslocoModule, - CustomIconModule + getTestTranslocoModule(), + LynxInsightsPanelComponent, + LynxInsightsPanelHeaderComponent ], - declarations: [LynxInsightsPanelComponent, LynxInsightsPanelHeaderComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], providers: [ + provideNoopAnimations(), { provide: LynxInsightStateService, useMock: mockLynxInsightStateService }, { provide: ActivatedProjectService, useMock: mockActivatedProjectService }, { provide: ActivatedBookChapterService, useMock: mockActivatedBookChapterService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel.component.ts index 689c348926b..c7781587a1c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-panel/lynx-insights-panel.component.ts @@ -1,6 +1,14 @@ +import { NgClass } from '@angular/common'; import { AfterViewInit, Component, DestroyRef, Inject, ViewChild } from '@angular/core'; -import { MatTree } from '@angular/material/tree'; +import { MatButton } from '@angular/material/button'; +import { MatRipple } from '@angular/material/core'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { MatProgressSpinner } from '@angular/material/progress-spinner'; +import { MatTooltip } from '@angular/material/tooltip'; +import { MatTree, MatTreeNode, MatTreeNodeDef, MatTreeNodeToggle } from '@angular/material/tree'; import { Router } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon, VerseRef } from '@sillsdev/scripture'; import { groupBy } from 'lodash-es'; import { Range } from 'quill'; @@ -24,6 +32,7 @@ import { combineVerseRefStrs, getVerseRefFromSegmentRef } from '../../../../../s import { EditorSegmentService } from '../base-services/editor-segment.service'; import { EDITOR_INSIGHT_DEFAULTS, LynxInsight, LynxInsightConfig, LynxInsightRange } from '../lynx-insight'; import { LynxInsightStateService } from '../lynx-insight-state.service'; +import { LynxInsightsPanelHeaderComponent } from './lynx-insights-panel-header/lynx-insights-panel-header.component'; /** * The sample text surrounding an insight, broken into pre-text, insight text, and post-text. @@ -63,7 +72,21 @@ interface LynxInsightWithText extends LynxInsight { selector: 'app-lynx-insights-panel', templateUrl: './lynx-insights-panel.component.html', styleUrl: './lynx-insights-panel.component.scss', - standalone: false + imports: [ + TranslocoModule, + LynxInsightsPanelHeaderComponent, + MatTree, + MatTreeNodeDef, + MatTreeNode, + MatRipple, + MatProgressSpinner, + MatIcon, + MatTooltip, + MatTreeNodeToggle, + NgClass, + MatButton, + MatProgressBar + ] }) export class LynxInsightsPanelComponent implements AfterViewInit { @ViewChild(MatTree) tree?: MatTree; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-providers.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-providers.ts new file mode 100644 index 00000000000..b13455efca3 --- /dev/null +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights-providers.ts @@ -0,0 +1,44 @@ +import { EnvironmentProviders, inject, makeEnvironmentProviders, provideAppInitializer } from '@angular/core'; +import { DocumentManager, DocumentReader } from '@sillsdev/lynx'; +import { ScriptureDeltaDocument, ScriptureDeltaDocumentFactory } from '@sillsdev/lynx-delta'; +import Delta, { Op } from 'quill-delta'; +import { QuillFormatRegistryService } from '../../../../shared/text/quill-editor-registration/quill-format-registry.service'; +import { EditorReadyService } from './base-services/editor-ready.service'; +import { EditorSegmentService } from './base-services/editor-segment.service'; +import { InsightRenderService } from './base-services/insight-render.service'; +import { LynxWorkspaceService, TextDocReader } from './lynx-workspace.service'; +import { lynxInsightBlots } from './quill-services/blots/lynx-insight-blot'; +import { QuillEditorReadyService } from './quill-services/quill-editor-ready.service'; +import { QuillEditorSegmentService } from './quill-services/quill-editor-segment.service'; +import { QuillInsightRenderService } from './quill-services/quill-insight-render.service'; + +/** + * Lynx Insights services' providers and initialization. + */ +export function provideLynxInsights(): EnvironmentProviders { + return makeEnvironmentProviders([ + { + provide: DocumentManager, + useFactory: createLynxDocumentManager, + deps: [TextDocReader] + }, + provideAppInitializer(() => { + const lynxWorkspaceService = inject(LynxWorkspaceService); + return lynxWorkspaceService.init(); + }), + provideAppInitializer(() => { + const formatRegistry = inject(QuillFormatRegistryService); + formatRegistry.registerFormats(lynxInsightBlots); + }), + { provide: EditorReadyService, useClass: QuillEditorReadyService }, + { provide: InsightRenderService, useClass: QuillInsightRenderService }, + { provide: EditorSegmentService, useClass: QuillEditorSegmentService } + ]); +} + +function createLynxDocumentManager( + documentReader: DocumentReader +): DocumentManager { + const documentFactory = new ScriptureDeltaDocumentFactory(); + return new DocumentManager(documentFactory, documentReader); +} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights.module.ts deleted file mode 100644 index 264e688e8dc..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-insights.module.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { BidiModule } from '@angular/cdk/bidi'; -import { OverlayModule } from '@angular/cdk/overlay'; -import { CommonModule } from '@angular/common'; -import { inject, ModuleWithProviders, NgModule, provideAppInitializer } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatRippleModule } from '@angular/material/core'; -import { MatDividerModule } from '@angular/material/divider'; -import { MatIconModule } from '@angular/material/icon'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatTabsModule } from '@angular/material/tabs'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { MatTreeModule } from '@angular/material/tree'; -import { TranslocoModule } from '@ngneat/transloco'; -import { DocumentManager, DocumentReader } from '@sillsdev/lynx'; -import { ScriptureDeltaDocument, ScriptureDeltaDocumentFactory } from '@sillsdev/lynx-delta'; -import Delta, { Op } from 'quill-delta'; -import { IncludesPipe } from 'xforge-common/includes.pipe'; -import { QuillFormatRegistryService } from '../../../../shared/text/quill-editor-registration/quill-format-registry.service'; -import { EditorReadyService } from './base-services/editor-ready.service'; -import { EditorSegmentService } from './base-services/editor-segment.service'; -import { InsightRenderService } from './base-services/insight-render.service'; -import { LynxInsightActionPromptComponent } from './lynx-insight-action-prompt/lynx-insight-action-prompt.component'; -import { LynxInsightEditorObjectsComponent } from './lynx-insight-editor-objects/lynx-insight-editor-objects.component'; -import { LynxInsightOverlayComponent } from './lynx-insight-overlay/lynx-insight-overlay.component'; -import { LynxInsightScrollPositionIndicatorComponent } from './lynx-insight-scroll-position-indicator/lynx-insight-scroll-position-indicator.component'; -import { LynxInsightStatusIndicatorComponent } from './lynx-insight-status-indicator/lynx-insight-status-indicator.component'; -import { LynxInsightsPanelHeaderComponent } from './lynx-insights-panel/lynx-insights-panel-header/lynx-insights-panel-header.component'; -import { LynxInsightsPanelComponent } from './lynx-insights-panel/lynx-insights-panel.component'; -import { LynxWorkspaceService, TextDocReader } from './lynx-workspace.service'; -import { lynxInsightBlots } from './quill-services/blots/lynx-insight-blot'; -import { QuillEditorReadyService } from './quill-services/quill-editor-ready.service'; -import { QuillEditorSegmentService } from './quill-services/quill-editor-segment.service'; -import { QuillInsightRenderService } from './quill-services/quill-insight-render.service'; - -@NgModule({ - declarations: [ - LynxInsightActionPromptComponent, - LynxInsightEditorObjectsComponent, - LynxInsightsPanelComponent, - LynxInsightsPanelHeaderComponent, - LynxInsightOverlayComponent, - LynxInsightScrollPositionIndicatorComponent, - LynxInsightStatusIndicatorComponent - ], - imports: [ - CommonModule, - BidiModule, - TranslocoModule, - MatButtonModule, - MatDividerModule, - MatIconModule, - MatMenuModule, - MatProgressBarModule, - MatProgressSpinnerModule, - MatRippleModule, - MatTabsModule, - MatTooltipModule, - MatTreeModule, - OverlayModule, - IncludesPipe - ], - exports: [LynxInsightEditorObjectsComponent, LynxInsightsPanelComponent] -}) -export class LynxInsightsModule { - static forRoot(): ModuleWithProviders { - return { - ngModule: LynxInsightsModule, - providers: [ - { - provide: DocumentManager, - useFactory: createLynxDocumentManager, - deps: [TextDocReader] - }, - provideAppInitializer(() => { - const initializerFn = moduleInit(inject(LynxWorkspaceService)); - return initializerFn(); - }), - provideAppInitializer(() => { - const initializerFn = ((formatRegistry: QuillFormatRegistryService) => () => { - formatRegistry.registerFormats(lynxInsightBlots); - })(inject(QuillFormatRegistryService)); - return initializerFn(); - }), - { provide: EditorReadyService, useClass: QuillEditorReadyService }, - { provide: InsightRenderService, useClass: QuillInsightRenderService }, - { provide: EditorSegmentService, useClass: QuillEditorSegmentService } - ] - }; - } -} - -function createLynxDocumentManager( - documentReader: DocumentReader -): DocumentManager { - const documentFactory = new ScriptureDeltaDocumentFactory(); - return new DocumentManager(documentFactory, documentReader); -} - -function moduleInit(lynxWorkspaceService: LynxWorkspaceService): () => Promise { - return () => { - return lynxWorkspaceService.init(); - }; -} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-workspace.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-workspace.service.spec.ts index 41a0b0f0c9d..d0182960c30 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-workspace.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/lynx/insights/lynx-workspace.service.spec.ts @@ -14,7 +14,7 @@ import { ActivatedProjectService } from 'xforge-common/activated-project.service import { I18nService } from 'xforge-common/i18n.service'; import { Locale } from 'xforge-common/models/i18n-locale'; import { RealtimeService } from 'xforge-common/realtime.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { configureTestingModule } from 'xforge-common/test-utils'; import { SFProjectProfileDoc } from '../../../../core/models/sf-project-profile-doc'; @@ -328,8 +328,9 @@ describe('LynxWorkspaceService', () => { } configureTestingModule(() => ({ - imports: [BrowserModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [BrowserModule], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), LynxWorkspaceService, { provide: SFProjectService, useMock: mockProjectService }, { provide: I18nService, useMock: mockI18nService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/multi-viewer/multi-viewer.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/multi-viewer/multi-viewer.component.ts index 6f6e8f21ef2..b6a6d2d1387 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/multi-viewer/multi-viewer.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/multi-viewer/multi-viewer.component.ts @@ -1,9 +1,14 @@ import { BreakpointObserver } from '@angular/cdk/layout'; import { Component, DestroyRef, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { MatMiniFabButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { MatTooltip } from '@angular/material/tooltip'; import { translate } from '@ngneat/transloco'; import { slice } from 'lodash-es'; import { UserProfile } from 'realtime-server/lib/esm/common/models/user'; import { combineLatest } from 'rxjs'; +import { AvatarComponent } from 'xforge-common/avatar/avatar.component'; import { Breakpoint, MediaBreakpointService } from 'xforge-common/media-breakpoints/media-breakpoint.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; export interface MultiCursorViewer extends UserProfile { @@ -15,7 +20,7 @@ export interface MultiCursorViewer extends UserProfile { selector: 'app-multi-viewer', templateUrl: './multi-viewer.component.html', styleUrls: ['./multi-viewer.component.scss'], - standalone: false + imports: [MatTooltip, AvatarComponent, MatMiniFabButton, MatMenuTrigger, MatIcon, MatMenu, MatMenuItem] }) export class MultiViewerComponent implements OnInit { @Input() viewers: MultiCursorViewer[] = []; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/note-dialog/note-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/note-dialog/note-dialog.component.spec.ts index 4c7aba27d67..17b78c25348 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/note-dialog/note-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/note-dialog/note-dialog.component.spec.ts @@ -1,9 +1,9 @@ import { HttpClient } from '@angular/common/http'; -import { DebugElement, NgModule } from '@angular/core'; +import { DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { translate } from '@ngneat/transloco'; import { VerseRef } from '@sillsdev/scripture'; import { cloneDeep } from 'lodash-es'; @@ -40,9 +40,14 @@ import { anything, mock, verify, when } from 'ts-mockito'; import { DialogService } from 'xforge-common/dialog.service'; import { FontService } from 'xforge-common/font.service'; import { UserProfileDoc } from 'xforge-common/models/user-profile-doc'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { ChildViewContainerComponent, configureTestingModule, matDialogCloseDelay } from 'xforge-common/test-utils'; +import { + ChildViewContainerComponent, + configureTestingModule, + getTestTranslocoModule, + matDialogCloseDelay +} from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { BiblicalTermDoc } from '../../../core/models/biblical-term-doc'; import { NoteThreadDoc } from '../../../core/models/note-thread-doc'; @@ -52,7 +57,6 @@ import { SFProjectUserConfigDoc } from '../../../core/models/sf-project-user-con import { SF_TYPE_REGISTRY } from '../../../core/models/sf-type-registry'; import { TextDoc, TextDocId } from '../../../core/models/text-doc'; import { getCombinedVerseTextDoc, getTextDoc, paratextUsersFromRoles } from '../../../shared/test-utils'; -import { TranslateModule } from '../../translate.module'; import { NoteDialogComponent, NoteDialogData, NoteDialogResult } from './note-dialog.component'; const mockedDialogService = mock(DialogService); @@ -62,12 +66,14 @@ const mockedUserService = mock(UserService); describe('NoteDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, NoopAnimationsModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [NoteDialogComponent, getTestTranslocoModule()], providers: [ { provide: DialogService, useMock: mockedDialogService }, { provide: FontService, useMock: mockedFontService }, { provide: HttpClient, useMock: mockedHttpClient }, - { provide: UserService, useMock: mockedUserService } + { provide: UserService, useMock: mockedUserService }, + provideTestRealtime(SF_TYPE_REGISTRY), + provideNoopAnimations() ] })); @@ -691,11 +697,6 @@ describe('NoteDialogComponent', () => { })); }); -@NgModule({ - imports: [TranslateModule] -}) -class DialogTestModule {} - interface TestEnvironmentConstructorArgs { includeSnapshots?: boolean; isRightToLeftProject?: boolean; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/note-dialog/note-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/note-dialog/note-dialog.component.ts index 9e90d04fe36..19ccf81e877 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/note-dialog/note-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/note-dialog/note-dialog.component.ts @@ -1,6 +1,23 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { NgClass, NgStyle } from '@angular/common'; import { Component, ElementRef, Inject, OnInit } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatButton, MatIconButton } from '@angular/material/button'; +import { MatButtonToggle, MatButtonToggleGroup } from '@angular/material/button-toggle'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatError, MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatInput } from '@angular/material/input'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { VerseRef } from '@sillsdev/scripture'; import { sortBy } from 'lodash-es'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; @@ -65,7 +82,31 @@ type SaveOption = 'save' | 'resolve'; @Component({ templateUrl: './note-dialog.component.html', styleUrls: ['./note-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + NgClass, + MatIconButton, + MatMenuTrigger, + MatIcon, + MatMenu, + MatMenuItem, + NgStyle, + MatTooltip, + FormsModule, + ReactiveFormsModule, + MatFormField, + MatLabel, + MatInput, + MatError, + MatDialogActions, + MatButton, + MatDialogClose, + MatButtonToggleGroup, + MatButtonToggle + ] }) export class NoteDialogComponent implements OnInit { showSegmentText: boolean = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/suggestions.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/suggestions.component.ts index 9827371e08c..63628e65ab1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/suggestions.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/suggestions.component.ts @@ -21,7 +21,7 @@ export interface Suggestion { selector: 'app-suggestions', templateUrl: './suggestions.component.html', styleUrls: ['./suggestions.component.scss'], - standalone: false + imports: [MatSelectionList, MatListOption] }) export class SuggestionsComponent { @Output() selected = new EventEmitter(); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/suggestions.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/suggestions.stories.ts index bf688e2db10..827074bcc8d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/suggestions.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/suggestions.stories.ts @@ -1,7 +1,5 @@ -import { CommonModule } from '@angular/common'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { expect, within } from '@storybook/test'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { SuggestionsComponent } from './suggestions.component'; const meta: Meta = { @@ -9,8 +7,7 @@ const meta: Meta = { component: SuggestionsComponent, decorators: [ moduleMetadata({ - imports: [CommonModule, UICommonModule], - declarations: [SuggestionsComponent] + imports: [SuggestionsComponent] }) ] }; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-request.service.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-request.service.ts index 1dd71af371a..588f3545fcb 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-request.service.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-request.service.ts @@ -6,8 +6,7 @@ import { filterNullish } from 'xforge-common/util/rxjs-util'; import { SFProjectDoc } from '../../../core/models/sf-project-doc'; import { PermissionsService } from '../../../core/permissions.service'; import { SFProjectService } from '../../../core/sf-project.service'; -import { TabStateService } from '../../../shared/sf-tab-group'; -import { TabAddRequestService } from '../../../shared/sf-tab-group/base-services/tab-add-request.service'; +import { TabAddRequestService, TabStateService } from '../../../shared/sf-tab-group'; import { EditorTabAddResourceDialogComponent, EditorTabAddResourceDialogData diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component.spec.ts index cd1613d4b88..872d59d51ef 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component.spec.ts @@ -1,15 +1,14 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { provideAnimations } from '@angular/platform-browser/animations'; - import { SFProject } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { createTestProject } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; import { BehaviorSubject } from 'rxjs'; import { anything, mock, verify, when } from 'ts-mockito'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { SFUserProjectsService } from 'xforge-common/user-projects.service'; import { ParatextProject } from '../../../../core/models/paratext-project'; import { SFProjectDoc } from '../../../../core/models/sf-project-doc'; @@ -27,8 +26,9 @@ const mockProjectsService = mock(SFUserProjectsService); describe('EditorTabAddResourceDialogComponent', () => { configureTestingModule(() => ({ - imports: [TestOnlineStatusModule.forRoot(), TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ + provideTestOnlineStatus(), provideAnimations(), { provide: SFProjectService, useMock: mockSFProjectService }, { provide: ParatextService, useMock: mockParatextService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component.ts index e19af21f3c2..8f338b8ca3b 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component.ts @@ -1,6 +1,18 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { AsyncPipe } from '@angular/common'; import { Component, DestroyRef, Inject, OnInit } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatError } from '@angular/material/form-field'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { TranslocoModule } from '@ngneat/transloco'; import { map, repeat, take, timer } from 'rxjs'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; @@ -9,6 +21,8 @@ import { SFProjectDoc } from '../../../../core/models/sf-project-doc'; import { SelectableProject } from '../../../../core/paratext.service'; import { PermissionsService } from '../../../../core/permissions.service'; import { SFProjectService } from '../../../../core/sf-project.service'; +import { ProjectSelectComponent } from '../../../../project-select/project-select.component'; +import { SyncProgressComponent } from '../../../../sync/sync-progress/sync-progress.component'; import { EditorTabAddResourceDialogService } from './editor-tab-add-resource-dialog.service'; export interface EditorTabAddResourceDialogData { excludedParatextIds: string[]; @@ -18,7 +32,21 @@ export interface EditorTabAddResourceDialogData { selector: 'app-editor-tab-add-resource-dialog', templateUrl: './editor-tab-add-resource-dialog.component.html', styleUrls: ['./editor-tab-add-resource-dialog.component.scss'], - standalone: false + imports: [ + MatProgressBar, + SyncProgressComponent, + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + FormsModule, + ReactiveFormsModule, + ProjectSelectComponent, + MatError, + MatDialogActions, + MatButton, + AsyncPipe + ] }) export class EditorTabAddResourceDialogComponent implements OnInit { projects?: ParatextProject[]; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.stories.ts index 63db162b70f..d23ad8b1fd9 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.stories.ts @@ -3,9 +3,7 @@ import { provideAnimations } from '@angular/platform-browser/animations'; import { Meta, moduleMetadata } from '@storybook/angular'; import { of } from 'rxjs'; import { instance, mock, when } from 'ts-mockito'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { XForgeCommonModule } from 'xforge-common/xforge-common.module'; import { MatDialogLaunchComponent, matDialogStory, @@ -119,7 +117,7 @@ const meta: Meta = { export default meta; const dialogStoryConfig: MatDialogStoryConfig = { - imports: [XForgeCommonModule, I18nStoryModule], + imports: [EditorTabAddResourceDialogComponent], providers: [ provideAnimations(), { provide: EditorTabAddResourceDialogService, useValue: instance(mockEditorTabAddResourceDialogService) }, @@ -129,9 +127,7 @@ const dialogStoryConfig: MatDialogStoryConfig = { { provide: MatDialogRef, useValue: instance(mockMatDialogRef) }, { provide: OnlineStatusService, useValue: instance(mockOnlineStatusService) }, { provide: MAT_DIALOG_DATA, useValue: {} } - ], - declarations: [EditorTabAddResourceDialogComponent], - standaloneComponent: true + ] }; // List of stories. diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-menu.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-menu.service.spec.ts index d171eb2e0ea..8937541d41b 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-menu.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/tabs/editor-tab-menu.service.spec.ts @@ -7,10 +7,10 @@ import { anything, mock, when } from 'ts-mockito'; import { v4 as uuid } from 'uuid'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../../core/models/sf-type-registry'; @@ -31,8 +31,10 @@ const mockDraftGenerationService = mock(DraftGenerationService); describe('EditorTabMenuService', () => { configureTestingModule(() => ({ - imports: [TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), TestOnlineStatusModule.forRoot(), TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), + provideTestOnlineStatus(), EditorTabMenuService, { provide: ActivatedProjectService, useMock: mockActivatedProject }, { provide: TabStateService, useMock: mockTabState }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translate-metrics-session.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translate-metrics-session.spec.ts index fb2121d3280..4fd77aba77b 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translate-metrics-session.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translate-metrics-session.spec.ts @@ -11,19 +11,19 @@ import { CommandError, CommandErrorCode } from 'xforge-common/command.service'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; import { UserDoc } from 'xforge-common/models/user-doc'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { TextDoc, TextDocId } from '../../core/models/text-doc'; import { TranslateMetrics } from '../../core/models/translate-metrics'; import { SFProjectService } from '../../core/sf-project.service'; -import { SharedModule } from '../../shared/shared.module'; import { getTextDoc } from '../../shared/test-utils'; +import { provideQuillRegistrations } from '../../shared/text/quill-editor-registration/quill-providers'; import { EDITOR_READY_TIMEOUT, TextComponent } from '../../shared/text/text.component'; import { ACTIVE_EDIT_TIMEOUT, @@ -38,15 +38,11 @@ const mockedReportingService = mock(ErrorReportingService); describe('TranslateMetricsSession', () => { configureTestingModule(() => ({ - declarations: [TextComponent], - imports: [ - QuillModule.forRoot(), - TestTranslocoModule, - SharedModule.forRoot(), - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) - ], + imports: [TextComponent, QuillModule.forRoot(), getTestTranslocoModule()], providers: [ + provideQuillRegistrations(), + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: SFProjectService, useMock: mockedSFProjectService }, { provide: UserService, useMock: mockedUserService } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translator-settings-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translator-settings-dialog.component.spec.ts index 0831b0903ec..9e82e996444 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translator-settings-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translator-settings-dialog.component.spec.ts @@ -1,14 +1,13 @@ import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; -import { CommonModule } from '@angular/common'; -import { DebugElement, NgModule } from '@angular/core'; +import { DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { MatSelect } from '@angular/material/select'; import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing'; import { MatSlider } from '@angular/material/slider'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data'; @@ -19,17 +18,16 @@ import { } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-user-config'; import { createTestProjectUserConfig } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-user-config-test-data'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { ChildViewContainerComponent, configureTestingModule, - matDialogCloseDelay, - TestTranslocoModule + getTestTranslocoModule, + matDialogCloseDelay } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SFProjectUserConfigDoc } from '../../core/models/sf-project-user-config-doc'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; @@ -42,13 +40,13 @@ import { describe('TranslatorSettingsDialogComponent', () => { configureTestingModule(() => ({ - imports: [ - DialogTestModule, - NoopAnimationsModule, - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY) - ], - providers: [{ provide: OnlineStatusService, useClass: TestOnlineStatusService }] + imports: [getTestTranslocoModule(), NoticeComponent, TranslatorSettingsDialogComponent], + providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), + { provide: OnlineStatusService, useClass: TestOnlineStatusService }, + provideNoopAnimations() + ] })); it('update confidence threshold', fakeAsync(() => { @@ -312,12 +310,6 @@ describe('TranslatorSettingsDialogComponent', () => { }); }); -@NgModule({ - imports: [CommonModule, UICommonModule, TestTranslocoModule, NoticeComponent], - declarations: [TranslatorSettingsDialogComponent] -}) -class DialogTestModule {} - interface TestEnvironmentConstructorArgs { translationSuggestionsEnabled?: boolean; } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translator-settings-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translator-settings-dialog.component.ts index 5efc6375957..889a59624e8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translator-settings-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/translator-settings-dialog.component.ts @@ -1,12 +1,29 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { AsyncPipe } from '@angular/common'; import { Component, DestroyRef, Inject, OnInit } from '@angular/core'; -import { FormControl } from '@angular/forms'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatOption } from '@angular/material/autocomplete'; +import { MatButton } from '@angular/material/button'; +import { MatCard, MatCardContent } from '@angular/material/card'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatSelect } from '@angular/material/select'; +import { MatSlideToggle } from '@angular/material/slide-toggle'; +import { MatSlider, MatSliderThumb } from '@angular/material/slider'; +import { TranslocoModule } from '@ngneat/transloco'; import { BehaviorSubject } from 'rxjs'; import { debounceTime, map, skip, startWith } from 'rxjs/operators'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SFProjectUserConfigDoc } from '../../core/models/sf-project-user-config-doc'; +import { NoticeComponent } from '../../shared/notice/notice.component'; export const CONFIDENCE_THRESHOLD_TIMEOUT = 500; @@ -18,7 +35,28 @@ export interface TranslatorSettingsDialogData { @Component({ templateUrl: './translator-settings-dialog.component.html', styleUrls: ['./translator-settings-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + MatCard, + MatCardContent, + NoticeComponent, + MatSlideToggle, + FormsModule, + ReactiveFormsModule, + MatFormField, + MatLabel, + MatSelect, + MatOption, + MatSlider, + MatSliderThumb, + MatDialogActions, + MatButton, + MatDialogClose, + AsyncPipe + ] }) export class TranslatorSettingsDialogComponent implements OnInit { readonly suggestionsEnabledSwitch = new FormControl({ diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/font-unsupported-message/font-unsupported-message.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/font-unsupported-message/font-unsupported-message.component.ts index c431b49c589..f18874ad745 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/font-unsupported-message/font-unsupported-message.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/font-unsupported-message/font-unsupported-message.component.ts @@ -1,4 +1,4 @@ -import { CommonModule } from '@angular/common'; +import { AsyncPipe } from '@angular/common'; import { Component } from '@angular/core'; import { TranslocoModule } from '@ngneat/transloco'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; @@ -12,7 +12,7 @@ import { NoticeComponent } from '../../shared/notice/notice.component'; @Component({ selector: 'app-font-unsupported-message', - imports: [CommonModule, NoticeComponent, TranslocoModule], + imports: [AsyncPipe, NoticeComponent, TranslocoModule], templateUrl: './font-unsupported-message.component.html', styleUrl: './font-unsupported-message.component.scss' }) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/nllb-language.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/nllb-language.service.spec.ts index 37917060ada..abad9f6d619 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/nllb-language.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/nllb-language.service.spec.ts @@ -4,7 +4,7 @@ import { fakeAsync, TestBed } from '@angular/core/testing'; import { of, throwError } from 'rxjs'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; import { HttpClient } from '../machine-api/http-client'; import { NllbLanguageService } from './nllb-language.service'; @@ -20,8 +20,8 @@ describe('NllbLanguageService', () => { beforeEach(() => { mockErrorReportingService = jasmine.createSpyObj(['silentError']); TestBed.configureTestingModule({ - imports: [TestOnlineStatusModule.forRoot()], providers: [ + provideTestOnlineStatus(), { provide: NLLB_LANGUAGES, useValue: { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/training-progress/training-progress.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/training-progress/training-progress.component.spec.ts index 18171f8232a..22fb9a63e0d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/training-progress/training-progress.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/training-progress/training-progress.component.spec.ts @@ -9,10 +9,9 @@ import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge import * as RichText from 'rich-text'; import { defer, Subject } from 'rxjs'; import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; @@ -26,9 +25,9 @@ const mockedUserService = mock(UserService); describe('TrainingProgressComponent', () => { configureTestingModule(() => ({ - imports: [TestTranslocoModule, UICommonModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], - declarations: [TrainingProgressComponent], + imports: [TrainingProgressComponent, getTestTranslocoModule()], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), { provide: TranslationEngineService, useMock: mockedTranslationEngineService }, { provide: UserService, useMock: mockedUserService }, provideHttpClient(withInterceptorsFromDi()), diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/training-progress/training-progress.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/training-progress/training-progress.component.ts index c56d0d22bdc..03bf060380f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/training-progress/training-progress.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/training-progress/training-progress.component.ts @@ -1,23 +1,27 @@ import { Component, DestroyRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { TranslocoModule } from '@ngneat/transloco'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; import { BehaviorSubject, Subscription, timer } from 'rxjs'; import { filter, repeat, retry, tap } from 'rxjs/operators'; import { DataLoadingComponent } from 'xforge-common/data-loading-component'; +import { DonutChartComponent } from 'xforge-common/donut-chart/donut-chart.component'; +import { I18nService } from 'xforge-common/i18n.service'; import { NoticeService } from 'xforge-common/notice.service'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; - -import { I18nService } from 'xforge-common/i18n.service'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SFProjectService } from '../../core/sf-project.service'; import { TranslationEngineService } from '../../core/translation-engine.service'; import { RemoteTranslationEngine } from '../../machine-api/remote-translation-engine'; + @Component({ selector: 'app-training-progress', templateUrl: './training-progress.component.html', styleUrls: ['./training-progress.component.scss'], - standalone: false + imports: [TranslocoModule, MatIconButton, MatIcon, DonutChartComponent] }) export class TrainingProgressComponent extends DataLoadingComponent implements OnInit, OnDestroy { showTrainingProgress: boolean = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-overview/translate-overview.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-overview/translate-overview.component.spec.ts index f3cb3c2800b..3171f202b05 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-overview/translate-overview.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-overview/translate-overview.component.spec.ts @@ -22,12 +22,11 @@ import { L10nPercentPipe } from 'xforge-common/l10n-percent.pipe'; import { UserDoc } from 'xforge-common/models/user-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; @@ -50,16 +49,16 @@ const mockedProgressService = mock(ProgressService); describe('TranslateOverviewComponent', () => { configureTestingModule(() => ({ - declarations: [TranslateOverviewComponent, TrainingProgressComponent], imports: [ - UICommonModule, - TestTranslocoModule, - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), + TrainingProgressComponent, + TranslateOverviewComponent, + getTestTranslocoModule(), FontUnsupportedMessageComponent, L10nPercentPipe ], providers: [ + provideTestOnlineStatus(), + provideTestRealtime(SF_TYPE_REGISTRY), { provide: AuthService, useMock: mockedAuthService }, { provide: ActivatedRoute, useMock: mockedActivatedRoute }, { provide: TranslationEngineService, useMock: mockedTranslationEngineService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-overview/translate-overview.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-overview/translate-overview.component.ts index ddb2c87361c..9e58c32d5a9 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-overview/translate-overview.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-overview/translate-overview.component.ts @@ -1,6 +1,21 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Component, DestroyRef, OnDestroy, OnInit } from '@angular/core'; +import { MatButton } from '@angular/material/button'; +import { MatCard, MatCardActions, MatCardContent, MatCardHeader, MatCardTitle } from '@angular/material/card'; +import { MatDivider } from '@angular/material/divider'; +import { MatIcon } from '@angular/material/icon'; +import { + MatList, + MatListItem, + MatListItemIcon, + MatListItemLine, + MatListItemMeta, + MatListItemTitle +} from '@angular/material/list'; +import { MatProgressBar } from '@angular/material/progress-bar'; +import { MatTooltip } from '@angular/material/tooltip'; import { ActivatedRoute } from '@angular/router'; +import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { ANY_INDEX, obj } from 'realtime-server/lib/esm/common/utils/obj-path'; @@ -12,9 +27,13 @@ import { asyncScheduler, firstValueFrom, Subscription, timer } from 'rxjs'; import { filter, map, repeat, retry, tap, throttleTime } from 'rxjs/operators'; import { AuthService } from 'xforge-common/auth.service'; import { DataLoadingComponent } from 'xforge-common/data-loading-component'; +import { DonutChartComponent } from 'xforge-common/donut-chart/donut-chart.component'; import { I18nService } from 'xforge-common/i18n.service'; +import { L10nNumberPipe } from 'xforge-common/l10n-number.pipe'; +import { L10nPercentPipe } from 'xforge-common/l10n-percent.pipe'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; +import { RouterLinkDirective } from 'xforge-common/router-link.directive'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; @@ -22,6 +41,8 @@ import { SFProjectService } from '../../core/sf-project.service'; import { TranslationEngineService } from '../../core/translation-engine.service'; import { RemoteTranslationEngine } from '../../machine-api/remote-translation-engine'; import { ProgressService, TextProgress } from '../../shared/progress-service/progress.service'; +import { FontUnsupportedMessageComponent } from '../font-unsupported-message/font-unsupported-message.component'; +import { TrainingProgressComponent } from '../training-progress/training-progress.component'; const ENGINE_QUALITY_STAR_COUNT = 3; const TEXT_PATH_TEMPLATE = obj().pathTemplate(p => p.texts[ANY_INDEX]); @@ -29,7 +50,31 @@ const TEXT_PATH_TEMPLATE = obj().pathTemplate(p => p.texts[ANY_INDEX] selector: 'app-translate-overview', templateUrl: './translate-overview.component.html', styleUrls: ['./translate-overview.component.scss'], - standalone: false + imports: [ + TranslocoModule, + FontUnsupportedMessageComponent, + MatCard, + MatCardHeader, + MatCardTitle, + MatTooltip, + DonutChartComponent, + MatDivider, + MatList, + MatListItem, + RouterLinkDirective, + MatIcon, + MatListItemIcon, + MatListItemTitle, + MatListItemLine, + MatListItemMeta, + MatProgressBar, + MatCardContent, + MatCardActions, + MatButton, + TrainingProgressComponent, + L10nNumberPipe, + L10nPercentPipe + ] }) export class TranslateOverviewComponent extends DataLoadingComponent implements OnInit, OnDestroy { trainingPercentage: number = 0; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-routing.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-routing.module.ts deleted file mode 100644 index e7d1abaa6d6..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate-routing.module.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { DraftNavigationAuthGuard, NmtDraftAuthGuard, TranslateAuthGuard } from '../shared/project-router.guard'; -import { DraftGenerationComponent } from './draft-generation/draft-generation.component'; -import { DraftSourcesComponent } from './draft-generation/draft-sources/draft-sources.component'; -import { DraftUsfmFormatComponent } from './draft-generation/draft-usfm-format/draft-usfm-format.component'; -import { EditorComponent } from './editor/editor.component'; -import { TranslateOverviewComponent } from './translate-overview/translate-overview.component'; - -const routes: Routes = [ - { - path: 'projects/:projectId/translate/:bookId/:chapter', - component: EditorComponent, - canActivate: [TranslateAuthGuard] - }, - { path: 'projects/:projectId/translate/:bookId', component: EditorComponent, canActivate: [TranslateAuthGuard] }, - { path: 'projects/:projectId/translate', component: TranslateOverviewComponent, canActivate: [TranslateAuthGuard] }, - { - path: 'projects/:projectId/draft-generation', - component: DraftGenerationComponent, - canActivate: [NmtDraftAuthGuard] - }, - { - path: 'projects/:projectId/draft-generation/sources', - component: DraftSourcesComponent, - canActivate: [NmtDraftAuthGuard], - canDeactivate: [DraftNavigationAuthGuard] - }, - { - path: 'projects/:projectId/draft-generation/format', - component: DraftUsfmFormatComponent, - canActivate: [NmtDraftAuthGuard], - canDeactivate: [DraftNavigationAuthGuard] - }, - { - path: 'projects/:projectId/draft-generation/format/:bookId', - component: DraftUsfmFormatComponent, - canActivate: [NmtDraftAuthGuard], - canDeactivate: [DraftNavigationAuthGuard] - }, - { - path: 'projects/:projectId/draft-generation/format/:bookId/:chapter', - component: DraftUsfmFormatComponent, - canActivate: [NmtDraftAuthGuard], - canDeactivate: [DraftNavigationAuthGuard] - } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class TranslateRoutingModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate.module.ts deleted file mode 100644 index a1d6704e7a0..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/translate.module.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { TranslocoModule } from '@ngneat/transloco'; -import { AngularSplitModule } from 'angular-split'; -import { TranslocoMarkupModule } from 'ngx-transloco-markup'; -import { AvatarComponent } from 'xforge-common/avatar/avatar.component'; -import { L10nPercentPipe } from 'xforge-common/l10n-percent.pipe'; -import { UICommonModule } from 'xforge-common/ui-common.module'; -import { XForgeCommonModule } from 'xforge-common/xforge-common.module'; -import { CopyrightBannerComponent } from '../shared/copyright-banner/copyright-banner.component'; -import { SFTabsModule } from '../shared/sf-tab-group'; -import { SharedModule } from '../shared/shared.module'; -import { BiblicalTermDialogComponent } from './biblical-terms/biblical-term-dialog.component'; -import { BiblicalTermsComponent } from './biblical-terms/biblical-terms.component'; -import { DraftApplyProgressDialogComponent } from './draft-generation/draft-apply-progress-dialog/draft-apply-progress-dialog.component'; -import { DraftPreviewBooksComponent } from './draft-generation/draft-preview-books/draft-preview-books.component'; -import { EditorDraftComponent } from './editor/editor-draft/editor-draft.component'; -import { EditorHistoryComponent } from './editor/editor-history/editor-history.component'; -import { HistoryChooserComponent } from './editor/editor-history/history-chooser/history-chooser.component'; -import { HistoryRevisionFormatPipe } from './editor/editor-history/history-chooser/history-revision-format.pipe'; -import { EditorResourceComponent } from './editor/editor-resource/editor-resource.component'; -import { EditorComponent } from './editor/editor.component'; -import { LynxInsightsModule } from './editor/lynx/insights/lynx-insights.module'; -import { MultiViewerComponent } from './editor/multi-viewer/multi-viewer.component'; -import { NoteDialogComponent } from './editor/note-dialog/note-dialog.component'; -import { SuggestionsComponent } from './editor/suggestions.component'; -import { EditorTabAddResourceDialogComponent } from './editor/tabs/editor-tab-add-resource-dialog/editor-tab-add-resource-dialog.component'; -import { TranslatorSettingsDialogComponent } from './editor/translator-settings-dialog.component'; -import { FontUnsupportedMessageComponent } from './font-unsupported-message/font-unsupported-message.component'; -import { TrainingProgressComponent } from './training-progress/training-progress.component'; -import { TranslateOverviewComponent } from './translate-overview/translate-overview.component'; -import { TranslateRoutingModule } from './translate-routing.module'; - -@NgModule({ - declarations: [ - BiblicalTermDialogComponent, - EditorComponent, - MultiViewerComponent, - NoteDialogComponent, - SuggestionsComponent, - TranslatorSettingsDialogComponent, - TrainingProgressComponent, - TranslateOverviewComponent, - HistoryChooserComponent, - EditorHistoryComponent, - EditorDraftComponent, - HistoryRevisionFormatPipe, - EditorTabAddResourceDialogComponent, - EditorResourceComponent - ], - imports: [ - AngularSplitModule, - TranslateRoutingModule, - CommonModule, - SharedModule, - UICommonModule, - XForgeCommonModule, - TranslocoModule, - TranslocoMarkupModule, - AvatarComponent, - SFTabsModule, - BiblicalTermsComponent, - CopyrightBannerComponent, - DraftPreviewBooksComponent, - DraftApplyProgressDialogComponent, - FontUnsupportedMessageComponent, - LynxInsightsModule, - L10nPercentPipe - ] -}) -export class TranslateModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/users/collaborators/collaborators.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/users/collaborators/collaborators.component.spec.ts index a91384e9b15..f02819d551e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/users/collaborators/collaborators.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/users/collaborators/collaborators.component.spec.ts @@ -4,7 +4,7 @@ import { DebugElement, getDebugNode } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatMenuHarness } from '@angular/material/menu/testing'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { UserProfile } from 'realtime-server/lib/esm/common/models/user'; import { createTestUserProfile } from 'realtime-server/lib/esm/common/models/user-test-data'; import { CheckingAnswerExport, CheckingConfig } from 'realtime-server/lib/esm/scriptureforge/models/checking-config'; @@ -22,20 +22,19 @@ import { NONE_ROLE, ProjectRoleInfo } from 'xforge-common/models/project-role-in import { UserProfileDoc } from 'xforge-common/models/user-profile-doc'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; -import { configureTestingModule, emptyHammerLoader, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, emptyHammerLoader, getTestTranslocoModule } from 'xforge-common/test-utils'; import { UserService } from 'xforge-common/user.service'; import { SFProjectDoc } from '../../core/models/sf-project-doc'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SF_PROJECT_ROLES } from '../../core/models/sf-project-role-info'; import { SF_TYPE_REGISTRY } from '../../core/models/sf-type-registry'; import { SFProjectService } from '../../core/sf-project.service'; -import { SharedModule } from '../../shared/shared.module'; import { paratextUsersFromRoles } from '../../shared/test-utils'; +import { provideQuillRegistrations } from '../../shared/text/quill-editor-registration/quill-providers'; import { CollaboratorsComponent, UserType } from './collaborators.component'; const mockedActivatedProject = mock(ActivatedProjectService); @@ -46,24 +45,19 @@ const mockedDialogService = mock(DialogService); describe('CollaboratorsComponent', () => { configureTestingModule(() => ({ - declarations: [CollaboratorsComponent], - imports: [ - NoopAnimationsModule, - UICommonModule, - TestTranslocoModule, - TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), - SharedModule.forRoot(), - TestOnlineStatusModule.forRoot(), - AvatarComponent - ], + imports: [CollaboratorsComponent, getTestTranslocoModule(), AvatarComponent], providers: [ + provideQuillRegistrations(), + provideTestRealtime(SF_TYPE_REGISTRY), + provideTestOnlineStatus(), { provide: ActivatedProjectService, useMock: mockedActivatedProject }, { provide: NoticeService, useMock: mockedNoticeService }, { provide: SFProjectService, useMock: mockedProjectService }, { provide: UserService, useMock: mockedUserService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: DialogService, useMock: mockedDialogService }, - emptyHammerLoader + emptyHammerLoader, + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/users/collaborators/collaborators.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/users/collaborators/collaborators.component.ts index 962886a476d..06ce66e0a90 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/users/collaborators/collaborators.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/users/collaborators/collaborators.component.ts @@ -1,11 +1,21 @@ import { Component, DestroyRef, OnInit } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { MatIconButton } from '@angular/material/button'; +import { MatFormField, MatHint, MatLabel } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatInput } from '@angular/material/input'; +import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; +import { MatCell, MatCellDef, MatColumnDef, MatRow, MatRowDef, MatTable } from '@angular/material/table'; +import { MatTab, MatTabGroup } from '@angular/material/tabs'; +import { MatTooltip } from '@angular/material/tooltip'; +import { TranslocoModule } from '@ngneat/transloco'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { ParatextUserProfile } from 'realtime-server/lib/esm/scriptureforge/models/paratext-user-profile'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; import { isParatextRole, SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; import { BehaviorSubject, combineLatest, distinctUntilChanged, filter, tap } from 'rxjs'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; +import { AvatarComponent } from 'xforge-common/avatar/avatar.component'; import { DataLoadingComponent } from 'xforge-common/data-loading-component'; import { DialogService } from 'xforge-common/dialog.service'; import { ExternalUrlService } from 'xforge-common/external-url.service'; @@ -17,7 +27,10 @@ import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { XFValidators } from 'xforge-common/xfvalidators'; import { SFProjectDoc } from '../../core/models/sf-project-doc'; import { SFProjectService } from '../../core/sf-project.service'; +import { NoticeComponent } from '../../shared/notice/notice.component'; +import { ShareControlComponent } from '../../shared/share/share-control.component'; import { RolesAndPermissionsDialogComponent } from '../roles-and-permissions/roles-and-permissions-dialog.component'; + interface UserInfo { displayName?: string; avatarUrl?: string; @@ -55,7 +68,32 @@ export enum UserType { selector: 'app-collaborators', templateUrl: './collaborators.component.html', styleUrls: ['./collaborators.component.scss'], - standalone: false + imports: [ + TranslocoModule, + NoticeComponent, + MatTabGroup, + MatTab, + MatFormField, + FormsModule, + ReactiveFormsModule, + MatLabel, + MatInput, + MatTable, + MatColumnDef, + MatCellDef, + MatCell, + AvatarComponent, + MatTooltip, + MatIcon, + MatIconButton, + MatMenuTrigger, + MatMenu, + MatMenuItem, + MatRowDef, + MatRow, + MatHint, + ShareControlComponent + ] }) export class CollaboratorsComponent extends DataLoadingComponent implements OnInit { userInviteForm = new UntypedFormGroup({ diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/users/roles-and-permissions/roles-and-permissions-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/users/roles-and-permissions/roles-and-permissions-dialog.component.ts index 0e377ed48ef..abbd63a9b97 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/users/roles-and-permissions/roles-and-permissions-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/users/roles-and-permissions/roles-and-permissions-dialog.component.ts @@ -1,18 +1,31 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component, DestroyRef, Inject, OnInit } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButton } from '@angular/material/button'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogTitle +} from '@angular/material/dialog'; +import { MatRadioButton, MatRadioGroup } from '@angular/material/radio'; +import { TranslocoModule } from '@ngneat/transloco'; import { Operation } from 'realtime-server/lib/esm/common/models/project-rights'; import { UserProfile } from 'realtime-server/lib/esm/common/models/user'; import { SFProject } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights'; import { isParatextRole, SFProjectRole } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-role'; import { Subscription } from 'rxjs'; +import { AvatarComponent } from 'xforge-common/avatar/avatar.component'; import { ExternalUrlService } from 'xforge-common/external-url.service'; import { I18nService } from 'xforge-common/i18n.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { SFProjectDoc } from '../../core/models/sf-project-doc'; import { SFProjectService } from '../../core/sf-project.service'; +import { NoticeComponent } from '../../shared/notice/notice.component'; export interface UserData { projectId: string; @@ -24,7 +37,22 @@ export interface UserData { selector: 'app-roles-and-permissions', templateUrl: './roles-and-permissions-dialog.component.html', styleUrls: ['./roles-and-permissions-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + AvatarComponent, + CdkScrollable, + MatDialogContent, + FormsModule, + ReactiveFormsModule, + NoticeComponent, + MatRadioGroup, + MatRadioButton, + MatCheckbox, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class RolesAndPermissionsDialogComponent implements OnInit { readonly roles: FormControl = new FormControl(''); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/users/roles-and-permissions/roles-and-permissions-dialog.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/users/roles-and-permissions/roles-and-permissions-dialog.spec.ts index 80624dc91f8..66cba45b438 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/users/roles-and-permissions/roles-and-permissions-dialog.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/users/roles-and-permissions/roles-and-permissions-dialog.spec.ts @@ -1,5 +1,5 @@ import { HttpClient, HttpHandler } from '@angular/common/http'; -import { Component, DebugElement, Input, NgModule } from '@angular/core'; +import { Component, DebugElement, Input } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; @@ -22,15 +22,14 @@ import { anything, deepEqual, mock, verify, when } from 'ts-mockito'; import { ExternalUrlService } from 'xforge-common/external-url.service'; import { I18nService } from 'xforge-common/i18n.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { ChildViewContainerComponent, configureTestingModule, - matDialogCloseDelay, - TestTranslocoModule + getTestTranslocoModule, + matDialogCloseDelay } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { SFProjectDoc } from '../../core/models/sf-project-doc'; import { SFProjectProfileDoc } from '../../core/models/sf-project-profile-doc'; import { SFProjectUserConfigDoc } from '../../core/models/sf-project-user-config-doc'; @@ -45,8 +44,9 @@ const mockedProjectService = mock(SFProjectService); describe('RolesAndPermissionsComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule, TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)], + imports: [getTestTranslocoModule(), NoticeComponent, RolesAndPermissionsDialogComponent, FakeAvatarComponent], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), { provide: ExternalUrlService }, { provide: HttpClient }, { provide: HttpHandler }, @@ -194,8 +194,7 @@ describe('RolesAndPermissionsComponent', () => { }); @Component({ - selector: 'app-avatar', - standalone: false + selector: 'app-avatar' }) class FakeAvatarComponent { @Input() user?: UserProfile; @@ -203,12 +202,6 @@ class FakeAvatarComponent { @Input() round?: boolean; } -@NgModule({ - imports: [UICommonModule, TestTranslocoModule, NoticeComponent], - declarations: [RolesAndPermissionsDialogComponent, FakeAvatarComponent] -}) -class DialogTestModule {} - class TestEnvironment { component?: RolesAndPermissionsDialogComponent; readonly isOnline$: BehaviorSubject = new BehaviorSubject(true); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/users/users-routing.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/users/users-routing.module.ts deleted file mode 100644 index eef384eac1a..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/users/users-routing.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { UsersAuthGuard } from '../shared/project-router.guard'; -import { UsersComponent } from './users.component'; - -const routes: Routes = [ - { path: 'projects/:projectId/users', component: UsersComponent, canActivate: [UsersAuthGuard] } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class UsersRoutingModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/users/users.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/users/users.component.ts index 340731ac7b7..fc8fe61a967 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/users/users.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/users/users.component.ts @@ -1,8 +1,10 @@ import { Component } from '@angular/core'; +import { TranslocoModule } from '@ngneat/transloco'; +import { CollaboratorsComponent } from './collaborators/collaborators.component'; @Component({ selector: 'app-users', templateUrl: './users.component.html', - standalone: false + imports: [TranslocoModule, CollaboratorsComponent] }) export class UsersComponent {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/users/users.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/users/users.module.ts deleted file mode 100644 index 0bcb0a2589a..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/users/users.module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { TranslocoModule } from '@ngneat/transloco'; -import { AvatarComponent } from 'xforge-common/avatar/avatar.component'; -import { UICommonModule } from 'xforge-common/ui-common.module'; -import { XForgeCommonModule } from 'xforge-common/xforge-common.module'; -import { SharedModule } from '../shared/shared.module'; -import { CollaboratorsComponent } from './collaborators/collaborators.component'; -import { RolesAndPermissionsDialogComponent } from './roles-and-permissions/roles-and-permissions-dialog.component'; -import { UsersRoutingModule } from './users-routing.module'; -import { UsersComponent } from './users.component'; - -@NgModule({ - declarations: [CollaboratorsComponent, UsersComponent, RolesAndPermissionsDialogComponent], - imports: [ - UsersRoutingModule, - CommonModule, - SharedModule, - UICommonModule, - XForgeCommonModule, - TranslocoModule, - AvatarComponent - ] -}) -export class UsersModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/main.ts b/src/SIL.XForge.Scripture/ClientApp/src/main.ts index 719f9c2d72b..099b5868e4c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/main.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/main.ts @@ -1,22 +1,94 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - +import { OverlayContainer } from '@angular/cdk/overlay'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { + APP_ID, + enableProdMode, + ErrorHandler, + importProvidersFrom, + inject, + provideAppInitializer +} from '@angular/core'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { provideAnimations } from '@angular/platform-browser/animations'; +import { provideRouter, withRouterConfig } from '@angular/router'; +import { ServiceWorkerModule } from '@angular/service-worker'; +import { TranslocoModule, TranslocoService } from '@ngneat/transloco'; +import { CookieService } from 'ngx-cookie-service'; +import { QuillModule } from 'ngx-quill'; +import { + defaultTranslocoMarkupTranspilers, + provideTranslationMarkupTranspiler, + TranslocoMarkupModule +} from 'ngx-transloco-markup'; +import { translocoMarkupRouterLinkRenderer } from 'ngx-transloco-markup-router-link'; import { ExceptionHandlingService } from 'xforge-common/exception-handling.service'; -import { AppModule } from './app/app.module'; +import { EmTextTranspiler } from 'xforge-common/i18n-transpilers/em-text.transpiler'; +import { InAppRootOverlayContainer } from 'xforge-common/overlay-container'; +import { ProjectService } from 'xforge-common/project.service'; +import { TypeRegistry } from 'xforge-common/type-registry'; +import { provideUICommon } from 'xforge-common/ui-common-providers'; +import { provideXForgeCommon } from 'xforge-common/xforge-common-providers'; +import { AppComponent } from './app/app.component'; +import { APP_ROUTES } from './app/app.routes'; +import { SF_TYPE_REGISTRY } from './app/core/models/sf-type-registry'; +import { SFProjectService } from './app/core/sf-project.service'; +import { provideCustomIcons } from './app/shared/custom-icons'; +import { provideSFTabs } from './app/shared/sf-tab-group'; +import { provideQuillRegistrations } from './app/shared/text/quill-editor-registration/quill-providers'; +import { preloadEnglishTranslations } from './app/shared/utils'; +import { provideLynxInsights } from './app/translate/editor/lynx/insights/lynx-insights-providers'; import { environment } from './environments/environment'; export function getBaseUrl(): string { return document.getElementsByTagName('base')[0].href; } -const providers = [{ provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] as any[] }]; - if (environment.production || environment.pwaTest) { enableProdMode(); } ExceptionHandlingService.initBugsnag(); -platformBrowserDynamic(providers) - .bootstrapModule(AppModule, { ngZoneEventCoalescing: true }) - .catch(err => console.log(err)); +bootstrapApplication(AppComponent, { + providers: [ + { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] as any[] }, + { provide: TypeRegistry, useValue: SF_TYPE_REGISTRY }, + { provide: ProjectService, useExisting: SFProjectService }, + provideCustomIcons(), + provideSFTabs(), + provideQuillRegistrations(), + provideLynxInsights(), + provideXForgeCommon(), + provideRouter( + APP_ROUTES, + withRouterConfig({ + // This setting was introduced to prevent canceling the "prompt on leave" dialog for pages like draft-usfm-format + // from mangling the browser history (SF-3577). + canceledNavigationResolution: 'computed' + }) + ), + importProvidersFrom( + ServiceWorkerModule.register('sf-service-worker.js', { + enabled: environment.pwaTest || environment.production, + registrationStrategy: 'registerImmediately' + }), + TranslocoModule, + TranslocoMarkupModule, + QuillModule.forRoot() + ), + { provide: APP_ID, useValue: 'ng-cli-universal' }, + CookieService, + provideAnimations(), + provideUICommon(), + provideTranslationMarkupTranspiler(EmTextTranspiler), + translocoMarkupRouterLinkRenderer(), + defaultTranslocoMarkupTranspilers(), + { provide: ErrorHandler, useClass: ExceptionHandlingService }, + { provide: OverlayContainer, useClass: InAppRootOverlayContainer }, + provideHttpClient(withInterceptorsFromDi()), + provideAppInitializer(() => { + const initializerFn = preloadEnglishTranslations(inject(TranslocoService)); + return initializerFn(); + }) + ] +}).catch(err => console.log(err)); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/activated-project.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/activated-project.service.spec.ts index 8e46202c89b..73f73d8d60e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/activated-project.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/activated-project.service.spec.ts @@ -1,13 +1,12 @@ import { Component } from '@angular/core'; import { fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { Route, Router, RouterModule } from '@angular/router'; +import { provideRouter, Route, Router } from '@angular/router'; import { Subscription } from 'rxjs'; import { ActiveProjectIdService } from './activated-project.service'; import { configureTestingModule } from './test-utils'; @Component({ - template: '
', - standalone: false + template: '
' }) class MockComponent {} @@ -16,7 +15,7 @@ let env: TestEnvironment; describe('ActiveProjectIdService', () => { configureTestingModule(() => ({ - imports: [RouterModule.forRoot(ROUTES)] + providers: [provideRouter(ROUTES)] })); beforeEach(() => (env = new TestEnvironment())); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/auth.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/auth.service.spec.ts index a22ee1c2e35..be3133bc31c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/auth.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/auth.service.spec.ts @@ -1,5 +1,5 @@ import { discardPeriodicTasks, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { Router, RouterModule } from '@angular/router'; +import { provideRouter, Router } from '@angular/router'; import { Auth0Client, GenericError, @@ -36,9 +36,9 @@ import { MemoryRealtimeRemoteStore } from './memory-realtime-remote-store'; import { OfflineStore } from './offline-store'; import { OnlineStatusService } from './online-status.service'; import { SharedbRealtimeRemoteStore } from './sharedb-realtime-remote-store'; -import { TestOnlineStatusModule } from './test-online-status.module'; +import { provideTestOnlineStatus } from './test-online-status-providers'; import { TestOnlineStatusService } from './test-online-status.service'; -import { configureTestingModule, TestTranslocoModule } from './test-utils'; +import { configureTestingModule, getTestTranslocoModule } from './test-utils'; import { aspCultureCookieValue } from './utils'; const mockedAuth0Service = mock(Auth0Service); @@ -55,8 +55,10 @@ const mockedConsole: MockConsole = MockConsole.install(); describe('AuthService', () => { configureTestingModule(() => ({ - imports: [RouterModule.forRoot([]), TestOnlineStatusModule.forRoot(), TestTranslocoModule], + imports: [getTestTranslocoModule()], providers: [ + provideRouter([]), + provideTestOnlineStatus(), AuthService, { provide: Auth0Service, useMock: mockedAuth0Service }, { provide: SharedbRealtimeRemoteStore, useClass: MemoryRealtimeRemoteStore }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/autofocus.directive.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/autofocus.directive.ts index 394103f8cf2..7b02d3be094 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/autofocus.directive.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/autofocus.directive.ts @@ -3,10 +3,7 @@ import { AfterViewInit, Directive, ElementRef } from '@angular/core'; /** * Auto focuses text inputs and textarea. HTML autofocus attribute does not work for dynamically generated content. */ -@Directive({ - selector: '[appAutofocus]', - standalone: false -}) +@Directive({ selector: '[appAutofocus]' }) export class AutofocusDirective implements AfterViewInit { constructor(private readonly elementRef: ElementRef) {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/avatar/avatar.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/avatar/avatar.component.ts index 6780244e1d7..cebbd55cbff 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/avatar/avatar.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/avatar/avatar.component.ts @@ -1,5 +1,5 @@ import { Component, DoCheck, Input, OnChanges } from '@angular/core'; -import { MatIconModule } from '@angular/material/icon'; +import { MatIcon } from '@angular/material/icon'; import { UserProfile } from 'realtime-server/lib/esm/common/models/user'; type AvatarMode = 'image' | 'initials' | 'user_icon'; @@ -8,7 +8,7 @@ type AvatarMode = 'image' | 'initials' | 'user_icon'; selector: 'app-avatar', templateUrl: './avatar.component.html', styleUrls: ['./avatar.component.scss'], - imports: [MatIconModule] + imports: [MatIcon] }) export class AvatarComponent implements DoCheck, OnChanges { @Input() size: number = 32; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/blur-on-click.directive.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/blur-on-click.directive.ts index c22d1281f67..b2ee30c250d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/blur-on-click.directive.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/blur-on-click.directive.ts @@ -1,9 +1,6 @@ import { Directive, ElementRef, HostListener } from '@angular/core'; -@Directive({ - selector: 'button[appBlurOnClick]', - standalone: false -}) +@Directive({ selector: 'button[appBlurOnClick]' }) export class BlurOnClickDirective { constructor(private readonly elementRef: ElementRef) {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/bubble-button/bubble-button.directive.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/bubble-button/bubble-button.directive.ts index 2f819aee844..5713c6f6252 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/bubble-button/bubble-button.directive.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/bubble-button/bubble-button.directive.ts @@ -7,8 +7,7 @@ import { Directive, ElementRef, OnInit, Renderer2 } from '@angular/core'; * with other styles or components that use `::before` or `::after` such as Angular Material components. */ @Directive({ - selector: '[sfBubbleButton]', - standalone: false + selector: '[sfBubbleButton]' }) export class BubbleButtonDirective implements OnInit { cssInnerSpanStyleClass = 'sf-bubble-button-elements'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/bubble-button/bubble-button.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/bubble-button/bubble-button.stories.ts index 7cecb7f6417..1263293304c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/bubble-button/bubble-button.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/bubble-button/bubble-button.stories.ts @@ -1,5 +1,5 @@ import '!style-loader!css-loader!sass-loader!./bubble-button.scss'; -import { MatButtonModule } from '@angular/material/button'; +import { MatButton } from '@angular/material/button'; import { componentWrapperDecorator, Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { BubbleButtonDirective } from './bubble-button.directive'; @@ -8,8 +8,7 @@ export default { decorators: [ moduleMetadata({ - imports: [MatButtonModule], - declarations: [BubbleButtonDirective] + imports: [MatButton, BubbleButtonDirective] }), componentWrapperDecorator( story => ` @@ -26,19 +25,19 @@ export default { type Story = StoryObj; -export const MatRaisedButton: Story = { +export const NgMatRaisedButton: Story = { render: () => ({ template: `` }) }; -export const MatFlatButton: Story = { +export const NgMatFlatButton: Story = { render: () => ({ template: `` }) }; -export const MatStrokedButton: Story = { +export const NgMatStrokedButton: Story = { render: () => ({ template: `` }) }; -export const MatButton: Story = { +export const NgMatButton: Story = { render: () => ({ template: `` }) }; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/donut-chart/donut-chart.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/donut-chart/donut-chart.component.ts index ab778d3b8cd..a078a0ba018 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/donut-chart/donut-chart.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/donut-chart/donut-chart.component.ts @@ -27,8 +27,7 @@ function getPercentages(data: number[]): number[] { @Component({ selector: 'app-donut-chart', templateUrl: './donut-chart.component.html', - styleUrls: ['./donut-chart.component.scss'], - standalone: false + styleUrls: ['./donut-chart.component.scss'] }) export class DonutChartComponent implements AfterViewInit { @Input() animationDuration: number = 1000; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/donut-chart/donut-chart.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/donut-chart/donut-chart.module.ts deleted file mode 100644 index f8fb658c6df..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/donut-chart/donut-chart.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { DonutChartComponent } from './donut-chart.component'; - -@NgModule({ - declarations: [DonutChartComponent], - exports: [DonutChartComponent], - imports: [CommonModule] -}) -export class DonutChartModule {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/edit-name-dialog/edit-name-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/edit-name-dialog/edit-name-dialog.component.spec.ts index ec30e6ad0c9..7f355e65ba8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/edit-name-dialog/edit-name-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/edit-name-dialog/edit-name-dialog.component.spec.ts @@ -1,20 +1,23 @@ -import { Component, NgModule } from '@angular/core'; +import { Component } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatDialogRef } from '@angular/material/dialog'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { DialogService } from 'xforge-common/dialog.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { TestOnlineStatusService } from 'xforge-common/test-online-status.service'; -import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; +import { configureTestingModule, getTestTranslocoModule } from 'xforge-common/test-utils'; import { EditNameDialogComponent, EditNameDialogResult } from './edit-name-dialog.component'; describe('EditNameDialogComponent', () => { configureTestingModule(() => ({ - imports: [TestOnlineStatusModule.forRoot()], - providers: [{ provide: OnlineStatusService, useClass: TestOnlineStatusService }] + imports: [getTestTranslocoModule(), EditNameDialogComponent], + providers: [ + provideTestOnlineStatus(), + { provide: OnlineStatusService, useClass: TestOnlineStatusService }, + provideNoopAnimations() + ] })); it('should display name and cancel button', fakeAsync(() => { @@ -107,7 +110,7 @@ class TestEnvironment { constructor() { TestBed.configureTestingModule({ - imports: [DialogTestModule] + imports: [getTestTranslocoModule(), EditNameDialogComponent, DialogOpenerComponent] }); this.testOnlineStatusService = TestBed.inject(OnlineStatusService) as TestOnlineStatusService; this.fixture = TestBed.createComponent(DialogOpenerComponent); @@ -176,15 +179,8 @@ class TestEnvironment { } } -@NgModule({ - imports: [UICommonModule, TestTranslocoModule, NoopAnimationsModule], - declarations: [EditNameDialogComponent] -}) -class DialogTestModule {} - @Component({ - template: ``, - standalone: false + template: `` }) class DialogOpenerComponent { publicName: string = 'Simon Says'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/edit-name-dialog/edit-name-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/edit-name-dialog/edit-name-dialog.component.ts index 1c45c61b49d..afdb781a653 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/edit-name-dialog/edit-name-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/edit-name-dialog/edit-name-dialog.component.ts @@ -1,10 +1,23 @@ import { Component, DestroyRef, Inject } from '@angular/core'; -import { UntypedFormControl, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; +import { UntypedFormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { + MAT_DIALOG_DATA, + MatDialogConfig, + MatDialogRef, + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatDialogClose +} from '@angular/material/dialog'; import { I18nService } from 'xforge-common/i18n.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { XFValidators } from 'xforge-common/xfvalidators'; +import { TranslocoModule } from '@ngneat/transloco'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; +import { MatButton } from '@angular/material/button'; export interface EditNameDialogResult { displayName: string; } @@ -13,7 +26,20 @@ export interface EditNameDialogResult { selector: 'app-edit-name-dialog', styleUrls: ['./edit-name-dialog.component.scss'], templateUrl: './edit-name-dialog.component.html', - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + FormsModule, + MatFormField, + MatLabel, + MatInput, + ReactiveFormsModule, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class EditNameDialogComponent { static defaultMatDialogConfig: MatDialogConfig = { autoFocus: true }; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.spec.ts index 60e401a8fa0..b0f0ee55f7e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.spec.ts @@ -1,18 +1,16 @@ import { OverlayContainer } from '@angular/cdk/overlay'; -import { NgModule } from '@angular/core'; import { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { anything, mock, when } from 'ts-mockito'; import { I18nService } from '../i18n.service'; -import { ChildViewContainerComponent, configureTestingModule, TestTranslocoModule } from '../test-utils'; -import { UICommonModule } from '../ui-common.module'; +import { ChildViewContainerComponent, configureTestingModule, getTestTranslocoModule } from '../test-utils'; import { ErrorAlertData, ErrorDialogComponent } from './error-dialog.component'; const mockedI18nService = mock(I18nService); describe('ErrorDialogComponent', () => { configureTestingModule(() => ({ - imports: [DialogTestModule], + imports: [getTestTranslocoModule(), ErrorDialogComponent], providers: [{ provide: I18nService, useMock: mockedI18nService }] })); @@ -69,12 +67,6 @@ describe('ErrorDialogComponent', () => { })); }); -@NgModule({ - imports: [UICommonModule, TestTranslocoModule], - declarations: [ErrorDialogComponent] -}) -class DialogTestModule {} - class TestEnvironment { readonly fixture: ComponentFixture; componentInstance: ErrorDialogComponent; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.stories.ts index 1d9ce6ee93e..3de5661c4bc 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.stories.ts @@ -1,10 +1,7 @@ import { Component, Inject, InjectionToken, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialog, MatDialogConfig } from '@angular/material/dialog'; -import { CommonModule } from '@angular/common'; import { Meta, StoryFn } from '@storybook/angular'; -import { I18nStoryModule } from 'xforge-common/i18n-story.module'; -import { UICommonModule } from '../ui-common.module'; import { ErrorAlertData, ErrorDialogComponent } from './error-dialog.component'; interface StoryArgs { @@ -34,8 +31,7 @@ export default { const Template: StoryFn = args => ({ moduleMetadata: { - imports: [UICommonModule, CommonModule, I18nStoryModule], - declarations: [ErrorDialogComponent], + imports: [ErrorDialogComponent], providers: [ { provide: MAT_DIALOG_DATA, useValue: { data: args.dialogData } }, { provide: STORY_ARGS, useValue: args } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.ts index 646a8c6e8c9..6b17bee8f6f 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/error-dialog/error-dialog.component.ts @@ -1,5 +1,16 @@ +import { Dir } from '@angular/cdk/bidi'; +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import { TranslocoModule } from '@ngneat/transloco'; import { browserLinks, getLinkHTML, issuesEmailTemplate, supportedBrowser } from 'xforge-common/utils'; import { environment } from '../../environments/environment'; import { I18nService } from '../i18n.service'; @@ -13,7 +24,16 @@ export interface ErrorAlertData { @Component({ templateUrl: './error-dialog.component.html', styleUrls: ['./error-dialog.component.scss'], - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + Dir, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class ErrorDialogComponent implements OnInit { initComplete = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/exception-handling.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/exception-handling.service.spec.ts index d05c7706b1d..84dbdb24ff1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/exception-handling.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/exception-handling.service.spec.ts @@ -18,7 +18,7 @@ import { FeatureFlagService } from './feature-flags/feature-flag.service'; import { UserDoc } from './models/user-doc'; import { NoticeService } from './notice.service'; import { PwaService } from './pwa.service'; -import { configureTestingModule, TestTranslocoModule } from './test-utils'; +import { configureTestingModule, getTestTranslocoModule } from './test-utils'; import { UserService } from './user.service'; const mockedAuthService = mock(AuthService); @@ -55,7 +55,7 @@ class MockConsole { } describe('ExceptionHandlingService', () => { configureTestingModule(() => ({ - declarations: [HostComponent], + imports: [HostComponent, getTestTranslocoModule()], providers: [ ExceptionHandlingService, { provide: AuthService, useMock: mockedAuthService }, @@ -67,8 +67,7 @@ describe('ExceptionHandlingService', () => { { provide: CONSOLE, useValue: new MockConsole() }, { provide: CookieService, useMock: mockedCookieService }, { provide: FeatureFlagService, useMock: mockedFeatureFlagService } - ], - imports: [TestTranslocoModule] + ] })); it('should not crash on anything', fakeAsync(() => { @@ -233,8 +232,7 @@ interface BreadcrumbTests {
Ripple text - `, - standalone: false + ` }) class HostComponent {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flag.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flag.service.spec.ts index ef50c811bc2..bd9938c1e2b 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flag.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flag.service.spec.ts @@ -1,7 +1,7 @@ import { fakeAsync, flush, TestBed } from '@angular/core/testing'; import { mock, verify, when } from 'ts-mockito'; import { AnonymousService } from 'xforge-common/anonymous.service'; -import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module'; +import { provideTestOnlineStatus } from 'xforge-common/test-online-status-providers'; import { configureTestingModule } from 'xforge-common/test-utils'; import { FeatureFlagService } from './feature-flag.service'; @@ -9,8 +9,7 @@ const mockedAnonymousService = mock(AnonymousService); describe('FeatureFlagService', () => { configureTestingModule(() => ({ - imports: [TestOnlineStatusModule.forRoot()], - providers: [{ provide: AnonymousService, useMock: mockedAnonymousService }] + providers: [provideTestOnlineStatus(), { provide: AnonymousService, useMock: mockedAnonymousService }] })); it('sets and gets the enabled property', fakeAsync(() => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flags-dialog.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flags-dialog.component.spec.ts index 734a2b36d62..07d8577170c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flags-dialog.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flags-dialog.component.spec.ts @@ -6,7 +6,6 @@ import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; import { mock, when } from 'ts-mockito'; import { ChildViewContainerComponent, configureTestingModule } from 'xforge-common/test-utils'; -import { UICommonModule } from 'xforge-common/ui-common.module'; import { NoticeComponent } from '../../app/shared/notice/notice.component'; import { FeatureFlagService } from './feature-flag.service'; import { FeatureFlagsDialogComponent } from './feature-flags-dialog.component'; @@ -15,8 +14,7 @@ const mockedFeatureFlagService = mock(FeatureFlagService); describe('FeatureFlagsComponent', () => { configureTestingModule(() => ({ - declarations: [FeatureFlagsDialogComponent], - imports: [UICommonModule, NoticeComponent], + imports: [FeatureFlagsDialogComponent, NoticeComponent], providers: [{ provide: FeatureFlagService, useMock: mockedFeatureFlagService }] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flags-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flags-dialog.component.ts index aeb482ec37a..11e3f4230a7 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flags-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/feature-flags/feature-flags-dialog.component.ts @@ -1,10 +1,16 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { MatDialogContent, MatDialogTitle } from '@angular/material/dialog'; +import { MatIcon } from '@angular/material/icon'; +import { NoticeComponent } from '../../app/shared/notice/notice.component'; import { FeatureFlagService } from './feature-flag.service'; @Component({ templateUrl: './feature-flags-dialog.component.html', styleUrls: ['./feature-flags-dialog.component.scss'], - standalone: false + imports: [MatDialogTitle, MatIcon, CdkScrollable, MatDialogContent, NoticeComponent, MatCheckbox, FormsModule] }) export class FeatureFlagsDialogComponent { constructor(readonly featureFlags: FeatureFlagService) {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/file.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/file.service.spec.ts index c70c0534bb1..2a2dd507578 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/file.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/file.service.spec.ts @@ -12,9 +12,9 @@ import { FileService, formatFileSource } from './file.service'; import { createDeletionFileData, createStorageFileData, FileOfflineData, FileType } from './models/file-offline-data'; import { ProjectDataDoc } from './models/project-data-doc'; import { OnlineStatusService } from './online-status.service'; -import { TestOnlineStatusModule } from './test-online-status.module'; +import { provideTestOnlineStatus } from './test-online-status-providers'; import { TestOnlineStatusService } from './test-online-status.service'; -import { TestRealtimeModule } from './test-realtime.module'; +import { provideTestRealtime } from './test-realtime-providers'; import { TestRealtimeService } from './test-realtime.service'; import { TypeRegistry } from './type-registry'; import { COMMAND_API_NAMESPACE, PROJECTS_URL } from './url-constants'; @@ -25,11 +25,9 @@ const mockedDialogService = mock(DialogService); describe('FileService', () => { configureTestingModule(() => ({ - imports: [ - TestOnlineStatusModule.forRoot(), - TestRealtimeModule.forRoot(new TypeRegistry([TestDataDoc], [FileType.Audio], [])) - ], providers: [ + provideTestRealtime(new TypeRegistry([TestDataDoc], [FileType.Audio], [])), + provideTestOnlineStatus(), FileService, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: AuthService, useMock: mockedAuthService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/generic-dialog/generic-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/generic-dialog/generic-dialog.component.ts index c723f78d39d..7ba36bc383e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/generic-dialog/generic-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/generic-dialog/generic-dialog.component.ts @@ -1,6 +1,16 @@ import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { + MAT_DIALOG_DATA, + MatDialogRef, + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatDialogClose +} from '@angular/material/dialog'; import { Observable } from 'rxjs'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { MatButton } from '@angular/material/button'; +import { AsyncPipe } from '@angular/common'; export interface GenericDialogOptions { title?: Observable; @@ -23,7 +33,7 @@ export interface GenericDialogRef { @Component({ selector: 'app-generic-dialog', templateUrl: './generic-dialog.component.html', - standalone: false + imports: [MatDialogTitle, CdkScrollable, MatDialogContent, MatDialogActions, MatButton, MatDialogClose, AsyncPipe] }) export class GenericDialogComponent { constructor(@Inject(MAT_DIALOG_DATA) private readonly data: GenericDialogOptions) {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-story.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-story.ts similarity index 71% rename from src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-story.module.ts rename to src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-story.ts index 4cd2bb7218a..b20354d79b5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-story.module.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-story.ts @@ -1,5 +1,11 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; -import { APP_INITIALIZER, NgModule } from '@angular/core'; +import { + EnvironmentProviders, + importProvidersFrom, + inject, + makeEnvironmentProviders, + provideAppInitializer +} from '@angular/core'; import { TRANSLOCO_CONFIG, TRANSLOCO_LOADER, TranslocoConfig, TranslocoModule } from '@ngneat/transloco'; import { DecoratorFunction } from '@storybook/types'; import { I18nService, IGNORE_COOKIE_LOCALE, TranslationLoader } from './i18n.service'; @@ -9,14 +15,6 @@ let selectedLocale: string | undefined; const translocoConfig: TranslocoConfig = { ...I18nService.translocoConfig, prodMode: false }; -function localizationInit(transloco: I18nService): () => void { - return () => { - i18nService = transloco; - - if (selectedLocale != null) i18nService.trySetLocale(selectedLocale); - }; -} - export const I18nStoryDecorator: DecoratorFunction = (Story, context) => { // In some cases the locale has been known to be the empty string, so make sure not to set it to that. const locale = context.parameters.locale || context.globals.locale || I18nService.defaultLocale.canonicalTag; @@ -25,14 +23,18 @@ export const I18nStoryDecorator: DecoratorFunction = (Story, context) => { return Story(); }; -@NgModule({ - exports: [TranslocoModule], - providers: [ - { provide: APP_INITIALIZER, useFactory: localizationInit, deps: [I18nService], multi: true }, +export function provideI18nStory(): EnvironmentProviders { + return makeEnvironmentProviders([ + provideAppInitializer(() => { + i18nService = inject(I18nService); + if (selectedLocale != null) { + i18nService.trySetLocale(selectedLocale); + } + }), + importProvidersFrom(TranslocoModule), { provide: TRANSLOCO_CONFIG, useValue: translocoConfig }, { provide: TRANSLOCO_LOADER, useClass: TranslationLoader }, { provide: IGNORE_COOKIE_LOCALE, useValue: true }, provideHttpClient(withInterceptorsFromDi()) - ] -}) -export class I18nStoryModule {} + ]); +} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-transpilers/em-text.transpiler.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-transpilers/em-text.transpiler.spec.ts index 3759d1db909..522a76cf879 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-transpilers/em-text.transpiler.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/i18n-transpilers/em-text.transpiler.spec.ts @@ -6,7 +6,7 @@ import { TranslationMarkupRendererFactory, TranslocoMarkupModule } from 'ngx-transloco-markup'; -import { TestTranslocoModule } from '../test-utils'; +import { getTestTranslocoModule } from '../test-utils'; import { EmTextTranspiler } from './em-text.transpiler'; function createTestTranspiler(): EmTextTranspiler { @@ -39,9 +39,8 @@ describe('EmTextTranspiler', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [TestTranslocoModule, TranslocoMarkupModule], - providers: [provideTranslationMarkupTranspiler(EmTextTranspiler)], - declarations: [TestComponent] + imports: [getTestTranslocoModule(), TranslocoMarkupModule, TestComponent], + providers: [provideTranslationMarkupTranspiler(EmTextTranspiler)] }); fixture = TestBed.createComponent(TestComponent); @@ -62,7 +61,7 @@ describe('EmTextTranspiler', () => { @Component({ selector: 'app-test', template: ``, - standalone: false + imports: [TranslocoMarkupModule] }) export class TestComponent { translation: string = ''; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/overlay-container.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/overlay-container.spec.ts index cdc94fd0b61..1cc31fd89f4 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/overlay-container.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/overlay-container.spec.ts @@ -3,7 +3,7 @@ import { Component, DebugElement, TemplateRef, ViewChild } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatBottomSheet } from '@angular/material/bottom-sheet'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; import { InAppRootOverlayContainer } from './overlay-container'; describe('OverlayContainer', () => { @@ -15,26 +15,9 @@ describe('OverlayContainer', () => { })); }); -/** - * Host component is generated to contain the element. When tests are rendered the initial component - * is only rendered as a
element whereas this test specifically needs access to the element - */ -@Component({ - selector: 'app-host', - template: '', - standalone: false -}) -class HostComponent { - @ViewChild('root') appRoot?: AppRootComponent; - - open(): void { - this.appRoot?.open(); - } -} @Component({ selector: 'app-root', - template: '
Opened
', - standalone: false + template: '
Opened
' }) class AppRootComponent { @ViewChild('bottomSheet') TemplateBottomSheet?: TemplateRef; @@ -49,15 +32,31 @@ class AppRootComponent { } } +/** + * Host component is generated to contain the element. When tests are rendered the initial component + * is only rendered as a
element whereas this test specifically needs access to the element + */ +@Component({ + selector: 'app-host', + template: '', + imports: [AppRootComponent] +}) +class HostComponent { + @ViewChild('root') appRoot?: AppRootComponent; + + open(): void { + this.appRoot?.open(); + } +} + class TestEnvironment { readonly component: HostComponent; readonly fixture: ComponentFixture; constructor() { TestBed.configureTestingModule({ - declarations: [HostComponent, AppRootComponent], - imports: [NoopAnimationsModule], - providers: [{ provide: OverlayContainer, useClass: InAppRootOverlayContainer }] + imports: [HostComponent, AppRootComponent], + providers: [{ provide: OverlayContainer, useClass: InAppRootOverlayContainer }, provideNoopAnimations()] }); this.fixture = TestBed.createComponent(HostComponent); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/owner/owner.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/owner/owner.component.spec.ts index 255d47da357..6f57b8baf89 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/owner/owner.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/owner/owner.component.spec.ts @@ -8,7 +8,7 @@ import { UserProfile } from 'realtime-server/lib/esm/common/models/user'; import { createTestUserProfile } from 'realtime-server/lib/esm/common/models/user-test-data'; import { anything, instance, mock, when } from 'ts-mockito'; import { UserProfileDoc } from 'xforge-common/models/user-profile-doc'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { TestRealtimeService } from 'xforge-common/test-realtime.service'; import { SF_TYPE_REGISTRY } from '../../app/core/models/sf-type-registry'; import { isSafari } from '../utils'; @@ -81,7 +81,7 @@ describe('OwnerComponent', () => { @Component({ selector: 'app-host', template: '', - standalone: false + imports: [OwnerComponent] }) class HostComponent { @ViewChild(OwnerComponent) checkingOwner!: OwnerComponent; @@ -96,9 +96,9 @@ class TestEnvironment { constructor(template: string) { TestBed.configureTestingModule({ - declarations: [HostComponent], - imports: [TestRealtimeModule.forRoot(SF_TYPE_REGISTRY), OwnerComponent], + imports: [OwnerComponent, HostComponent], providers: [ + provideTestRealtime(SF_TYPE_REGISTRY), { provide: TranslocoService, useFactory: () => instance(this.mockedTranslocoService) }, provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting() diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/owner/owner.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/owner/owner.component.ts index f26cb799349..30f42cdaac7 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/owner/owner.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/owner/owner.component.ts @@ -1,4 +1,4 @@ -import { CommonModule } from '@angular/common'; +import { NgClass } from '@angular/common'; import { Component, Input, OnInit } from '@angular/core'; import { TranslocoService } from '@ngneat/transloco'; import { UserProfile } from 'realtime-server/lib/esm/common/models/user'; @@ -11,7 +11,7 @@ import { UserService } from '../user.service'; selector: 'app-owner', templateUrl: './owner.component.html', styleUrls: ['./owner.component.scss'], - imports: [AvatarComponent, CommonModule] + imports: [AvatarComponent, NgClass] }) export class OwnerComponent implements OnInit { @Input() ownerRef?: string; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/realtime.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/realtime.service.spec.ts index ab5822514d5..cc0eec1587c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/realtime.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/realtime.service.spec.ts @@ -6,12 +6,12 @@ import { SF_TYPE_REGISTRY } from '../app/core/models/sf-type-registry'; import { RealtimeDoc } from './models/realtime-doc'; import { RealtimeQuery } from './models/realtime-query'; import { RealtimeService } from './realtime.service'; -import { TestRealtimeModule } from './test-realtime.module'; +import { provideTestRealtime } from './test-realtime-providers'; import { configureTestingModule } from './test-utils'; describe('RealtimeService', () => { configureTestingModule(() => ({ - imports: [TestRealtimeModule.forRoot(SF_TYPE_REGISTRY)] + providers: [provideTestRealtime(SF_TYPE_REGISTRY)] })); describe('manageQuery', () => { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/router-link.directive.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/router-link.directive.ts index ca421406a38..24e83968692 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/router-link.directive.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/router-link.directive.ts @@ -2,10 +2,7 @@ import { Directive, ElementRef, HostBinding, HostListener, Inject, Input } from import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; import { WINDOW } from './browser-globals'; -@Directive({ - selector: '[appRouterLink]', - standalone: false -}) +@Directive({ selector: '[appRouterLink]' }) export class RouterLinkDirective { @Input() set appRouterLink(value: string | string[]) { this._route = Array.isArray(value) ? value : [value]; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/scroll-into-view.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/scroll-into-view.ts index 1e651259cae..33fc294f6c5 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/scroll-into-view.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/scroll-into-view.ts @@ -1,9 +1,6 @@ import { AfterViewInit, Directive, ElementRef } from '@angular/core'; -@Directive({ - selector: '[appScrollIntoView]', - standalone: false -}) +@Directive({ selector: '[appScrollIntoView]' }) export class ScrollIntoViewDirective implements AfterViewInit { constructor(private readonly elementRef: ElementRef) {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/supported-browsers-dialog/supported-browsers-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/supported-browsers-dialog/supported-browsers-dialog.component.ts index ca6f1090b80..049b960fb58 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/supported-browsers-dialog/supported-browsers-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/supported-browsers-dialog/supported-browsers-dialog.component.ts @@ -1,7 +1,16 @@ import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { + MAT_DIALOG_DATA, + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatDialogClose +} from '@angular/material/dialog'; import { I18nService } from 'xforge-common/i18n.service'; import { browserLinks, isIosDevice } from 'xforge-common/utils'; +import { TranslocoModule } from '@ngneat/transloco'; +import { CdkScrollable } from '@angular/cdk/scrolling'; +import { MatButton } from '@angular/material/button'; export enum BrowserIssue { Upgrade = 'upgrade_chrome_firefox', @@ -11,7 +20,15 @@ export enum BrowserIssue { @Component({ selector: 'app-supported-browsers-dialog', templateUrl: './supported-browsers-dialog.component.html', - standalone: false + imports: [ + TranslocoModule, + MatDialogTitle, + CdkScrollable, + MatDialogContent, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class SupportedBrowsersDialogComponent { constructor( diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-delete-dialog.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-delete-dialog.component.ts index f1908919864..439af1f8ed1 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-delete-dialog.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-delete-dialog.component.ts @@ -1,6 +1,15 @@ +import { CdkScrollable } from '@angular/cdk/scrolling'; import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MatButton } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogTitle +} from '@angular/material/dialog'; import { User } from 'realtime-server/lib/esm/common/models/user'; +import { AvatarComponent } from '../avatar/avatar.component'; export interface SaDeleteUserDialogData { user: User; @@ -9,7 +18,15 @@ export interface SaDeleteUserDialogData { @Component({ templateUrl: './sa-delete-dialog.component.html', styleUrls: ['./sa-delete-dialog.component.scss'], - standalone: false + imports: [ + MatDialogTitle, + CdkScrollable, + MatDialogContent, + AvatarComponent, + MatDialogActions, + MatButton, + MatDialogClose + ] }) export class SaDeleteDialogComponent { constructor(@Inject(MAT_DIALOG_DATA) public data: SaDeleteUserDialogData) {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-projects.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-projects.component.spec.ts index 41251483ebb..4d7a007735e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-projects.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-projects.component.spec.ts @@ -4,8 +4,8 @@ import { DebugElement, getDebugNode } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatCheckbox } from '@angular/material/checkbox'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { provideRouter } from '@angular/router'; import { escapeRegExp, merge } from 'lodash-es'; import { Project } from 'realtime-server/lib/esm/common/models/project'; import { obj } from 'realtime-server/lib/esm/common/utils/obj-path'; @@ -16,15 +16,14 @@ import { combineLatest, from, Observable } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { anything, mock, verify, when } from 'ts-mockito'; import { FileType } from 'xforge-common/models/file-offline-data'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { SFProjectService } from '../../app/core/sf-project.service'; import { ProjectDoc } from '../models/project-doc'; import { NONE_ROLE, ProjectRoleInfo } from '../models/project-role-info'; import { QueryFilter, QueryParameters } from '../query-parameters'; import { TestRealtimeService } from '../test-realtime.service'; -import { configureTestingModule, emptyHammerLoader, TestTranslocoModule } from '../test-utils'; +import { configureTestingModule, emptyHammerLoader, getTestTranslocoModule } from '../test-utils'; import { TypeRegistry } from '../type-registry'; -import { UICommonModule } from '../ui-common.module'; import { UserService } from '../user.service'; import { SaProjectsComponent } from './sa-projects.component'; @@ -33,20 +32,16 @@ const mockedUserService = mock(UserService); describe('SaProjectsComponent', () => { configureTestingModule(() => ({ - imports: [ - NoopAnimationsModule, - RouterModule.forRoot([]), - UICommonModule, - TestTranslocoModule, - TestRealtimeModule.forRoot(new TypeRegistry([TestProjectDoc], [FileType.Audio], [])) - ], - declarations: [SaProjectsComponent], + imports: [SaProjectsComponent, getTestTranslocoModule()], providers: [ + provideRouter([]), + provideTestRealtime(new TypeRegistry([TestProjectDoc], [FileType.Audio], [])), { provide: SFProjectService, useMock: mockedProjectService }, { provide: UserService, useMock: mockedUserService }, emptyHammerLoader, provideHttpClient(withInterceptorsFromDi()), - provideHttpClientTesting() + provideHttpClientTesting(), + provideNoopAnimations() ] })); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-projects.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-projects.component.ts index 1bde8c5ca81..88cd46d036d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-projects.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-projects.component.ts @@ -1,4 +1,12 @@ import { Component, DestroyRef, HostBinding, OnInit } from '@angular/core'; +import { MatOption } from '@angular/material/autocomplete'; +import { MatCheckbox } from '@angular/material/checkbox'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatInput } from '@angular/material/input'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSelect } from '@angular/material/select'; +import { MatCell, MatCellDef, MatColumnDef, MatRow, MatRowDef, MatTable } from '@angular/material/table'; +import { TranslocoModule } from '@ngneat/transloco'; import { Project } from 'realtime-server/lib/esm/common/models/project'; import { obj } from 'realtime-server/lib/esm/common/utils/obj-path'; import { SFProject } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; @@ -11,7 +19,9 @@ import { DataLoadingComponent } from '../data-loading-component'; import { NONE_ROLE, ProjectRoleInfo } from '../models/project-role-info'; import { NoticeService } from '../notice.service'; import { QueryParameters } from '../query-parameters'; +import { RouterLinkDirective } from '../router-link.directive'; import { UserService } from '../user.service'; + class Row { isUpdatingRole: boolean = false; @@ -59,7 +69,23 @@ class Row { selector: 'app-sa-projects', templateUrl: './sa-projects.component.html', styleUrls: ['./sa-projects.component.scss'], - standalone: false + imports: [ + MatFormField, + MatLabel, + MatInput, + MatTable, + MatColumnDef, + MatCellDef, + MatCell, + RouterLinkDirective, + MatSelect, + MatOption, + MatCheckbox, + MatRowDef, + MatRow, + MatPaginator, + TranslocoModule + ] }) export class SaProjectsComponent extends DataLoadingComponent implements OnInit { @HostBinding('class') classes = 'flex-column'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-users.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-users.component.spec.ts index bcbf7ea18b0..0ba947852b8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-users.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-users.component.spec.ts @@ -1,11 +1,11 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { DebugElement, getDebugNode, NgModule } from '@angular/core'; +import { DebugElement, getDebugNode } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterModule } from '@angular/router'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { provideRouter } from '@angular/router'; import { escapeRegExp, merge } from 'lodash-es'; import { Project } from 'realtime-server/lib/esm/common/models/project'; import { User } from 'realtime-server/lib/esm/common/models/user'; @@ -17,16 +17,15 @@ import { switchMap } from 'rxjs/operators'; import { anything, instance, mock, verify, when } from 'ts-mockito'; import { AvatarComponent } from 'xforge-common/avatar/avatar.component'; import { FileType } from 'xforge-common/models/file-offline-data'; -import { TestRealtimeModule } from 'xforge-common/test-realtime.module'; +import { provideTestRealtime } from 'xforge-common/test-realtime-providers'; import { environment } from '../../environments/environment'; import { ProjectDoc } from '../models/project-doc'; import { UserDoc } from '../models/user-doc'; import { ProjectService } from '../project.service'; import { QueryFilter, QueryParameters } from '../query-parameters'; import { TestRealtimeService } from '../test-realtime.service'; -import { configureTestingModule, emptyHammerLoader, TestTranslocoModule } from '../test-utils'; +import { configureTestingModule, emptyHammerLoader, getTestTranslocoModule } from '../test-utils'; import { TypeRegistry } from '../type-registry'; -import { UICommonModule } from '../ui-common.module'; import { UserService } from '../user.service'; import { SaDeleteDialogComponent } from './sa-delete-dialog.component'; import { SaUsersComponent } from './sa-users.component'; @@ -37,22 +36,17 @@ const mockedProjectService: ProjectService = mock(ProjectService); describe('SaUsersComponent', () => { configureTestingModule(() => ({ - imports: [ - RouterModule.forRoot([]), - UICommonModule, - DialogTestModule, - TestTranslocoModule, - TestRealtimeModule.forRoot(new TypeRegistry([UserDoc, TestProjectDoc], [FileType.Audio], [])), - AvatarComponent - ], - declarations: [SaUsersComponent], + imports: [SaUsersComponent, getTestTranslocoModule(), AvatarComponent], providers: [ + provideRouter([]), + provideTestRealtime(new TypeRegistry([UserDoc, TestProjectDoc], [FileType.Audio], [])), { provide: MatDialog, useMock: mockedMatDialog }, { provide: UserService, useMock: mockedUserService }, { provide: ProjectService, useMock: mockedProjectService }, emptyHammerLoader, provideHttpClient(withInterceptorsFromDi()), - provideHttpClientTesting() + provideHttpClientTesting(), + provideNoopAnimations() ] })); @@ -161,11 +155,6 @@ class TestProjectDoc extends ProjectDoc { readonly taskNames: string[] = []; } -@NgModule({ - imports: [NoopAnimationsModule] -}) -class DialogTestModule {} - class TestEnvironment { readonly component: SaUsersComponent; readonly fixture: ComponentFixture; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-users.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-users.component.ts index bfc8eacad7b..8b890dc8980 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-users.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/sa-users.component.ts @@ -1,5 +1,11 @@ import { Component, DestroyRef, HostBinding, OnInit } from '@angular/core'; +import { MatIconButton } from '@angular/material/button'; import { MatDialogConfig } from '@angular/material/dialog'; +import { MatFormField, MatLabel } from '@angular/material/form-field'; +import { MatIcon } from '@angular/material/icon'; +import { MatInput } from '@angular/material/input'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatCell, MatCellDef, MatColumnDef, MatRow, MatRowDef, MatTable } from '@angular/material/table'; import { Project } from 'realtime-server/lib/esm/common/models/project'; import { User } from 'realtime-server/lib/esm/common/models/user'; import { obj } from 'realtime-server/lib/esm/common/utils/obj-path'; @@ -8,14 +14,17 @@ import { RealtimeQuery } from 'xforge-common/models/realtime-query'; import { UserDoc } from 'xforge-common/models/user-doc'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; import { environment } from '../../environments/environment'; +import { AvatarComponent } from '../avatar/avatar.component'; import { DataLoadingComponent } from '../data-loading-component'; import { DialogService } from '../dialog.service'; import { ProjectDoc } from '../models/project-doc'; import { NoticeService } from '../notice.service'; import { ProjectService } from '../project.service'; import { QueryParameters } from '../query-parameters'; +import { RouterLinkDirective } from '../router-link.directive'; import { UserService } from '../user.service'; import { SaDeleteDialogComponent, SaDeleteUserDialogData } from './sa-delete-dialog.component'; + interface ProjectInfo { id: string; name: string; @@ -31,7 +40,22 @@ interface Row { selector: 'app-sa-users', templateUrl: './sa-users.component.html', styleUrls: ['./sa-users.component.scss'], - standalone: false + imports: [ + MatFormField, + MatLabel, + MatInput, + MatTable, + MatColumnDef, + MatCellDef, + MatCell, + AvatarComponent, + RouterLinkDirective, + MatIconButton, + MatIcon, + MatRowDef, + MatRow, + MatPaginator + ] }) export class SaUsersComponent extends DataLoadingComponent implements OnInit { @HostBinding('class') classes = 'flex-column'; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/system-administration.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/system-administration.component.ts index 2f655bb0d66..ef0fb5ba204 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/system-administration.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/system-administration/system-administration.component.ts @@ -1,9 +1,13 @@ import { Component } from '@angular/core'; +import { MatTab, MatTabGroup } from '@angular/material/tabs'; +import { MobileNotSupportedComponent } from '../../app/shared/mobile-not-supported/mobile-not-supported.component'; +import { SaProjectsComponent } from './sa-projects.component'; +import { SaUsersComponent } from './sa-users.component'; @Component({ selector: 'app-system-administration', templateUrl: './system-administration.component.html', styleUrls: ['./system-administration.component.scss'], - standalone: false + imports: [MobileNotSupportedComponent, MatTabGroup, MatTab, SaUsersComponent, SaProjectsComponent] }) export class SystemAdministrationComponent {} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-online-status-providers.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-online-status-providers.ts new file mode 100644 index 00000000000..081906add65 --- /dev/null +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-online-status-providers.ts @@ -0,0 +1,17 @@ +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { mock, when } from 'ts-mockito'; + +/** + * Provides a mocked Navigator (defaults to online). + */ +export function provideTestOnlineStatus(): EnvironmentProviders { + const mockedNavigator = mock(Navigator); + when(mockedNavigator.onLine).thenReturn(true); + return makeEnvironmentProviders([ + provideHttpClient(withInterceptorsFromDi()), + provideHttpClientTesting(), + { provide: Navigator, useValue: mockedNavigator } + ]); +} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-online-status.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-online-status.module.ts deleted file mode 100644 index ef93755543d..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-online-status.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; -import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { ModuleWithProviders, NgModule } from '@angular/core'; -import { mock, when } from 'ts-mockito'; - -@NgModule({ providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] }) -export class TestOnlineStatusModule { - static forRoot(): ModuleWithProviders { - const mockedNavigator = mock(Navigator); - when(mockedNavigator.onLine).thenReturn(true); - return { - ngModule: TestOnlineStatusModule, - providers: [{ provide: Navigator, useValue: mockedNavigator }] - }; - } -} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-realtime-providers.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-realtime-providers.ts new file mode 100644 index 00000000000..8e0a6895d01 --- /dev/null +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-realtime-providers.ts @@ -0,0 +1,23 @@ +import { Provider } from '@angular/core'; +import { FileService } from './file.service'; +import { MemoryOfflineStore } from './memory-offline-store'; +import { MemoryRealtimeRemoteStore } from './memory-realtime-remote-store'; +import { OfflineStore } from './offline-store'; +import { RealtimeRemoteStore } from './realtime-remote-store'; +import { RealtimeService } from './realtime.service'; +import { TestRealtimeService } from './test-realtime.service'; +import { TypeRegistry } from './type-registry'; + +/** + * Provides test doubles for realtime services using in-memory stores. + */ +export function provideTestRealtime(typeRegistry: TypeRegistry): Provider[] { + return [ + { provide: TypeRegistry, useValue: typeRegistry }, + { provide: RealtimeRemoteStore, useClass: MemoryRealtimeRemoteStore }, + { provide: OfflineStore, useClass: MemoryOfflineStore }, + { provide: TestRealtimeService, useClass: TestRealtimeService }, + { provide: RealtimeService, useExisting: TestRealtimeService }, + { provide: FileService, useValue: undefined } + ]; +} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-realtime.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-realtime.module.ts deleted file mode 100644 index 966f4c268ef..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-realtime.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ModuleWithProviders, NgModule } from '@angular/core'; -import { FileService } from './file.service'; -import { MemoryOfflineStore } from './memory-offline-store'; -import { MemoryRealtimeRemoteStore } from './memory-realtime-remote-store'; -import { OfflineStore } from './offline-store'; -import { RealtimeRemoteStore } from './realtime-remote-store'; -import { RealtimeService } from './realtime.service'; -import { TestRealtimeService } from './test-realtime.service'; -import { TypeRegistry } from './type-registry'; - -@NgModule() -export class TestRealtimeModule { - static forRoot(typeRegistry: TypeRegistry): ModuleWithProviders { - return { - ngModule: TestRealtimeModule, - providers: [ - { provide: TypeRegistry, useValue: typeRegistry }, - { provide: RealtimeRemoteStore, useClass: MemoryRealtimeRemoteStore }, - { provide: OfflineStore, useClass: MemoryOfflineStore }, - { provide: TestRealtimeService, useClass: TestRealtimeService }, - { provide: RealtimeService, useExisting: TestRealtimeService }, - { provide: FileService, useValue: undefined } - ] - }; - } -} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-utils.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-utils.ts index 6f91dbd77d0..6a7caae3db7 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-utils.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/test-utils.ts @@ -1,4 +1,12 @@ -import { Component, Directive, Input, NgModule, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core'; +import { + Component, + Directive, + Input, + ModuleWithProviders, + TemplateRef, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { TestBed, TestModuleMetadata } from '@angular/core/testing'; import { HAMMER_LOADER } from '@angular/platform-browser'; import { TranslocoTestingModule } from '@ngneat/transloco'; @@ -52,15 +60,23 @@ export const configureTestingModule = (createModuleDef: () => TestModuleMetadata }); }; -export const TestTranslocoModule = TranslocoTestingModule.forRoot({ - langs: { en }, - translocoConfig: { - availableLangs: ['en'], - reRenderOnLangChange: true, - fallbackLang: 'en', - defaultLang: 'en' - } -}); +/** + * Gets a Transloco testing module with 'en' translations loaded. + * @param loadLangs Whether to preload the languages. Set to false if tests want to use the untranslated key. + * Default is true. + */ +export function getTestTranslocoModule(loadLangs = true): ModuleWithProviders { + return TranslocoTestingModule.forRoot({ + langs: { en }, + translocoConfig: { + availableLangs: ['en'], + reRenderOnLangChange: true, + fallbackLang: 'en', + defaultLang: 'en' + }, + preloadLangs: loadLangs + }); +} // used to prevent Angular from complaining that HammerJS isn't available export const emptyHammerLoader = { @@ -387,8 +403,7 @@ export function getShortAudioBlob(): Blob { @Directive({ // es lint complains that a directive should be used as an attribute // eslint-disable-next-line @angular-eslint/directive-selector - selector: 'viewContainerDirective', - standalone: false + selector: 'viewContainerDirective' }) export class ViewContainerDirective { constructor(public viewContainerRef: ViewContainerRef) {} @@ -397,7 +412,7 @@ export class ViewContainerDirective { @Component({ selector: 'app-view-container', template: '', - standalone: false + imports: [ViewContainerDirective] }) export class ChildViewContainerComponent { @ViewChild(ViewContainerDirective, { static: true }) viewContainer!: ViewContainerDirective; @@ -407,12 +422,6 @@ export class ChildViewContainerComponent { } } -@NgModule({ - declarations: [ChildViewContainerComponent, ViewContainerDirective], - exports: [ViewContainerDirective] -}) -export class ChildViewContainerModule {} - export function arrayOfIntsFromZero(size: number): number[] { return Array.from({ length: size }, (_, i) => i); } @@ -426,8 +435,7 @@ export function arrayOfIntsFromOne(size: number): number[] { */ @Directive({ // eslint-disable-next-line @angular-eslint/directive-selector - selector: '[transloco]', - standalone: false + selector: '[transloco]' }) export class MockTranslocoDirective { @Input() translocoRead?: string; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/theme.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/theme.service.spec.ts index 8b28dee5ef7..804ca217a06 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/theme.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/theme.service.spec.ts @@ -1,8 +1,8 @@ import { TestBed } from '@angular/core/testing'; import { anyString, mock, when } from 'ts-mockito'; +import { DOCUMENT } from './browser-globals'; import { LocalSettingsService } from './local-settings.service'; import { configureTestingModule } from './test-utils'; -import { DOCUMENT } from './browser-globals'; import { Theme, ThemeService } from './theme.service'; const mockedLocalSettingsService = mock(LocalSettingsService); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/ui-common-providers.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/ui-common-providers.ts new file mode 100644 index 00000000000..3f65851ebcf --- /dev/null +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/ui-common-providers.ts @@ -0,0 +1,48 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; +import { MatPaginatorIntl } from '@angular/material/paginator'; +import { MAT_SELECT_CONFIG } from '@angular/material/select'; +import { MAT_TOOLTIP_DEFAULT_OPTIONS } from '@angular/material/tooltip'; +import { TranslocoService } from '@ngneat/transloco'; +import { NgCircleProgressModule } from 'ng-circle-progress'; +import { Paginator } from './paginator/paginator.component'; + +/** + * Provides Angular Material configuration and other UI-related providers for the application. + */ +export function provideUICommon(): EnvironmentProviders { + return makeEnvironmentProviders([ + { + provide: MatPaginatorIntl, + useClass: Paginator, + deps: [TranslocoService] + }, + { + provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, + useValue: { appearance: 'outline', hideRequiredMarker: true } + }, + { + provide: MAT_TOOLTIP_DEFAULT_OPTIONS, + useValue: { disableTooltipInteractivity: true } + }, + { + provide: MAT_SELECT_CONFIG, + useValue: { panelWidth: null } + }, + ...(NgCircleProgressModule.forRoot({ + // Defaults + radius: 100, + outerStrokeWidth: 8, + innerStrokeWidth: 4, + outerStrokeColor: '#298ed1', + innerStrokeColor: '#95c4e6', + animationDuration: 1000, + startFromZero: false, + titleFontSize: '48', + unitsFontSize: '20', + showSubtitle: false, + responsive: true, + renderOnClick: false + }).providers ?? []) + ]); +} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/ui-common.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/ui-common.module.ts deleted file mode 100644 index 71bd1602ca7..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/ui-common.module.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { BidiModule } from '@angular/cdk/bidi'; -import { ModuleWithProviders, NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocompleteModule } from '@angular/material/autocomplete'; -import { MatBadgeModule } from '@angular/material/badge'; -import { MatBottomSheetModule } from '@angular/material/bottom-sheet'; -import { MatButtonModule } from '@angular/material/button'; -import { MatButtonToggleModule } from '@angular/material/button-toggle'; -import { MatCardModule } from '@angular/material/card'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatChipsModule } from '@angular/material/chips'; -import { MatOptionModule } from '@angular/material/core'; -import { MatDialogModule } from '@angular/material/dialog'; -import { MatDividerModule } from '@angular/material/divider'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { MAT_FORM_FIELD_DEFAULT_OPTIONS, MatFormFieldModule } from '@angular/material/form-field'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatListModule } from '@angular/material/list'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatPaginatorIntl, MatPaginatorModule } from '@angular/material/paginator'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatRadioModule } from '@angular/material/radio'; -import { MAT_SELECT_CONFIG, MatSelectModule } from '@angular/material/select'; -import { MatSidenavModule } from '@angular/material/sidenav'; -import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { MatSliderModule } from '@angular/material/slider'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; -import { MatSortModule } from '@angular/material/sort'; -import { MatStepperModule } from '@angular/material/stepper'; -import { MatTableModule } from '@angular/material/table'; -import { MatTabsModule } from '@angular/material/tabs'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { MAT_TOOLTIP_DEFAULT_OPTIONS, MatTooltipModule } from '@angular/material/tooltip'; -import { TranslocoService } from '@ngneat/transloco'; -import { NgCircleProgressModule } from 'ng-circle-progress'; -import { AutofocusDirective } from './autofocus.directive'; -import { BlurOnClickDirective } from './blur-on-click.directive'; -import { DonutChartModule } from './donut-chart/donut-chart.module'; -import { L10nNumberPipe } from './l10n-number.pipe'; -import { Paginator } from './paginator/paginator.component'; -import { RouterLinkDirective } from './router-link.directive'; -import { ScrollIntoViewDirective } from './scroll-into-view'; - -const modules = [ - DonutChartModule, - FormsModule, - BidiModule, - MatAutocompleteModule, - MatBadgeModule, - MatBottomSheetModule, - MatButtonModule, - MatButtonToggleModule, - MatCardModule, - MatCheckboxModule, - MatChipsModule, - MatDialogModule, - MatDividerModule, - MatFormFieldModule, - MatIconModule, - MatInputModule, - MatListModule, - MatMenuModule, - MatOptionModule, - MatPaginatorModule, - MatProgressBarModule, - MatProgressSpinnerModule, - MatRadioModule, - MatSelectModule, - MatSidenavModule, - MatSliderModule, - MatSlideToggleModule, - MatSnackBarModule, - MatSortModule, - MatStepperModule, - MatTableModule, - MatTabsModule, - MatToolbarModule, - MatTooltipModule, - MatExpansionModule, - ReactiveFormsModule, - NgCircleProgressModule -]; - -@NgModule({ - declarations: [BlurOnClickDirective, AutofocusDirective, ScrollIntoViewDirective, RouterLinkDirective], - imports: [...modules, L10nNumberPipe], - exports: [ - ...modules, - BlurOnClickDirective, - AutofocusDirective, - ScrollIntoViewDirective, - RouterLinkDirective, - L10nNumberPipe - ], - providers: [ - { - provide: MatPaginatorIntl, - useClass: Paginator, - deps: [TranslocoService] - }, - { - provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, - useValue: { appearance: 'outline', hideRequiredMarker: true } - }, - { - provide: MAT_TOOLTIP_DEFAULT_OPTIONS, - useValue: { disableTooltipInteractivity: true } - }, - { - provide: MAT_SELECT_CONFIG, - useValue: { panelWidth: null } - } - ] -}) -export class UICommonModule { - static forRoot(): ModuleWithProviders { - return { - ngModule: UICommonModule, - providers: [ - ...(NgCircleProgressModule.forRoot({ - // Defaults - radius: 100, - outerStrokeWidth: 8, - innerStrokeWidth: 4, - outerStrokeColor: '#298ed1', - innerStrokeColor: '#95c4e6', - animationDuration: 1000, - startFromZero: false, - titleFontSize: '48', - unitsFontSize: '20', - showSubtitle: false, - responsive: true, - renderOnClick: false - }).providers ?? []) - ] - }; - } -} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/user-projects.service.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/user-projects.service.ts index c25d824a060..3f2c5ec6e99 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/user-projects.service.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/user-projects.service.ts @@ -8,6 +8,7 @@ import { environment } from '../environments/environment'; import { AuthService, LoginResult } from './auth.service'; import { UserDoc } from './models/user-doc'; import { UserService } from './user.service'; + /** Service that maintains an up-to-date set of SF project docs that the current user has access to. */ @Injectable({ providedIn: 'root' diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/user.service.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/user.service.spec.ts index 13cbc7f42ee..94994046d2e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/user.service.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/user.service.spec.ts @@ -11,9 +11,9 @@ import { DialogService } from './dialog.service'; import { LocalSettingsService } from './local-settings.service'; import { UserDoc } from './models/user-doc'; import { NoticeService } from './notice.service'; -import { TestRealtimeModule } from './test-realtime.module'; +import { provideTestRealtime } from './test-realtime-providers'; import { TestRealtimeService } from './test-realtime.service'; -import { configureTestingModule, TestTranslocoModule } from './test-utils'; +import { configureTestingModule, getTestTranslocoModule } from './test-utils'; import { TypeRegistry } from './type-registry'; import { CURRENT_PROJECT_ID_SETTING, UserService } from './user.service'; @@ -25,8 +25,9 @@ const mockedNoticeService = mock(NoticeService); describe('UserService', () => { configureTestingModule(() => ({ - imports: [TestTranslocoModule, TestRealtimeModule.forRoot(new TypeRegistry([UserDoc], [], []))], + imports: [getTestTranslocoModule()], providers: [ + provideTestRealtime(new TypeRegistry([UserDoc], [], [])), { provide: AuthService, useMock: mockedAuthService }, { provide: LocalSettingsService, useMock: mockedLocalSettingsService }, { provide: CommandService, useMock: mockedCommandService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/util/rxjs-util.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/util/rxjs-util.spec.ts index fe756ec3704..5ada7948d1d 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/util/rxjs-util.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/util/rxjs-util.spec.ts @@ -64,9 +64,7 @@ describe('quietTakeUntilDestroyed', () => { }); }); -@Component({ - standalone: false -}) +@Component({}) class QuietTakeUntilDestroyedTestComponent implements OnDestroy { mainSubjectCompleted = false; subjectCreatedAfterDestroyCompleted = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/utils.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/utils.spec.ts index a559ee33941..c2c8f217244 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/utils.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/utils.spec.ts @@ -63,9 +63,7 @@ describe('quietTakeUntilDestroyed', () => { }); }); -@Component({ - standalone: false -}) +@Component({}) class QuietTakeUntilDestroyedTestComponent implements OnDestroy { mainSubjectCompleted = false; subjectCreatedAfterDestroyCompleted = false; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.component.spec.ts index acea967bdfa..4ab6702a11e 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.component.spec.ts @@ -7,8 +7,7 @@ import { WriteStatusComponent } from './write-status.component'; describe('WriteStatusComponent', () => { configureTestingModule(() => ({ - declarations: [TestHostComponent], - imports: [WriteStatusComponent] + imports: [WriteStatusComponent, TestHostComponent] })); it('should display done, spinner and error icons', () => { @@ -64,7 +63,7 @@ class TestEnvironment { @Component({ template: ``, - standalone: false + imports: [WriteStatusComponent] }) class TestHostComponent { testForm: FormGroup = new FormGroup({ diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.component.ts index 57220471e14..4ad2d749556 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { MatIconModule } from '@angular/material/icon'; +import { MatIcon } from '@angular/material/icon'; import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { ElementState } from '../models/element-state'; @@ -8,8 +8,7 @@ import { ElementState } from '../models/element-state'; selector: 'app-write-status', templateUrl: './write-status.component.html', styleUrls: ['./write-status.component.scss'], - imports: [MatIconModule, MatProgressSpinner], - standalone: true + imports: [MatIcon, MatProgressSpinner] }) export class WriteStatusComponent { @Input() state?: ElementState; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.stories.ts index 00ce7b72227..26c2c34e80c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/write-status/write-status.stories.ts @@ -9,7 +9,7 @@ import { WriteStatusComponent } from './write-status.component'; template: `
`, - standalone: false + imports: [WriteStatusComponent] }) class WriteStatusTestComponent { @Input() state?: ElementState; @@ -21,8 +21,7 @@ const meta: Meta = { component: WriteStatusTestComponent, decorators: [ moduleMetadata({ - declarations: [WriteStatusTestComponent], - imports: [WriteStatusComponent] + imports: [WriteStatusTestComponent] }) ] }; diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/xforge-common-providers.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/xforge-common-providers.ts new file mode 100644 index 00000000000..a275c61ad46 --- /dev/null +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/xforge-common-providers.ts @@ -0,0 +1,24 @@ +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { TRANSLOCO_CONFIG, TRANSLOCO_INTERCEPTOR, TRANSLOCO_LOADER } from '@ngneat/transloco'; +import { LtrMarkerInterceptor } from '../app/shared/ltr-marker.interceptor'; +import { AuthHttpInterceptor } from './auth-http-interceptor'; +import { I18nService, TranslationLoader } from './i18n.service'; +import { IndexeddbOfflineStore } from './indexeddb-offline-store'; +import { OfflineStore } from './offline-store'; +import { RealtimeRemoteStore } from './realtime-remote-store'; +import { SharedbRealtimeRemoteStore } from './sharedb-realtime-remote-store'; + +/** + * Provides core xForge services including HTTP interceptors, realtime/offline stores, and i18n configuration. + */ +export function provideXForgeCommon(): EnvironmentProviders { + return makeEnvironmentProviders([ + { provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true }, + { provide: RealtimeRemoteStore, useExisting: SharedbRealtimeRemoteStore }, + { provide: OfflineStore, useExisting: IndexeddbOfflineStore }, + { provide: TRANSLOCO_CONFIG, useValue: I18nService.translocoConfig }, + { provide: TRANSLOCO_LOADER, useClass: TranslationLoader }, + { provide: TRANSLOCO_INTERCEPTOR, useClass: LtrMarkerInterceptor } + ]); +} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/xforge-common.module.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/xforge-common.module.ts deleted file mode 100644 index c6cea7d6668..00000000000 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/xforge-common.module.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { HTTP_INTERCEPTORS } from '@angular/common/http'; -import { NgModule } from '@angular/core'; -import { MatDialogModule } from '@angular/material/dialog'; -import { RouterModule } from '@angular/router'; -import { TRANSLOCO_CONFIG, TRANSLOCO_INTERCEPTOR, TRANSLOCO_LOADER, TranslocoModule } from '@ngneat/transloco'; -import { ngfModule } from 'angular-file'; -import { ProjectSelectComponent } from '../app/project-select/project-select.component'; -import { LtrMarkerInterceptor } from '../app/shared/ltr-marker.interceptor'; -import { MobileNotSupportedComponent } from '../app/shared/mobile-not-supported/mobile-not-supported.component'; -import { PageNotFoundComponent } from '../app/shared/page-not-found/page-not-found.component'; -import { SyncProgressComponent } from '../app/sync/sync-progress/sync-progress.component'; -import { AuthHttpInterceptor } from './auth-http-interceptor'; -import { AvatarComponent } from './avatar/avatar.component'; -import { GenericDialogComponent } from './generic-dialog/generic-dialog.component'; -import { I18nService, TranslationLoader } from './i18n.service'; -import { IndexeddbOfflineStore } from './indexeddb-offline-store'; -import { OfflineStore } from './offline-store'; -import { OwnerComponent } from './owner/owner.component'; -import { RealtimeRemoteStore } from './realtime-remote-store'; -import { SharedbRealtimeRemoteStore } from './sharedb-realtime-remote-store'; -import { SaDeleteDialogComponent } from './system-administration/sa-delete-dialog.component'; -import { SaProjectsComponent } from './system-administration/sa-projects.component'; -import { SaUsersComponent } from './system-administration/sa-users.component'; -import { SystemAdministrationComponent } from './system-administration/system-administration.component'; -import { UICommonModule } from './ui-common.module'; - -const componentExports = [ - GenericDialogComponent, - SaProjectsComponent, - SaDeleteDialogComponent, - SaUsersComponent, - SystemAdministrationComponent, - PageNotFoundComponent, - ProjectSelectComponent, - SyncProgressComponent -]; - -@NgModule({ - imports: [ - CommonModule, - ngfModule, - RouterModule, - UICommonModule, - TranslocoModule, - MatDialogModule, - AvatarComponent, - OwnerComponent, - MobileNotSupportedComponent - ], - declarations: componentExports, - exports: componentExports, - providers: [ - { provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true }, - { provide: RealtimeRemoteStore, useExisting: SharedbRealtimeRemoteStore }, - { provide: OfflineStore, useExisting: IndexeddbOfflineStore }, - { provide: TRANSLOCO_CONFIG, useValue: I18nService.translocoConfig }, - { provide: TRANSLOCO_LOADER, useClass: TranslationLoader }, - { provide: TRANSLOCO_INTERCEPTOR, useClass: LtrMarkerInterceptor } - ] -}) -export class XForgeCommonModule {}