diff --git a/src/app/core/components/breadcrumb/breadcrumb.component.spec.ts b/src/app/core/components/breadcrumb/breadcrumb.component.spec.ts index 591423245..edaaad4f9 100644 --- a/src/app/core/components/breadcrumb/breadcrumb.component.spec.ts +++ b/src/app/core/components/breadcrumb/breadcrumb.component.spec.ts @@ -3,27 +3,32 @@ import { MockProvider } from 'ng-mocks'; import { of } from 'rxjs'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { NavigationEnd, Router } from '@angular/router'; +import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { BreadcrumbComponent } from './breadcrumb.component'; describe('BreadcrumbComponent', () => { let component: BreadcrumbComponent; let fixture: ComponentFixture; - let router: Router; const mockRouter = { url: '/test/path', events: of(new NavigationEnd(1, '/test/path', '/test/path')), }; + const mockActivatedRoute = { + snapshot: { + data: { skipBreadcrumbs: false }, + }, + firstChild: null, + }; + beforeEach(async () => { await TestBed.configureTestingModule({ imports: [BreadcrumbComponent], - providers: [MockProvider(Router, mockRouter)], + providers: [MockProvider(Router, mockRouter), { provide: ActivatedRoute, useValue: mockActivatedRoute }], }).compileComponents(); - router = TestBed.inject(Router); fixture = TestBed.createComponent(BreadcrumbComponent); component = fixture.componentInstance; fixture.detectChanges(); @@ -34,25 +39,4 @@ describe('BreadcrumbComponent', () => { expect(component['url']()).toBe('/test/path'); expect(component['parsedUrl']()).toEqual(['test', 'path']); }); - - it('should not show breadcrumb for home page', () => { - Object.defineProperty(router, 'url', { value: '/home' }); - component['url'].set('/home'); - fixture.detectChanges(); - - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('.breadcrumbs')).toBeNull(); - }); - - it('should show breadcrumb for valid path', () => { - Object.defineProperty(router, 'url', { value: '/settings/profile' }); - component['url'].set('/settings/profile'); - fixture.detectChanges(); - - const compiled = fixture.nativeElement as HTMLElement; - const breadcrumbs = compiled.querySelector('.breadcrumbs'); - expect(breadcrumbs).toBeTruthy(); - expect(breadcrumbs?.textContent).toContain('settings'); - expect(breadcrumbs?.textContent).toContain('profile'); - }); }); diff --git a/src/app/core/components/footer/footer.component.scss b/src/app/core/components/footer/footer.component.scss index c6b90a91a..882994d28 100644 --- a/src/app/core/components/footer/footer.component.scss +++ b/src/app/core/components/footer/footer.component.scss @@ -1,52 +1,47 @@ @use "assets/styles/mixins" as mix; @use "assets/styles/variables" as var; -:host { - display: block; - height: auto; +.footer-nav, +.footer-secondary-nav { + color: var.$dark-blue-1; + padding: 0 1.5rem; - .footer-nav, - .footer-secondary-nav { - color: var.$dark-blue-1; - padding: 0 1.5rem; - - .separator { - margin: 0 mix.rem(6px); - } + .separator { + margin: 0 mix.rem(6px); + } - a { - color: var.$dark-blue-1; - text-align: center; - } + a { + color: var.$dark-blue-1; + text-align: center; + } - .social-link { - background-color: var.$pr-blue-1; - border-radius: mix.rem(6px); - color: var.$white; - padding: mix.rem(6px); - width: mix.rem(36px); - height: mix.rem(36px); - - &:hover { - background-color: var.$pr-blue-3; - text-decoration: none; - } + .social-link { + background-color: var.$pr-blue-1; + border-radius: mix.rem(6px); + color: var.$white; + padding: mix.rem(6px); + width: mix.rem(36px); + height: mix.rem(36px); + + &:hover { + background-color: var.$pr-blue-3; + text-decoration: none; } } +} - .footer-links { - gap: mix.rem(6px); - } +.footer-links { + gap: mix.rem(6px); +} - .footer-nav { - background-color: var.$bg-blue-3; +.footer-nav { + background-color: var.$bg-blue-3; - .footer-socials { - gap: mix.rem(8px); - } + .footer-socials { + gap: mix.rem(8px); } +} - .footer-secondary-nav { - background: var.$bg-blue-2; - } +.footer-secondary-nav { + background: var.$bg-blue-2; } diff --git a/src/app/core/components/forbidden-page/forbidden-page.component.spec.ts b/src/app/core/components/forbidden-page/forbidden-page.component.spec.ts index 236e6821e..7980e7835 100644 --- a/src/app/core/components/forbidden-page/forbidden-page.component.spec.ts +++ b/src/app/core/components/forbidden-page/forbidden-page.component.spec.ts @@ -1,3 +1,6 @@ +import { TranslatePipe } from '@ngx-translate/core'; +import { MockPipe } from 'ng-mocks'; + import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ForbiddenPageComponent } from './forbidden-page.component'; @@ -8,7 +11,7 @@ describe('ForbiddenPageComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ForbiddenPageComponent], + imports: [ForbiddenPageComponent, MockPipe(TranslatePipe)], }).compileComponents(); fixture = TestBed.createComponent(ForbiddenPageComponent); diff --git a/src/app/core/components/nav-menu/nav-menu.component.scss b/src/app/core/components/nav-menu/nav-menu.component.scss index 7228bf2ee..5f4e7a8aa 100644 --- a/src/app/core/components/nav-menu/nav-menu.component.scss +++ b/src/app/core/components/nav-menu/nav-menu.component.scss @@ -1,15 +1,12 @@ -@use "assets/styles/variables" as var; @use "assets/styles/mixins" as mix; -:host { - .nav-menu { - width: 250px; - max-width: 250px; +.nav-menu { + width: 250px; + max-width: 250px; - .active { - background-color: var.$dark-blue-2; - border-radius: mix.rem(8px); - font-weight: 700; - } + .active { + background-color: var(--dark-blue-2); + border-radius: mix.rem(8px); + font-weight: 700; } } diff --git a/src/app/core/components/nav-menu/nav-menu.component.ts b/src/app/core/components/nav-menu/nav-menu.component.ts index fc1502642..035c14c66 100644 --- a/src/app/core/components/nav-menu/nav-menu.component.ts +++ b/src/app/core/components/nav-menu/nav-menu.component.ts @@ -9,7 +9,7 @@ import { Component, computed, inject, output } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { ActivatedRoute, NavigationEnd, Router, RouterLink, RouterLinkActive } from '@angular/router'; -import { NAV_ITEMS, PROJECT_MENU_ITEMS } from '@core/constants/nav-items.constant'; +import { NAV_ITEMS, PROJECT_MENU_ITEMS } from '@core/constants'; import { IconComponent } from '@osf/shared/components'; import { NavItem } from '@osf/shared/models'; @@ -20,29 +20,29 @@ import { NavItem } from '@osf/shared/models'; styleUrl: './nav-menu.component.scss', }) export class NavMenuComponent { - readonly #router = inject(Router); - readonly #route = inject(ActivatedRoute); + private readonly router = inject(Router); + private readonly route = inject(ActivatedRoute); protected readonly navItems = NAV_ITEMS; protected readonly myProjectMenuItems = PROJECT_MENU_ITEMS; - protected readonly mainMenuItems = this.navItems.map((item) => this.#convertToMenuItem(item)); + protected readonly mainMenuItems = this.navItems.map((item) => this.convertToMenuItem(item)); closeMenu = output(); protected readonly currentRoute = toSignal( - this.#router.events.pipe( + this.router.events.pipe( filter((event): event is NavigationEnd => event instanceof NavigationEnd), - map(() => this.#getRouteInfo()) + map(() => this.getRouteInfo()) ), { - initialValue: this.#getRouteInfo(), + initialValue: this.getRouteInfo(), } ); protected readonly currentProjectId = computed(() => this.currentRoute().projectId); protected readonly isProjectRoute = computed(() => !!this.currentProjectId()); - #convertToMenuItem(item: NavItem): MenuItem { - const currentUrl = this.#router.url; + convertToMenuItem(item: NavItem): MenuItem { + const currentUrl = this.router.url; const isExpanded = item.isCollapsible && (currentUrl.startsWith(item.path) || @@ -53,13 +53,13 @@ export class NavMenuComponent { icon: item.icon ? `osf-icon-${item.icon}` : '', expanded: isExpanded, routerLink: item.isCollapsible ? undefined : item.path, - items: item.items?.map((subItem) => this.#convertToMenuItem(subItem)), + items: item.items?.map((subItem) => this.convertToMenuItem(subItem)), }; } - #getRouteInfo() { - const projectId = this.#route.firstChild?.snapshot.params['id'] || null; - const section = this.#route.firstChild?.firstChild?.snapshot.url[0]?.path || 'overview'; + getRouteInfo() { + const projectId = this.route.firstChild?.snapshot.params['id'] || null; + const section = this.route.firstChild?.firstChild?.snapshot.url[0]?.path || 'overview'; return { projectId, section }; } diff --git a/src/app/core/components/page-not-found/page-not-found.component.spec.ts b/src/app/core/components/page-not-found/page-not-found.component.spec.ts index 90873eba8..3da4b864d 100644 --- a/src/app/core/components/page-not-found/page-not-found.component.spec.ts +++ b/src/app/core/components/page-not-found/page-not-found.component.spec.ts @@ -1,3 +1,6 @@ +import { TranslatePipe } from '@ngx-translate/core'; +import { MockPipe } from 'ng-mocks'; + import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PageNotFoundComponent } from './page-not-found.component'; @@ -8,7 +11,7 @@ describe('PageNotFoundComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [PageNotFoundComponent], + imports: [PageNotFoundComponent, MockPipe(TranslatePipe)], }).compileComponents(); fixture = TestBed.createComponent(PageNotFoundComponent); diff --git a/src/app/core/components/request-access/request-access.component.spec.ts b/src/app/core/components/request-access/request-access.component.spec.ts index bc897e381..bf2e5594d 100644 --- a/src/app/core/components/request-access/request-access.component.spec.ts +++ b/src/app/core/components/request-access/request-access.component.spec.ts @@ -1,4 +1,14 @@ +import { TranslatePipe } from '@ngx-translate/core'; +import { MockPipe, MockProvider } from 'ng-mocks'; + +import { of } from 'rxjs'; + +import { provideHttpClient } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; + +import { ToastService } from '@osf/shared/services'; import { RequestAccessComponent } from './request-access.component'; @@ -8,7 +18,13 @@ describe('RequestAccessComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [RequestAccessComponent], + imports: [RequestAccessComponent, MockPipe(TranslatePipe)], + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + MockProvider(ToastService), + MockProvider(ActivatedRoute, { params: of({}) }), + ], }).compileComponents(); fixture = TestBed.createComponent(RequestAccessComponent); diff --git a/src/app/core/components/root/root.component.scss b/src/app/core/components/root/root.component.scss index 262425260..beee5455a 100644 --- a/src/app/core/components/root/root.component.scss +++ b/src/app/core/components/root/root.component.scss @@ -5,43 +5,43 @@ display: flex; height: 100vh; max-width: 100vw; +} + +.layout-desktop { + display: flex; + flex: 1; + background-color: var.$dark-blue-1; + max-width: 100vw; - .layout-desktop { + .content-wrapper { + position: relative; + background-color: var.$bg-blue-3; + border-radius: mix.rem(12px); + margin: mix.rem(6px); display: flex; + flex-direction: column; flex: 1; - background-color: var.$dark-blue-1; - max-width: 100vw; - - .content-wrapper { - position: relative; - background-color: var.$bg-blue-3; - border-radius: mix.rem(12px); - margin: mix.rem(6px); - display: flex; - flex-direction: column; - flex: 1; - overflow-y: auto; - } + overflow-y: auto; } +} + +.layout-tablet { + @include mix.flex-center; + flex: 1; + max-width: 100vw; - .layout-tablet { - @include mix.flex-center; + .content-wrapper { + @include mix.flex-column; + width: 100%; + height: 100%; flex: 1; - max-width: 100vw; + overflow-y: auto; + background-color: var.$bg-blue-3; - .content-wrapper { + .content { + position: relative; @include mix.flex-column; - width: 100%; - height: 100%; flex: 1; - overflow-y: auto; - background-color: var.$bg-blue-3; - - .content { - position: relative; - @include mix.flex-column; - flex: 1; - } } } } diff --git a/src/app/core/components/topnav/topnav.component.scss b/src/app/core/components/topnav/topnav.component.scss index 2deb687b0..595ed25eb 100644 --- a/src/app/core/components/topnav/topnav.component.scss +++ b/src/app/core/components/topnav/topnav.component.scss @@ -1,20 +1,19 @@ -@use "assets/styles/variables" as var; @use "assets/styles/mixins" as mix; :host { z-index: 1103; +} - .nav-container { - background: var.$dark-blue-1; - padding: mix.rem(28px) mix.rem(24px); - color: var.$white; +.nav-container { + background: var(--dark-blue-1); + padding: mix.rem(28px) mix.rem(24px); + color: var(--white); - .topnav-btn { - height: mix.rem(36px); - width: mix.rem(36px); + .topnav-btn { + height: mix.rem(36px); + width: mix.rem(36px); - --p-button-contrast-background: transparent; - --p-button-contrast-border-color: transparent; - } + --p-button-contrast-background: transparent; + --p-button-contrast-border-color: transparent; } } diff --git a/src/app/core/constants/ngxs-states.constant.ts b/src/app/core/constants/ngxs-states.constant.ts index d04e13eb9..60211390e 100644 --- a/src/app/core/constants/ngxs-states.constant.ts +++ b/src/app/core/constants/ngxs-states.constant.ts @@ -12,13 +12,11 @@ import { AccountSettingsState } from '@osf/features/settings/account-settings/st import { DeveloperAppsState } from '@osf/features/settings/developer-apps/store'; import { NotificationSubscriptionState } from '@osf/features/settings/notifications/store'; import { ProfileSettingsState } from '@osf/features/settings/profile-settings/store/profile-settings.state'; -import { TokensState } from '@osf/features/settings/tokens/store'; import { InstitutionsState } from '@shared/stores'; import { AddonsState } from '@shared/stores/addons'; export const STATES = [ AuthState, - TokensState, AddonsState, UserState, MyProjectsState, diff --git a/src/app/core/models/user.models.ts b/src/app/core/models/user.models.ts index eff1c718b..318400525 100644 --- a/src/app/core/models/user.models.ts +++ b/src/app/core/models/user.models.ts @@ -23,7 +23,6 @@ export interface UserSettings { subscribeOsfHelpEmail: boolean; } -// API Request/Response Models export interface UserGetResponse { id: string; type: string; diff --git a/src/app/features/project/addons/components/connect-configured-addon/connect-configured-addon.component.spec.ts b/src/app/features/project/addons/components/connect-configured-addon/connect-configured-addon.component.spec.ts index d1a866264..88240f190 100644 --- a/src/app/features/project/addons/components/connect-configured-addon/connect-configured-addon.component.spec.ts +++ b/src/app/features/project/addons/components/connect-configured-addon/connect-configured-addon.component.spec.ts @@ -77,6 +77,5 @@ describe('ConnectAddonComponent', () => { expect(component).toBeTruthy(); expect(component['addon']()).toEqual(mockAddon); expect(component['terms']().length).toBeGreaterThan(0); - expect(component['addonForm']).toBeTruthy(); }); }); diff --git a/src/app/features/project/contributors/components/create-view-link-dialog/create-view-link-dialog.component.html b/src/app/features/project/contributors/components/create-view-link-dialog/create-view-link-dialog.component.html index 135c3e6b5..eb0f4aef4 100644 --- a/src/app/features/project/contributors/components/create-view-link-dialog/create-view-link-dialog.component.html +++ b/src/app/features/project/contributors/components/create-view-link-dialog/create-view-link-dialog.component.html @@ -55,7 +55,6 @@ class="w-full" styleClass="w-full" (click)="dialogRef.close()" - text severity="info" [label]="'project.contributors.addDialog.cancel' | translate" > diff --git a/src/app/features/search/search.component.scss b/src/app/features/search/search.component.scss index 3429bc57f..1ffdbbbe2 100644 --- a/src/app/features/search/search.component.scss +++ b/src/app/features/search/search.component.scss @@ -1,6 +1,9 @@ @use "assets/styles/variables" as var; :host { + display: flex; + flex-direction: column; + flex: 1; height: 100%; } diff --git a/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.html b/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.html index f6a2a10f3..bed186089 100644 --- a/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.html +++ b/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.html @@ -1,28 +1,33 @@
- - + +
-

+

{{ 'settings.tokens.form.scopes.title' | translate }} -

-

+

+ +

{{ 'settings.tokens.form.scopes.description' | translate }}

-
+
@for (scope of tokenScopes(); track scope.id) {
+
- - {{ scope.attributes.description }} + + {{ scope.description }}
} @@ -31,12 +36,14 @@

{{ scope.id }}

@if (isEditMode()) { - +
+ +
} @else { {{ scope.id }} class="w-12rem btn-full-width" [label]="'settings.tokens.form.buttons.create' | translate" type="submit" - [disabled]="!tokenForm.valid" + [disabled]="!tokenForm.valid || isLoading()" + [loading]="isLoading()" /> }
diff --git a/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.scss b/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.scss index a4bcfd80e..97c455de0 100644 --- a/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.scss +++ b/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.scss @@ -1,11 +1,4 @@ -@use "assets/styles/variables" as var; - -:host { - label { - color: var.$dark-blue-1; - } - - h3 { - text-transform: none; - } +.scope-container { + height: 40vh; + overflow: auto; } diff --git a/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.ts b/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.ts index 995868f3f..32111c9e1 100644 --- a/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.ts +++ b/src/app/features/settings/tokens/components/token-add-edit-form/token-add-edit-form.component.ts @@ -1,47 +1,57 @@ -import { Store } from '@ngxs/store'; +import { createDispatchMap, select, Store } from '@ngxs/store'; import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { Button } from 'primeng/button'; import { Checkbox } from 'primeng/checkbox'; import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog'; -import { InputText } from 'primeng/inputtext'; import { map } from 'rxjs'; -import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, Component, inject, input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, effect, inject, input, OnInit } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { IS_XSMALL } from '@osf/shared/utils'; +import { TextInputComponent } from '@osf/shared/components'; +import { InputLimits } from '@osf/shared/constants'; +import { ToastService } from '@osf/shared/services'; -import { Token, TokenForm, TokenFormControls } from '../../models'; +import { TokenForm, TokenFormControls, TokenModel } from '../../models'; import { CreateToken, GetTokens, TokensSelectors, UpdateToken } from '../../store'; import { TokenCreatedDialogComponent } from '../token-created-dialog/token-created-dialog.component'; @Component({ selector: 'osf-token-add-edit-form', - imports: [Button, InputText, ReactiveFormsModule, CommonModule, Checkbox, TranslatePipe], + imports: [Button, Checkbox, ReactiveFormsModule, TextInputComponent, TranslatePipe], templateUrl: './token-add-edit-form.component.html', styleUrl: './token-add-edit-form.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class TokenAddEditFormComponent implements OnInit { - #store = inject(Store); - #route = inject(ActivatedRoute); - #router = inject(Router); - #dialogService = inject(DialogService); - #translateService = inject(TranslateService); + private readonly route = inject(ActivatedRoute); + private readonly router = inject(Router); + private readonly dialogService = inject(DialogService); + private readonly translateService = inject(TranslateService); + private readonly toastService = inject(ToastService); + private readonly store = inject(Store); + + private readonly actions = createDispatchMap({ + createToken: CreateToken, + getTokens: GetTokens, + updateToken: UpdateToken, + }); isEditMode = input(false); - initialValues = input(null); - protected readonly tokenId = toSignal(this.#route.params.pipe(map((params) => params['id']))); + initialValues = input(null); + + inputLimits = InputLimits.fullName; + + protected readonly tokenId = toSignal(this.route.params.pipe(map((params) => params['id']))); protected readonly dialogRef = inject(DynamicDialogRef); protected readonly TokenFormControls = TokenFormControls; - protected readonly isMobile = toSignal(inject(IS_XSMALL)); - protected readonly tokenScopes = this.#store.selectSignal(TokensSelectors.getScopes); + protected readonly tokenScopes = select(TokensSelectors.getScopes); + protected readonly isLoading = select(TokensSelectors.isTokensLoading); readonly tokenForm: TokenForm = new FormGroup({ [TokenFormControls.TokenName]: new FormControl('', { @@ -54,8 +64,13 @@ export class TokenAddEditFormComponent implements OnInit { }), }); + constructor() { + effect(() => { + return this.isLoading() ? this.tokenForm.disable() : this.tokenForm.enable(); + }); + } + ngOnInit(): void { - this.#store.dispatch(GetTokens); if (this.initialValues()) { this.tokenForm.patchValue({ [TokenFormControls.TokenName]: this.initialValues()?.name, @@ -73,36 +88,33 @@ export class TokenAddEditFormComponent implements OnInit { } const { tokenName, scopes } = this.tokenForm.value; + if (!tokenName || !scopes) return; if (!this.isEditMode()) { - this.#store.dispatch(new CreateToken(tokenName, scopes)).subscribe({ + this.actions.createToken(tokenName, scopes).subscribe({ complete: () => { - const tokens = this.#store.selectSnapshot(TokensSelectors.getTokens); - const newToken = tokens[0]; + this.toastService.showSuccess('settings.tokens.toastMessage.successCreate'); + const tokens = this.store.selectSignal(TokensSelectors.getTokens); + const newToken = tokens()[0]; this.dialogRef.close(); - this.#showTokenCreatedDialog(newToken.name, newToken.tokenId); + this.showTokenCreatedDialog(newToken.name, newToken.tokenId); }, }); } else { - this.#store.dispatch(new UpdateToken(this.tokenId(), tokenName, scopes)).subscribe({ + this.actions.updateToken(this.tokenId(), tokenName, scopes).subscribe({ complete: () => { - this.#router.navigate(['settings/tokens']); + this.toastService.showSuccess('settings.tokens.toastMessage.successEdit'); + this.router.navigate(['settings/tokens']); }, }); } } - #showTokenCreatedDialog(tokenName: string, tokenValue: string) { - let dialogWidth = '500px'; - - if (this.isMobile()) { - dialogWidth = '345px'; - } - - this.#dialogService.open(TokenCreatedDialogComponent, { - width: dialogWidth, - header: this.#translateService.instant('settings.tokens.created-dialog.title'), + showTokenCreatedDialog(tokenName: string, tokenValue: string) { + this.dialogService.open(TokenCreatedDialogComponent, { + width: '500px', + header: this.translateService.instant('settings.tokens.createdDialog.title'), closeOnEscape: true, modal: true, closable: true, diff --git a/src/app/features/settings/tokens/components/token-created-dialog/token-created-dialog.component.html b/src/app/features/settings/tokens/components/token-created-dialog/token-created-dialog.component.html index 593c88b47..442daea1b 100644 --- a/src/app/features/settings/tokens/components/token-created-dialog/token-created-dialog.component.html +++ b/src/app/features/settings/tokens/components/token-created-dialog/token-created-dialog.component.html @@ -8,22 +8,18 @@
-
- - {{ 'settings.tokens.createdDialog.copyNotification' | translate }} - - - - - - - -
+ + + + + +
-

{{ 'settings.tokens.createdDialog.tokenWarning' | translate }}

+ +

{{ 'settings.tokens.createdDialog.tokenWarning' | translate }}

-
+
>('tokenInput'); readonly tokenName = input(this.config.data?.tokenName ?? ''); readonly tokenId = input(this.config.data?.tokenValue ?? ''); - protected readonly tokenCopiedNotificationVisible = signal(false); constructor() { afterNextRender(() => { @@ -42,9 +41,4 @@ export class TokenCreatedDialogComponent { } }); } - - protected tokenCopiedToClipboard(): void { - this.tokenCopiedNotificationVisible.set(true); - setTimeout(() => this.tokenCopiedNotificationVisible.set(false), 2000); - } } diff --git a/src/app/features/settings/tokens/mappers/index.ts b/src/app/features/settings/tokens/mappers/index.ts index b56bed078..3dfc4f08d 100644 --- a/src/app/features/settings/tokens/mappers/index.ts +++ b/src/app/features/settings/tokens/mappers/index.ts @@ -1 +1,2 @@ +export * from './scope.mapper'; export * from './token.mapper'; diff --git a/src/app/features/settings/tokens/mappers/scope.mapper.ts b/src/app/features/settings/tokens/mappers/scope.mapper.ts new file mode 100644 index 000000000..998650bb6 --- /dev/null +++ b/src/app/features/settings/tokens/mappers/scope.mapper.ts @@ -0,0 +1,10 @@ +import { ScopeJsonApi, ScopeModel } from '../models'; + +export class ScopeMapper { + static fromResponse(response: ScopeJsonApi[]): ScopeModel[] { + return response.map((scope) => ({ + id: scope.id, + description: scope.attributes.description, + })); + } +} diff --git a/src/app/features/settings/tokens/mappers/token.mapper.ts b/src/app/features/settings/tokens/mappers/token.mapper.ts index 45cc20602..b3f0ae3ff 100644 --- a/src/app/features/settings/tokens/mappers/token.mapper.ts +++ b/src/app/features/settings/tokens/mappers/token.mapper.ts @@ -1,4 +1,4 @@ -import { Token, TokenCreateRequestJsonApi, TokenCreateResponseJsonApi, TokenGetResponseJsonApi } from '../models'; +import { TokenCreateRequestJsonApi, TokenCreateResponseJsonApi, TokenGetResponseJsonApi, TokenModel } from '../models'; export class TokenMapper { static toRequest(name: string, scopes: string[]): TokenCreateRequestJsonApi { @@ -13,7 +13,7 @@ export class TokenMapper { }; } - static fromCreateResponse(response: TokenCreateResponseJsonApi): Token { + static fromCreateResponse(response: TokenCreateResponseJsonApi): TokenModel { return { id: response.id, name: response.attributes.name, @@ -23,7 +23,7 @@ export class TokenMapper { }; } - static fromGetResponse(response: TokenGetResponseJsonApi): Token { + static fromGetResponse(response: TokenGetResponseJsonApi): TokenModel { return { id: response.id, name: response.attributes.name, diff --git a/src/app/features/settings/tokens/models/add-edit-token.model.ts b/src/app/features/settings/tokens/models/add-edit-token.model.ts new file mode 100644 index 000000000..f7cfdac4e --- /dev/null +++ b/src/app/features/settings/tokens/models/add-edit-token.model.ts @@ -0,0 +1,4 @@ +export interface AddEditTokenModel { + name: string; + scopes: string[]; +} diff --git a/src/app/features/settings/tokens/models/index.ts b/src/app/features/settings/tokens/models/index.ts index 0b3ab05e3..8bc250995 100644 --- a/src/app/features/settings/tokens/models/index.ts +++ b/src/app/features/settings/tokens/models/index.ts @@ -1,3 +1,5 @@ export * from './scope.model'; +export * from './scope-json-api.model'; +export * from './token.model'; export * from './token-form.model'; -export * from './tokens.model'; +export * from './token-json-api.model'; diff --git a/src/app/features/settings/tokens/models/scope-json-api.model.ts b/src/app/features/settings/tokens/models/scope-json-api.model.ts new file mode 100644 index 000000000..443b1a22f --- /dev/null +++ b/src/app/features/settings/tokens/models/scope-json-api.model.ts @@ -0,0 +1,10 @@ +export interface ScopeJsonApi { + id: string; + type: string; + attributes: { + description: string; + }; + links: { + self: string; + }; +} diff --git a/src/app/features/settings/tokens/models/scope.model.ts b/src/app/features/settings/tokens/models/scope.model.ts index 11abe44af..d92bdfc01 100644 --- a/src/app/features/settings/tokens/models/scope.model.ts +++ b/src/app/features/settings/tokens/models/scope.model.ts @@ -1,10 +1,4 @@ -export interface Scope { +export interface ScopeModel { id: string; - type: string; - attributes: { - description: string; - }; - links: { - self: string; - }; + description: string; } diff --git a/src/app/features/settings/tokens/models/tokens.model.ts b/src/app/features/settings/tokens/models/token-json-api.model.ts similarity index 69% rename from src/app/features/settings/tokens/models/tokens.model.ts rename to src/app/features/settings/tokens/models/token-json-api.model.ts index 5fef6f9b4..657116c8b 100644 --- a/src/app/features/settings/tokens/models/tokens.model.ts +++ b/src/app/features/settings/tokens/models/token-json-api.model.ts @@ -1,4 +1,3 @@ -// API Request Model export interface TokenCreateRequestJsonApi { data: { attributes: { @@ -9,7 +8,6 @@ export interface TokenCreateRequestJsonApi { }; } -// API Response Model export interface TokenCreateResponseJsonApi { id: string; type: 'tokens'; @@ -21,7 +19,6 @@ export interface TokenCreateResponseJsonApi { }; } -// API Response Model for GET request export interface TokenGetResponseJsonApi { id: string; type: 'tokens'; @@ -31,12 +28,3 @@ export interface TokenGetResponseJsonApi { owner: string; }; } - -// Domain Models -export interface Token { - id: string; - name: string; - tokenId: string; - scopes: string[]; - ownerId: string; -} diff --git a/src/app/features/settings/tokens/models/token.model.ts b/src/app/features/settings/tokens/models/token.model.ts new file mode 100644 index 000000000..f4b5a3748 --- /dev/null +++ b/src/app/features/settings/tokens/models/token.model.ts @@ -0,0 +1,7 @@ +export interface TokenModel { + id: string; + name: string; + tokenId: string; + scopes: string[]; + ownerId: string; +} diff --git a/src/app/features/settings/tokens/pages/token-details/token-details.component.html b/src/app/features/settings/tokens/pages/token-details/token-details.component.html index dce71a1c5..33037eeb8 100644 --- a/src/app/features/settings/tokens/pages/token-details/token-details.component.html +++ b/src/app/features/settings/tokens/pages/token-details/token-details.component.html @@ -1,24 +1,33 @@ -
-