mirror of
https://github.com/frappe/books.git
synced 2025-01-03 07:12:21 +00:00
fix: capture key errors in print container
- add error boundary component
This commit is contained in:
parent
fe6ef65d3d
commit
fe9f1f7e3a
14
src/components/ErrorBoundary.vue
Normal file
14
src/components/ErrorBoundary.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<slot></slot>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
export default defineComponent({
|
||||||
|
emits: ['error-captured'],
|
||||||
|
props: { propagate: { type: Boolean, default: true } },
|
||||||
|
errorCaptured(error) {
|
||||||
|
this.$emit('error-captured', error);
|
||||||
|
return this.propagate;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -4,14 +4,19 @@
|
|||||||
ref="scaledContainer"
|
ref="scaledContainer"
|
||||||
class="mx-auto shadow-lg border"
|
class="mx-auto shadow-lg border"
|
||||||
>
|
>
|
||||||
<!-- Template -->
|
<ErrorBoundary
|
||||||
<component
|
|
||||||
v-if="!error"
|
v-if="!error"
|
||||||
class="flex-1 bg-white"
|
@error-captured="handleErrorCaptured"
|
||||||
:doc="values.doc"
|
:propagate="false"
|
||||||
:print="values.print"
|
>
|
||||||
:is="templateComponent"
|
<!-- Template -->
|
||||||
/>
|
<component
|
||||||
|
class="flex-1 bg-white"
|
||||||
|
:doc="values.doc"
|
||||||
|
:print="values.print"
|
||||||
|
:is="templateComponent"
|
||||||
|
/>
|
||||||
|
</ErrorBoundary>
|
||||||
|
|
||||||
<!-- Compilation Error -->
|
<!-- Compilation Error -->
|
||||||
<div
|
<div
|
||||||
@ -26,11 +31,11 @@
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<h1 class="text-4xl font-bold text-red-500 p-4 border-b border-red-200">
|
<h1 class="text-4xl font-bold text-red-500 p-4 border-b border-red-200">
|
||||||
{{ t`Template Compilation Error` }}
|
{{ error.name }}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="px-4 font-semibold">{{ error.message }}</p>
|
<p class="px-4 font-semibold">{{ error.message }}</p>
|
||||||
<pre v-if="error.codeframe" class="px-4 text-xl text-gray-700">{{
|
<pre v-if="error.detail" class="px-4 text-xl text-gray-700">{{
|
||||||
error.codeframe
|
error.detail
|
||||||
}}</pre>
|
}}</pre>
|
||||||
</div>
|
</div>
|
||||||
</ScaledContainer>
|
</ScaledContainer>
|
||||||
@ -42,6 +47,7 @@ import {
|
|||||||
generateCodeFrame,
|
generateCodeFrame,
|
||||||
SourceLocation,
|
SourceLocation,
|
||||||
} from '@vue/compiler-dom';
|
} from '@vue/compiler-dom';
|
||||||
|
import ErrorBoundary from 'src/components/ErrorBoundary.vue';
|
||||||
import { getPathAndMakePDF } from 'src/utils/printTemplates';
|
import { getPathAndMakePDF } from 'src/utils/printTemplates';
|
||||||
import { PrintValues } from 'src/utils/types';
|
import { PrintValues } from 'src/utils/types';
|
||||||
import { defineComponent, PropType } from 'vue';
|
import { defineComponent, PropType } from 'vue';
|
||||||
@ -57,7 +63,7 @@ export const baseSafeTemplate = `<main class="h-full w-full bg-white">
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
return { error: null } as {
|
return { error: null } as {
|
||||||
error: null | { codeframe: string; message: string };
|
error: null | { name: string; message: string; detail?: string };
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@ -82,7 +88,7 @@ export default defineComponent({
|
|||||||
* Note: This is a hacky method to prevent
|
* Note: This is a hacky method to prevent
|
||||||
* broken templates from reaching the `<component />`
|
* broken templates from reaching the `<component />`
|
||||||
* element.
|
* element.
|
||||||
*
|
*
|
||||||
* It's required because the CompilerOptions doesn't
|
* It's required because the CompilerOptions doesn't
|
||||||
* have an option to capture the errors.
|
* have an option to capture the errors.
|
||||||
*
|
*
|
||||||
@ -100,9 +106,29 @@ export default defineComponent({
|
|||||||
onError: this.onError,
|
onError: this.onError,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleErrorCaptured(error: unknown) {
|
||||||
|
if (!(error instanceof Error)) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = error.message;
|
||||||
|
let name = error.name;
|
||||||
|
let detail = '';
|
||||||
|
if (name === 'TypeError' && message.includes('Cannot read')) {
|
||||||
|
name = this.t`Invalid Key Error`;
|
||||||
|
detail = this.t`Please check Key Hints for valid key names`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.error = { name, message, detail };
|
||||||
|
},
|
||||||
onError({ message, loc }: CompilerError) {
|
onError({ message, loc }: CompilerError) {
|
||||||
const codeframe = loc ? this.getCodeFrame(loc) : '';
|
const codeframe = loc ? this.getCodeFrame(loc) : '';
|
||||||
this.error = { codeframe, message };
|
|
||||||
|
this.error = {
|
||||||
|
name: this.t`Template Compilation Error`,
|
||||||
|
detail: codeframe,
|
||||||
|
message,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
getCodeFrame(loc: SourceLocation) {
|
getCodeFrame(loc: SourceLocation) {
|
||||||
return generateCodeFrame(this.template, loc.start.offset, loc.end.offset);
|
return generateCodeFrame(this.template, loc.start.offset, loc.end.offset);
|
||||||
@ -142,6 +168,6 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: { ScaledContainer },
|
components: { ScaledContainer, ErrorBoundary },
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -149,7 +149,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="templateChanged"
|
v-if="templateChanged"
|
||||||
class="flex gap-2 p-2 text-sm text-gray-600 items-center mt-auto"
|
class="flex gap-2 p-2 text-sm text-gray-600 items-center mt-auto border-t"
|
||||||
>
|
>
|
||||||
<ShortcutKeys :keys="applyChangesShortcut" :simple="true" />
|
<ShortcutKeys :keys="applyChangesShortcut" :simple="true" />
|
||||||
{{ t` to apply changes` }}
|
{{ t` to apply changes` }}
|
||||||
|
Loading…
Reference in New Issue
Block a user