diff --git a/src/app/core/constants/general.ts b/src/app/core/constants/general.ts index 1abb4abe..2975aafd 100644 --- a/src/app/core/constants/general.ts +++ b/src/app/core/constants/general.ts @@ -1,4 +1,8 @@ +import { Profile, RequestUriMethod } from "../models/TransactionInitializationRequest"; + export const ACTIVE_TRANSACTION = 'ACTIVE_TRANSACTION'; export const SCHEME = 'scheme'; -export const DEFAULT_SCHEME = 'haip-vp://'; export const ISSUER_CHAIN = 'ISSUER_CHAIN'; + +export const DefaultRequestUriMethod: RequestUriMethod = 'get'; +export const DefaultProfile: Profile = 'haip'; \ No newline at end of file diff --git a/src/app/core/layout/wallet-layout/wallet-layout-header/wallet-layout-header.component.html b/src/app/core/layout/wallet-layout/wallet-layout-header/wallet-layout-header.component.html index 3c09816d..45a1cb16 100644 --- a/src/app/core/layout/wallet-layout/wallet-layout-header/wallet-layout-header.component.html +++ b/src/app/core/layout/wallet-layout/wallet-layout-header/wallet-layout-header.component.html @@ -8,9 +8,6 @@ Inspect transaction logs - Change default scheme Configure issuer chain diff --git a/src/app/core/layout/wallet-layout/wallet-layout-header/wallet-layout-header.component.ts b/src/app/core/layout/wallet-layout/wallet-layout-header/wallet-layout-header.component.ts index e60f7612..b8a6fef8 100644 --- a/src/app/core/layout/wallet-layout/wallet-layout-header/wallet-layout-header.component.ts +++ b/src/app/core/layout/wallet-layout/wallet-layout-header/wallet-layout-header.component.ts @@ -6,7 +6,6 @@ import { MatMenuModule } from "@angular/material/menu"; import { MatToolbarModule } from '@angular/material/toolbar'; import { OpenLogsComponent } from "@shared/elements/open-logs/open-logs.component"; import { MatDialog, MatDialogModule } from "@angular/material/dialog"; -import {InputSchemeComponent} from "@shared/elements/input-scheme/input-scheme.component"; import { IssuerChainComponent } from '@app/shared/elements/trusted-issuer/issuer-chain.component'; @Component({ @@ -40,16 +39,6 @@ export class WalletLayoutHeaderComponent { }); } - changeCustomScheme () { - this.dialog.open(InputSchemeComponent, { - data: { - transactionId: '', - label: 'Inspect transaction logs', - isInspectLogs: true - }, - }); - } - changeIssuerChain () { this.dialog.open(IssuerChainComponent, { data: { diff --git a/src/app/core/models/InitializedTransaction.ts b/src/app/core/models/InitializedTransaction.ts index 6a33cbc0..54e47310 100644 --- a/src/app/core/models/InitializedTransaction.ts +++ b/src/app/core/models/InitializedTransaction.ts @@ -1,6 +1,9 @@ +import { RequestUriMethod } from "./TransactionInitializationRequest" + export type InitializedTransaction = { client_id: string, request_uri: string, - request_uri_method: 'get' | 'post', - transaction_id: string + request_uri_method: RequestUriMethod, + transaction_id: string, + authorization_request_uri: string } diff --git a/src/app/core/models/TransactionInitializationRequest.ts b/src/app/core/models/TransactionInitializationRequest.ts index 337e7619..fe4d161f 100644 --- a/src/app/core/models/TransactionInitializationRequest.ts +++ b/src/app/core/models/TransactionInitializationRequest.ts @@ -1,10 +1,26 @@ import { DCQL } from './dcql/DCQL'; +export type RequestUriMethod = 'get' | 'post'; +export type Profile = 'haip' | 'openid4vp'; +export type ProfileOptions = { + endpoint: string; +} +export const profileOptions: Record = { + haip: { + endpoint: 'haip-vp://', + }, + openid4vp: { + endpoint: 'openid4vp://', + }, +}; + export type TransactionInitializationRequest = { nonce: string; - request_uri_method: 'get' | 'post'; + request_uri_method: RequestUriMethod; dcql_query: DCQL; issuer_chain?: string; + profile: Profile; + authorization_request_uri: string; }; export type PresentationQuery = DCQL; diff --git a/src/app/core/services/dcql-service.ts b/src/app/core/services/dcql-service.ts index 1a94178d..91e4f06d 100644 --- a/src/app/core/services/dcql-service.ts +++ b/src/app/core/services/dcql-service.ts @@ -8,7 +8,7 @@ import { AttributeSelectionMethod, } from '@app/features/presentation-request-preparation/models/AttestationSelection'; import { v4 as uuidv4 } from 'uuid'; -import { TransactionInitializationRequest } from '../models/TransactionInitializationRequest'; +import { Profile, RequestUriMethod, TransactionInitializationRequest } from '../models/TransactionInitializationRequest'; import { MsoMdocAttestation, SdJwtVcAttestation, @@ -21,7 +21,9 @@ export class DCQLService { dcqlPresentationRequest( selectedAttestations: AttestationSelection[], selectedAttributes: { [id: string]: string[] }, - selectedRequestUriMethod: 'get' | 'post', + selectedRequestUriMethod: RequestUriMethod, + selectedProfile: Profile, + authorizationRequestUri: string, issuerChain?: string ): TransactionInitializationRequest { let dcqlQueries: CredentialQuery[] = selectedAttestations.map( @@ -44,6 +46,8 @@ export class DCQLService { nonce: uuidv4(), request_uri_method: selectedRequestUriMethod, issuer_chain: issuerChain, + profile: selectedProfile, + authorization_request_uri: authorizationRequestUri }; } diff --git a/src/app/core/services/verifier-endpoint.service.ts b/src/app/core/services/verifier-endpoint.service.ts index a3404d7b..7705e820 100644 --- a/src/app/core/services/verifier-endpoint.service.ts +++ b/src/app/core/services/verifier-endpoint.service.ts @@ -14,8 +14,10 @@ import {ActiveTransaction} from "@core/models/ActiveTransaction"; import { SessionStorageService } from './session-storage.service'; const SAME_DEVICE_UI_RE_ENTRY_URL = '/get-wallet-code?response_code={RESPONSE_CODE}'; -const PRESENTATIONS_ENDPOINT = 'ui/presentations'; -const VALIDATE_SD_JWT_VC_PRESENTATION_ENDPOINT = 'utilities/process/sdJwtVc'; +const INIT_TRANSACTION_ENDPOINT = 'ui/presentations/v2'; +const WALLET_RESPONSE_ENDPOINT = 'ui/presentations/${transactionId}'; +const EVENTS_ENDPOINT = 'ui/presentations/${transactionId}/events'; +const VALIDATE_SD_JWT_VC_PRESENTATION_ENDPOINT = 'utilities/validations/sdJwtVc'; @Injectable() export class VerifierEndpointService { @@ -34,7 +36,7 @@ export class VerifierEndpointService { if (!this.deviceDetectorService.isDesktop()) { payload['wallet_response_redirect_uri_template'] = location.origin + SAME_DEVICE_UI_RE_ENTRY_URL; } - this.httpService.post(PRESENTATIONS_ENDPOINT, payload) + this.httpService.post(INIT_TRANSACTION_ENDPOINT, payload) .pipe( tap((res) => { let activeTransaction : ActiveTransaction = { @@ -49,14 +51,14 @@ export class VerifierEndpointService { getWalletResponse(transaction_id: string, code?: string): Observable { if (typeof code == 'undefined') { - return this.httpService.get(PRESENTATIONS_ENDPOINT+`/${transaction_id}`); + return this.httpService.get(WALLET_RESPONSE_ENDPOINT.replace('${transactionId}', transaction_id)); } else { - return this.httpService.get(PRESENTATIONS_ENDPOINT+`/${transaction_id}?response_code=${code}`); + return this.httpService.get(WALLET_RESPONSE_ENDPOINT.replace('${transactionId}', transaction_id) + `?response_code=${code}`); } } getsTransactionEventsLogs(transactionId: string): Observable { - return this.httpService.get(PRESENTATIONS_ENDPOINT+`/${transactionId}/events`) + return this.httpService.get(EVENTS_ENDPOINT.replace('${transactionId}', transactionId)) .pipe( map((data: any) => { return data.events.map((event: EventLog) => { diff --git a/src/app/features/invoke-wallet/components/qr-code/qr-code.component.ts b/src/app/features/invoke-wallet/components/qr-code/qr-code.component.ts index f4075528..375b8406 100644 --- a/src/app/features/invoke-wallet/components/qr-code/qr-code.component.ts +++ b/src/app/features/invoke-wallet/components/qr-code/qr-code.component.ts @@ -50,7 +50,7 @@ export class QrCodeComponent implements OnInit, OnDestroy { transaction!: ActiveTransaction; deepLinkTxt!: string; - scheme!: string; + qrCodeDownloadLink!: SafeUrl; readonly dialog!: MatDialog; @@ -69,12 +69,6 @@ export class QrCodeComponent implements OnInit, OnDestroy { this.localStorageService = this.injector.get(LocalStorageService); this.dialog = this.injector.get(MatDialog); this.isCrossDevice = this.deviceDetectorService.isDesktop(); - - if (this.localStorageService.get(constants.SCHEME)) { - this.scheme = this.localStorageService.get(constants.SCHEME) ?? constants.DEFAULT_SCHEME; - } else { - this.scheme = constants.DEFAULT_SCHEME; - } } ngOnInit(): void { @@ -84,7 +78,7 @@ export class QrCodeComponent implements OnInit, OnDestroy { if (!this.transaction) { this.navigateService.goHome(); } else { - this.deepLinkTxt = this.buildQrCode(this.transaction.initialized_transaction); + this.deepLinkTxt = this.transaction.initialized_transaction.authorization_request_uri; if (this.isCrossDevice) { this.pollingRequest(this.transaction.initialized_transaction.transaction_id); } @@ -131,10 +125,6 @@ export class QrCodeComponent implements OnInit, OnDestroy { return concludedTransaction; } - private buildQrCode(data: { client_id: string, request_uri: string, request_uri_method: 'get' | 'post', transaction_id: string }): string { - return `${this.scheme}?client_id=${encodeURIComponent(data.client_id)}&request_uri=${encodeURIComponent(data.request_uri)}&request_uri_method=${encodeURIComponent(data.request_uri_method)}`; - } - openLogs() { this.dialog.open(OpenLogsComponent, { data: { diff --git a/src/app/features/presentation-request-preparation/components/attribute-selection/attribute-selection.component.html b/src/app/features/presentation-request-preparation/components/attribute-selection/attribute-selection.component.html index 7280b244..03df8086 100644 --- a/src/app/features/presentation-request-preparation/components/attribute-selection/attribute-selection.component.html +++ b/src/app/features/presentation-request-preparation/components/attribute-selection/attribute-selection.component.html @@ -1,6 +1,6 @@
- + {{ nameOf(selection.type) }} diff --git a/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.html b/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.html new file mode 100644 index 00000000..09742a98 --- /dev/null +++ b/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.html @@ -0,0 +1,73 @@ + + + Presentation Options + + Configure the options for your presentation request. + + + + +
+
+
+ Presentation Profile +

+ Defines the rules and constraints of the presentation +

+
+
+ + HAIP + OpenID4VP + +
+
+ +
+
+ Request URI Method +

+ Choose how the wallet fetches the authorization request +

+
+
+ + GET + POST + +
+
+ +
+
+ Authorization Endpoint +

+ Specify an endpoint URI for the authorization request +

+
+
+ + Authorization Endpoint + + +
+
+
+
+
diff --git a/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.scss b/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.scss new file mode 100644 index 00000000..158f26f1 --- /dev/null +++ b/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.scss @@ -0,0 +1,46 @@ +:host { + display: block; +} + +.request-options-grid { + display: flex; + flex-direction: column; + gap: 24px; + padding-top: 16px; +} + +.request-options-row { + display: grid; + grid-template-columns: 220px minmax(0, 1fr); + gap: 16px; +} + +.request-options-label { + text-align: right; + + span { + display: block; + font-weight: 500; + } +} + +.request-options-helper { + margin: 4px 0 0; + font-size: 0.85rem; + color: rgba(0, 0, 0, 0.6); +} + +.request-options-control { + flex-direction: column; + gap: 8px; +} + +@media (max-width: 576px) { + .request-options-row { + grid-template-columns: 1fr; + } + + .request-options-label { + text-align: left; + } +} diff --git a/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.spec.ts b/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.spec.ts new file mode 100644 index 00000000..66b8db98 --- /dev/null +++ b/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PresentationOptionsComponent } from './presentation-options.component'; + +describe('PresentationOptionsComponent', () => { + let component: PresentationOptionsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PresentationOptionsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PresentationOptionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.ts b/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.ts new file mode 100644 index 00000000..941df092 --- /dev/null +++ b/src/app/features/presentation-request-preparation/components/presentation-options/presentation-options.component.ts @@ -0,0 +1,39 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatCardModule, MatCardHeader, MatCardSubtitle, MatCard, MatCardTitle, MatCardContent } from '@angular/material/card'; + +import { + Profile, + RequestUriMethod, +} from '@app/core/models/TransactionInitializationRequest'; + +@Component({ + selector: 'vc-presentation-options', + imports: [ + CommonModule, + ReactiveFormsModule, + MatButtonToggleModule, + MatFormFieldModule, + MatInputModule, + MatCardHeader, + MatCard, + MatCardTitle, + MatCardSubtitle, + MatCardContent +], + templateUrl: './presentation-options.component.html', + styleUrl: './presentation-options.component.scss', +}) +export class PresentationOptionsComponent { + @Input() presentationProfileControl!: FormControl; + @Input() requestUriMethodControl!: FormControl; + @Input() authorizationSchemeControl!: FormControl; + + @Output() profileChange = new EventEmitter(); + @Output() requestUriMethodChange = new EventEmitter(); + @Output() authorizationSchemeChange = new EventEmitter(); +} diff --git a/src/app/features/presentation-request-preparation/home/home.component.html b/src/app/features/presentation-request-preparation/home/home.component.html index dbf50775..cb598e33 100644 --- a/src/app/features/presentation-request-preparation/home/home.component.html +++ b/src/app/features/presentation-request-preparation/home/home.component.html @@ -2,71 +2,109 @@

Define your presentation request

- Follow the steps to specify what will be requested from the wallet to present. + Follow the steps to specify what will be requested from the wallet to + present.

... select attestation(s) - +
- +
- +
-
- ...select attestation(s) attributes - ...select attestation(s) attributes +
- +
- ...select request options and submit - -
-
- Request URI Method -
- - Get - Post - + ...select presentation options and submit + +
+
- - Your presentation request so far... + Your presentation request so far... - - {{ initializationRequest | json }} + {{ + initializationRequest | json + }}
..nothing prepared yet...
- - +
@@ -74,9 +112,9 @@

Define your presentation request

- Or, if this doesn't work for you, go straight to defining your presentation request + Or, if this doesn't work for you, go straight to defining your + presentation request here

-
diff --git a/src/app/features/presentation-request-preparation/home/home.component.scss b/src/app/features/presentation-request-preparation/home/home.component.scss index 12c4af0e..7fd232bf 100644 --- a/src/app/features/presentation-request-preparation/home/home.component.scss +++ b/src/app/features/presentation-request-preparation/home/home.component.scss @@ -15,12 +15,8 @@ } } - .config-option-container { + .presentation-options-container { margin-bottom: 16px; - - .config-option-label { - margin-bottom: 8px; - } } span#as-pre { diff --git a/src/app/features/presentation-request-preparation/home/home.component.ts b/src/app/features/presentation-request-preparation/home/home.component.ts index 31acd774..dcd788ef 100644 --- a/src/app/features/presentation-request-preparation/home/home.component.ts +++ b/src/app/features/presentation-request-preparation/home/home.component.ts @@ -1,4 +1,4 @@ -import { Component, inject, OnDestroy, OnInit } from '@angular/core'; +import { Component, inject, OnDestroy } from '@angular/core'; import { NavigateService } from '@app/core/services/navigate.service'; import { HOME_ACTIONS } from '@core/constants/pages-actions'; import { BodyAction } from '@app/shared/elements/body-actions/models/BodyAction'; @@ -17,9 +17,17 @@ import { Validators, } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; -import { AttestationSelection, AttributeSelectionMethod } from '@features/presentation-request-preparation/models/AttestationSelection'; +import { + AttestationSelection, + AttributeSelectionMethod, +} from '@features/presentation-request-preparation/models/AttestationSelection'; import { AttributeSelectionComponent } from '@features/presentation-request-preparation/components/attribute-selection/attribute-selection.component'; -import { TransactionInitializationRequest } from '@core/models/TransactionInitializationRequest'; +import { + Profile, + profileOptions, + RequestUriMethod, + TransactionInitializationRequest, +} from '@core/models/TransactionInitializationRequest'; import { VerifierEndpointService } from '@core/services/verifier-endpoint.service'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; @@ -30,9 +38,13 @@ import { AttributesSelectionEvent } from '../models/AttributesSelection'; import { DCQLService } from '@app/core/services/dcql-service'; import { Subject } from 'rxjs'; import { SessionStorageService } from '@app/core/services/session-storage.service'; -import { ISSUER_CHAIN } from '@app/core/constants/general'; -import { AttestationFormat } from '@app/core/models/attestation/AttestationFormat'; +import { + DefaultProfile, + DefaultRequestUriMethod, + ISSUER_CHAIN, +} from '@app/core/constants/general'; import { SUPPORTED_ATTESTATIONS } from '@app/core/constants/attestation-definitions'; +import { PresentationOptionsComponent } from '../components/presentation-options/presentation-options.component'; @Component({ imports: [ @@ -53,6 +65,7 @@ import { SUPPORTED_ATTESTATIONS } from '@app/core/constants/attestation-definiti ClipboardModule, MatTooltipModule, MatButtonToggleModule, + PresentationOptionsComponent, ], providers: [VerifierEndpointService], selector: 'vc-presentation-preparation-home', @@ -64,13 +77,21 @@ export class HomeComponent implements OnDestroy { private readonly navigateService: NavigateService, private readonly verifierEndpointService: VerifierEndpointService, private readonly dcqlService: DCQLService, - private readonly sessionStorageService: SessionStorageService, + private readonly sessionStorageService: SessionStorageService ) {} actions: BodyAction[] = HOME_ACTIONS; - requestUriMethodControl = new FormControl('get'); - + requestUriMethodControl = new FormControl(DefaultRequestUriMethod, { + nonNullable: true, + }); + authorizationSchemeControl = new FormControl( + profileOptions[DefaultProfile].endpoint, + { nonNullable: true } + ); + presentationProfileControl = new FormControl(DefaultProfile, { + nonNullable: true, + }); private readonly _formBuilder = inject(FormBuilder); formGroup = this._formBuilder.group({ @@ -79,7 +100,9 @@ export class HomeComponent implements OnDestroy { selectedAttestations: AttestationSelection[] | null = null; selectedAttributes: { [id: string]: string[] } | null = {}; - selectedRequestUriMethod: 'get' | 'post' = 'get'; + selectedRequestUriMethod: RequestUriMethod = DefaultRequestUriMethod; + selectedProfile: Profile = DefaultProfile; + authorizationRequestUri: string = profileOptions[DefaultProfile].endpoint; initializationRequest: TransactionInitializationRequest | null = null; @@ -92,21 +115,23 @@ export class HomeComponent implements OnDestroy { handleSelectionChangedEvent($event: AttestationSelection[]) { this.selectedAttestations = $event; - + if (this.selectedAttestations) { - this.selectedAttestations.forEach(attestation => { + this.selectedAttestations.forEach((attestation) => { const attestationDef = SUPPORTED_ATTESTATIONS[attestation.type]; if (attestationDef) { const neverSelectivelyDisclosableAttributes = attestationDef.dataSet - .filter(dataElement => dataElement.selectivelyDisclosable === 'never') - .map(dataElement => dataElement.identifier); + .filter( + (dataElement) => dataElement.selectivelyDisclosable === 'never' + ) + .map((dataElement) => dataElement.identifier); if (neverSelectivelyDisclosableAttributes.length > 0) { - this.selectedAttributes![attestation.type] = neverSelectivelyDisclosableAttributes; + this.selectedAttributes![attestation.type] = + neverSelectivelyDisclosableAttributes; } } }); } - } handleAttributesCollectedEvent($event: AttributesSelectionEvent) { @@ -116,7 +141,8 @@ export class HomeComponent implements OnDestroy { this.initializationRequest = this.prepareInitializationRequest( this.selectedAttestations!, this.selectedAttributes, - this.selectedRequestUriMethod + this.selectedRequestUriMethod, + this.selectedProfile ); } else { this.selectedAttributes = null; @@ -124,13 +150,44 @@ export class HomeComponent implements OnDestroy { } handleRequestUriMethodChangedEvent($event: string) { - this.selectedRequestUriMethod = $event as 'get' | 'post'; + this.selectedRequestUriMethod = $event as RequestUriMethod; + + if (this.selectedAttestations && this.selectedAttributes) { + this.initializationRequest = this.prepareInitializationRequest( + this.selectedAttestations, + this.selectedAttributes, + this.selectedRequestUriMethod, + this.selectedProfile + ); + } else { + this.initializationRequest = null; + } + } + + handleProfileChangedEvent($event: string) { + this.selectedProfile = $event as Profile; + this.authorizationSchemeControl.setValue(profileOptions[this.selectedProfile].endpoint); + this.authorizationRequestUri = profileOptions[this.selectedProfile].endpoint; + if (this.selectedAttestations && this.selectedAttributes) { + this.initializationRequest = this.prepareInitializationRequest( + this.selectedAttestations, + this.selectedAttributes, + this.selectedRequestUriMethod, + this.selectedProfile + ); + } else { + this.initializationRequest = null; + } + } + handleAuthorizationSchemeChangedEvent($event: string) { + this.authorizationRequestUri = $event; if (this.selectedAttestations && this.selectedAttributes) { this.initializationRequest = this.prepareInitializationRequest( this.selectedAttestations, this.selectedAttributes, - this.selectedRequestUriMethod + this.selectedRequestUriMethod, + this.selectedProfile ); } else { this.initializationRequest = null; @@ -140,16 +197,20 @@ export class HomeComponent implements OnDestroy { private prepareInitializationRequest( selectedAttestations: AttestationSelection[], selectedAttributes: { [id: string]: string[] }, - selectedRequestUriMethod: 'get' | 'post' + selectedRequestUriMethod: RequestUriMethod, + selectedProfile: Profile ): TransactionInitializationRequest { - - const issuerChain = this.sessionStorageService.get(ISSUER_CHAIN) ?? undefined; + const issuerChain = + this.sessionStorageService.get(ISSUER_CHAIN) ?? undefined; return this.dcqlService.dcqlPresentationRequest( selectedAttestations, selectedAttributes, selectedRequestUriMethod, - issuerChain); + selectedProfile, + this.authorizationRequestUri, + issuerChain + ); } proceedToInvokeWallet() { @@ -166,21 +227,32 @@ export class HomeComponent implements OnDestroy { } attestationsSelected(): boolean { - return this.selectedAttestations !== null - && this.selectedAttestations - .filter((attestation) => - attestation.format !== null && attestation.attributeSelectionMethod !== null - ). - length > 0; + return ( + this.selectedAttestations !== null && + this.selectedAttestations.filter( + (attestation) => + attestation.format !== null && + attestation.attributeSelectionMethod !== null + ).length > 0 + ); } attributesSelected(): boolean { - return this.selectedAttestations !== null - && this.selectedAttestations.filter((attestation) => { - if(attestation.attributeSelectionMethod === AttributeSelectionMethod.SELECTABLE) { - return this.selectedAttributes?.[attestation.type]?.length?? 0 > 0; - } else return attestation.attributeSelectionMethod === AttributeSelectionMethod.ALL_ATTRIBUTES; - }).length === this.selectedAttestations.length; + return ( + this.selectedAttestations !== null && + this.selectedAttestations.filter((attestation) => { + if ( + attestation.attributeSelectionMethod === + AttributeSelectionMethod.SELECTABLE + ) { + return this.selectedAttributes?.[attestation.type]?.length ?? 0 > 0; + } else + return ( + attestation.attributeSelectionMethod === + AttributeSelectionMethod.ALL_ATTRIBUTES + ); + }).length === this.selectedAttestations.length + ); } canProceed() { diff --git a/src/app/shared/elements/input-scheme/error-state-matcher.ts b/src/app/shared/elements/input-scheme/error-state-matcher.ts deleted file mode 100644 index 6c92c595..00000000 --- a/src/app/shared/elements/input-scheme/error-state-matcher.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { FormControl, FormGroupDirective, NgForm } from '@angular/forms'; - -/** Error when invalid control is dirty, touched, or submitted. */ -export class ErrorStateMatcher implements ErrorStateMatcher { - isErrorState (control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { - const isSubmitted = form && form.submitted; - return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted)); - } -} diff --git a/src/app/shared/elements/input-scheme/input-scheme.component.html b/src/app/shared/elements/input-scheme/input-scheme.component.html deleted file mode 100644 index f01fb3eb..00000000 --- a/src/app/shared/elements/input-scheme/input-scheme.component.html +++ /dev/null @@ -1,26 +0,0 @@ -

Change default custom scheme

- - - -
- Current custom scheme value is:  {{ schemeValue }} -
- -
- - - Scheme - - Please enter a valid scheme - scheme is required - - -
- -
- - - - - diff --git a/src/app/shared/elements/input-scheme/input-scheme.component.scss b/src/app/shared/elements/input-scheme/input-scheme.component.scss deleted file mode 100644 index 8d23d4f6..00000000 --- a/src/app/shared/elements/input-scheme/input-scheme.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -@use '/src/template' as temp; - -:host { - margin: temp.$spaceBasic; - .example-full-width { - width: 100%; - } -} diff --git a/src/app/shared/elements/input-scheme/input-scheme.component.spec.ts b/src/app/shared/elements/input-scheme/input-scheme.component.spec.ts deleted file mode 100644 index 6d0a7ccc..00000000 --- a/src/app/shared/elements/input-scheme/input-scheme.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InputSchemeComponent } from './input-scheme.component'; -import { SharedModule } from '@shared/shared.module'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { MatInputModule } from '@angular/material/input'; -import { MatIconModule } from '@angular/material/icon'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; - -describe('InputSchemeComponent', () => { - let component: InputSchemeComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - InputSchemeComponent, - BrowserAnimationsModule, - NoopAnimationsModule, - MatExpansionModule, FormsModule, ReactiveFormsModule, MatInputModule, SharedModule, MatIconModule - ], - }) - .compileComponents(); - - fixture = TestBed.createComponent(InputSchemeComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/shared/elements/input-scheme/input-scheme.component.ts b/src/app/shared/elements/input-scheme/input-scheme.component.ts deleted file mode 100644 index 57d8d626..00000000 --- a/src/app/shared/elements/input-scheme/input-scheme.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Component, inject, OnInit } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { MatIconModule } from '@angular/material/icon'; -import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; -import { MatInputModule } from '@angular/material/input'; -import { ErrorStateMatcher } from './error-state-matcher'; -import { SharedModule } from '@shared/shared.module'; -import { LocalStorageService } from '@core/services/local-storage.service'; -import { DEFAULT_SCHEME, SCHEME } from '@core/constants/general'; -import {MatDialogModule} from "@angular/material/dialog"; -import {MatButtonModule} from "@angular/material/button"; - -@Component({ - selector: 'vc-input-scheme', - imports: [CommonModule, MatExpansionModule, FormsModule, ReactiveFormsModule, MatInputModule, SharedModule, MatIconModule, MatDialogModule, MatButtonModule], - templateUrl: './input-scheme.component.html', - styleUrls: ['./input-scheme.component.scss'] -}) -export class InputSchemeComponent implements OnInit { - - - readonly localStorageService: LocalStorageService = inject(LocalStorageService); - schemeControl = new FormControl('', [Validators.required]); - matcher = new ErrorStateMatcher(); - - schemeValue!: string; - - ngOnInit (): void { - this.schemeValue = this.localStorageService.get(SCHEME) || DEFAULT_SCHEME; - } - - save () { - const {value} = this.schemeControl; - if (value) { - this.localStorageService.set(SCHEME, value); - this.schemeValue = value; - } - } -} diff --git a/tsconfig.json b/tsconfig.json index a8dcc23e..12d70fec 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -48,7 +48,6 @@ }, "types": [ "jest", - "node_modules/@types", "node" ] },