From df1ebf7c65c343b7304ed5f7b56d8f39abbd690e Mon Sep 17 00:00:00 2001 From: Julien Fraichot Date: Mon, 6 May 2024 16:30:22 +0200 Subject: [PATCH 1/2] feat(Error): display error message when initial parsing proves blockcerts invalid --- src/actions/setErrorMessage.ts | 6 ++++-- src/actions/updateCertificateDefinition.ts | 4 ++-- src/blockcerts-verifier/BlockcertsVerifier.ts | 6 +++++- .../BlockcertsVerifierContainer.ts | 3 ++- .../atoms/ErrorMessage/ErrorMessage.ts | 18 +++++++++++++++--- src/domain/certificates/useCases/parse.ts | 4 +++- src/i18n/lang/en.ts | 1 + src/i18n/lang/es.ts | 1 + src/i18n/lang/fr.ts | 1 + src/i18n/lang/it.ts | 1 + src/i18n/lang/ja.ts | 1 + src/i18n/lang/mt.ts | 1 + src/reducers/setErrorMessage.ts | 5 +++-- src/selectors/error.ts | 3 +++ src/store/getInitialState.ts | 1 + 15 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/actions/setErrorMessage.ts b/src/actions/setErrorMessage.ts index eae1507a..ef3a2696 100644 --- a/src/actions/setErrorMessage.ts +++ b/src/actions/setErrorMessage.ts @@ -3,13 +3,15 @@ import type { Action } from './action'; export interface SetErrorMessageActionPayload { errorMessage: string; + additionalErrorInfo?: string; } -export default function setErrorMessage (errorMessage: string): Action { +export default function setErrorMessage (errorMessage: string, additionalErrorInfo?: string): Action { return { type: ACTIONS.SET_ERROR_MESSAGE, payload: { - errorMessage + errorMessage, + additionalErrorInfo } }; } diff --git a/src/actions/updateCertificateDefinition.ts b/src/actions/updateCertificateDefinition.ts index 5ecfd613..d3520da7 100644 --- a/src/actions/updateCertificateDefinition.ts +++ b/src/actions/updateCertificateDefinition.ts @@ -23,9 +23,9 @@ export default function updateCertificateDefinition (definition: Blockcerts): Th explorerAPIs: getExplorerAPIs(state), didResolverUrl: getDidResolverUrl(state) }; - const { certificateDefinition, errorMessage } = await domain.certificates.parse(definition, options); + const { certificateDefinition, errorMessage, additionalErrorInfo } = await domain.certificates.parse(definition, options); - dispatch(setErrorMessage(errorMessage)); + dispatch(setErrorMessage(errorMessage, additionalErrorInfo)); dispatch({ type: ACTIONS.UPDATE_CERTIFICATE_DEFINITION, diff --git a/src/blockcerts-verifier/BlockcertsVerifier.ts b/src/blockcerts-verifier/BlockcertsVerifier.ts index 4a0c3a26..0f465fd3 100644 --- a/src/blockcerts-verifier/BlockcertsVerifier.ts +++ b/src/blockcerts-verifier/BlockcertsVerifier.ts @@ -23,6 +23,7 @@ export interface IBlockcertsVerifierProps { onLoad?: (IBlockcertsVerifierProps) => any; // the error message to be displayed, if any errorMessage?: string; + additionalErrorInfo?: string; // boolean to check if a certificate has been loaded into the component hasCertificate?: boolean; // flag to disable foreground verification modal (background verification still occurs) @@ -65,6 +66,7 @@ class BlockcertsVerifier extends LitElement { return { onLoad: Function as any, errorMessage: String as any, + additionalErrorInfo: String as any, hasCertificate: Boolean as any, ...APICamelCase }; @@ -112,7 +114,7 @@ class BlockcertsVerifier extends LitElement {
- ${ErrorMessage(_props.errorMessage, true)} + ${ErrorMessage(_props.errorMessage, _props.additionalErrorInfo, true)} ${this.renderCertificate(_props)} @@ -131,6 +133,7 @@ window.customElements.define('buv-raw', BlockcertsVerifier); interface BUVWrapperProps extends IBlockcertsVerifierAPI { onLoad?: (IBlockcertsVerifierProps) => any; errorMessage?: string; + additionalErrorInfo?: string; hasCertificate?: boolean; } @@ -141,6 +144,7 @@ function BUVWrapper (props: BUVWrapperProps = {}): TemplateResult { src='${props.src}' onLoad='${props.onLoad}' errorMessage='${props.errorMessage}' + additionalErrorInfo='${props.additionalErrorInfo}' hasCertificate='${props.hasCertificate}' disableAutoVerify='${props['disable-auto-verify']}' disableVerify='${props['disable-verify']}' diff --git a/src/blockcerts-verifier/BlockcertsVerifierContainer.ts b/src/blockcerts-verifier/BlockcertsVerifierContainer.ts index c442d1f0..89965347 100644 --- a/src/blockcerts-verifier/BlockcertsVerifierContainer.ts +++ b/src/blockcerts-verifier/BlockcertsVerifierContainer.ts @@ -1,7 +1,7 @@ import connector from '../store/connector'; import initialize from '../actions/initialize'; import { BlockcertsVerifier, SourceComponent } from './BlockcertsVerifier'; -import { getErrorMessage } from '../selectors/error'; +import { getAdditionalErrorInfo, getErrorMessage } from '../selectors/error'; import { APIKeys } from '../models/API'; import { getCertificateDefinition } from '../selectors/certificate'; import type { BlockcertsVerifierState } from '../store/getInitialState'; @@ -14,6 +14,7 @@ export const mapDispatchToProps = { export const mapStateToProps = (state: BlockcertsVerifierState): any => { return { errorMessage: getErrorMessage(state), + additionalErrorInfo: getAdditionalErrorInfo(state), hasCertificate: !!getCertificateDefinition(state) }; }; diff --git a/src/components/atoms/ErrorMessage/ErrorMessage.ts b/src/components/atoms/ErrorMessage/ErrorMessage.ts index c0655e57..941a4382 100644 --- a/src/components/atoms/ErrorMessage/ErrorMessage.ts +++ b/src/components/atoms/ErrorMessage/ErrorMessage.ts @@ -14,7 +14,7 @@ function translate (message: string): string { return message; } -export default function ErrorMessage (message: string, solidBackground = false): TemplateResult { +export default function ErrorMessage (message: string, additionalErrorInfo: string, solidBackground = false): TemplateResult { if (message == null) { return null; } @@ -27,8 +27,20 @@ export default function ErrorMessage (message: string, solidBackground = false): return html` ${CSS} -

+

+

${getText('errors.errorLabel')} ${translate(message)} -

`; +

+ ${additionalErrorInfo + ? html`

+ ${getText('errors.additionalErrorInfoLabel')} +
+
+ ${additionalErrorInfo} +

` + : '' + } +
+ `; } diff --git a/src/domain/certificates/useCases/parse.ts b/src/domain/certificates/useCases/parse.ts index 1a5fb781..9712e13e 100644 --- a/src/domain/certificates/useCases/parse.ts +++ b/src/domain/certificates/useCases/parse.ts @@ -9,6 +9,7 @@ import type { export interface ICertificateObject { certificateDefinition: Certificate | null; errorMessage?: string; + additionalErrorInfo?: string; } export default async function parse (definition: Blockcerts, options: CertificateOptions = {}): Promise { @@ -35,7 +36,8 @@ export default async function parse (definition: Blockcerts, options: Certificat console.error(e); return { certificateDefinition: null, - errorMessage: 'errors.invalidBlockcerts' + errorMessage: 'errors.invalidBlockcerts', + additionalErrorInfo: e.message }; } } diff --git a/src/i18n/lang/en.ts b/src/i18n/lang/en.ts index 9562b4d1..776873cc 100644 --- a/src/i18n/lang/en.ts +++ b/src/i18n/lang/en.ts @@ -1,6 +1,7 @@ export default { errors: { errorLabel: 'Error', + additionalErrorInfoLabel: 'The following error occurred:', invalidBlockcerts: 'Not a valid Blockcerts credential. Please check with the issuer or recipient that has provided this credential.', invalidBlockcertsUrl: 'Not a valid credential URL.', invalidFormatDragAndDrop: 'Only JSON files are accepted', diff --git a/src/i18n/lang/es.ts b/src/i18n/lang/es.ts index dee74767..1bb29241 100644 --- a/src/i18n/lang/es.ts +++ b/src/i18n/lang/es.ts @@ -1,6 +1,7 @@ export default { errors: { errorLabel: 'Error', + additionalErrorInfoLabel: 'El siguiente error ocurrió:', invalidBlockcerts: 'No es una credencial válida de Blockcerts. Verifique con el emisor o el destinatario que ha proporcionado esta credencial.', invalidBlockcertsUrl: 'No es URL de certificado valido.', invalidFormatDragAndDrop: 'Solo se aceptan archivos JSON', diff --git a/src/i18n/lang/fr.ts b/src/i18n/lang/fr.ts index 78181df6..5e2c2912 100644 --- a/src/i18n/lang/fr.ts +++ b/src/i18n/lang/fr.ts @@ -1,6 +1,7 @@ export default { errors: { errorLabel: 'Erreur', + additionalErrorInfoLabel: 'Cette erreur s\'est produite :', invalidBlockcerts: 'Ceci n\'est pas un certificat Blockcerts valide. Veuillez s\'il vous plaît contrôler avec l\'organisme émetteur ou le récipiendaire de ce certificat.', invalidBlockcertsUrl: 'Ceci n\'est pas une URL de certificat valide.', invalidFormatDragAndDrop: 'Seul le format JSON est accepté', diff --git a/src/i18n/lang/it.ts b/src/i18n/lang/it.ts index 70195f60..5e23deb2 100644 --- a/src/i18n/lang/it.ts +++ b/src/i18n/lang/it.ts @@ -1,6 +1,7 @@ export default { errors: { errorLabel: 'Errore', + additionalErrorInfoLabel: 'Si è verificato il seguente errore:', invalidBlockcerts: 'Non è una definizione valida di Blockcerts.', invalidBlockcertsUrl: 'Non è un URL di certificato valido.', invalidFormatDragAndDrop: 'Sono accettati solo file JSON', diff --git a/src/i18n/lang/ja.ts b/src/i18n/lang/ja.ts index c7427793..eefa707e 100644 --- a/src/i18n/lang/ja.ts +++ b/src/i18n/lang/ja.ts @@ -1,6 +1,7 @@ export default { errors: { errorLabel: 'エラー', + additionalErrorInfoLabel: '次のエラーが発生しました:', invalidBlockcerts: 'この証明書は有効なブロックサーツ証明書ではありません。発行者、もしくはこの証明書を提供した取得者にお問合せください。', invalidBlockcertsUrl: '有効な証明書URLではありません。', invalidFormatDragAndDrop: 'JSONファイルしか受理できません', diff --git a/src/i18n/lang/mt.ts b/src/i18n/lang/mt.ts index 8b9b1cc1..7b74f8e6 100644 --- a/src/i18n/lang/mt.ts +++ b/src/i18n/lang/mt.ts @@ -1,6 +1,7 @@ export default { errors: { errorLabel: 'Żball', + additionalErrorInfoLabel: 'L-error li ġie jmiss:', invalidBlockcerts: 'Mhux kredenzjal validu ta \'Blockcerts\'. Jekk jogħġbok iċċekkja ma \'l-emittent jew ir-riċevitur li pprovda din il-kredenzjali.', invalidBlockcertsUrl: 'Il-URL taċ-ċertifikat mhuwiex validu', invalidFormatDragAndDrop: 'Only JSON files are accepted', diff --git a/src/reducers/setErrorMessage.ts b/src/reducers/setErrorMessage.ts index 694e11b7..758e9089 100644 --- a/src/reducers/setErrorMessage.ts +++ b/src/reducers/setErrorMessage.ts @@ -3,10 +3,11 @@ import type { Action } from '../actions/action'; import type { SetErrorMessageActionPayload } from '../actions/setErrorMessage'; export default function setErrorMessage (state: BlockcertsVerifierState, action: Action): BlockcertsVerifierState { - const { errorMessage } = action.payload; + const { errorMessage, additionalErrorInfo } = action.payload; return { ...state, - errorMessage + errorMessage, + additionalErrorInfo }; } diff --git a/src/selectors/error.ts b/src/selectors/error.ts index 1f77c382..825b84dc 100644 --- a/src/selectors/error.ts +++ b/src/selectors/error.ts @@ -3,3 +3,6 @@ import type { BlockcertsVerifierState } from '../store/getInitialState'; export function getErrorMessage (state: BlockcertsVerifierState): string { return state.errorMessage; } +export function getAdditionalErrorInfo (state: BlockcertsVerifierState): string { + return state.additionalErrorInfo; +} diff --git a/src/store/getInitialState.ts b/src/store/getInitialState.ts index 3ea6f332..e9dd15bc 100644 --- a/src/store/getInitialState.ts +++ b/src/store/getInitialState.ts @@ -32,6 +32,7 @@ export interface BlockcertsVerifierState { explorerAPIs?: ExplorerAPI[]; didResolverUrl?: string; errorMessage?: string; + additionalErrorInfo?: string; } export default function getInitialState (apiConfiguration = {}): BlockcertsVerifierState { From 54953c55005317ec15f2260252bf7d9a66d6c203 Mon Sep 17 00:00:00 2001 From: Julien Fraichot Date: Mon, 6 May 2024 20:18:48 +0200 Subject: [PATCH 2/2] fix(ErrorMessage): make additionalErrorInfo optional --- src/components/atoms/ErrorMessage/ErrorMessage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/atoms/ErrorMessage/ErrorMessage.ts b/src/components/atoms/ErrorMessage/ErrorMessage.ts index 941a4382..4d473e4f 100644 --- a/src/components/atoms/ErrorMessage/ErrorMessage.ts +++ b/src/components/atoms/ErrorMessage/ErrorMessage.ts @@ -14,7 +14,7 @@ function translate (message: string): string { return message; } -export default function ErrorMessage (message: string, additionalErrorInfo: string, solidBackground = false): TemplateResult { +export default function ErrorMessage (message: string, additionalErrorInfo: string = '', solidBackground = false): TemplateResult { if (message == null) { return null; }