Merge branch 'more-fixes' into shigusegubu-themes3
This commit is contained in:
commit
e10eccea41
9 changed files with 254 additions and 2 deletions
|
|
@ -4,6 +4,7 @@ import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
import DesktopNav from 'src/components/desktop_nav/desktop_nav.vue'
|
import DesktopNav from 'src/components/desktop_nav/desktop_nav.vue'
|
||||||
import FeaturesPanel from 'src/components/features_panel/features_panel.vue'
|
import FeaturesPanel from 'src/components/features_panel/features_panel.vue'
|
||||||
|
import GlobalError from 'src/components/global_error/global_error.vue'
|
||||||
import GlobalNoticeList from 'src/components/global_notice_list/global_notice_list.vue'
|
import GlobalNoticeList from 'src/components/global_notice_list/global_notice_list.vue'
|
||||||
import InstanceSpecificPanel from 'src/components/instance_specific_panel/instance_specific_panel.vue'
|
import InstanceSpecificPanel from 'src/components/instance_specific_panel/instance_specific_panel.vue'
|
||||||
import MobileNav from 'src/components/mobile_nav/mobile_nav.vue'
|
import MobileNav from 'src/components/mobile_nav/mobile_nav.vue'
|
||||||
|
|
@ -68,6 +69,7 @@ export default {
|
||||||
() =>
|
() =>
|
||||||
import('src/components/status_history_modal/status_history_modal.vue'),
|
import('src/components/status_history_modal/status_history_modal.vue'),
|
||||||
),
|
),
|
||||||
|
GlobalError,
|
||||||
GlobalNoticeList,
|
GlobalNoticeList,
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
|
|
||||||
13
src/App.scss
13
src/App.scss
|
|
@ -144,6 +144,19 @@ h4 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background: var(--bg);
|
||||||
|
border: 1px solid var(--fg);
|
||||||
|
border-radius: var(--roundness);
|
||||||
|
margin: 0.2em;
|
||||||
|
padding: 0 0.2em;
|
||||||
|
|
||||||
|
&.pre {
|
||||||
|
white-space: pre;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.iconLetter {
|
.iconLetter {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@
|
||||||
<StatusHistoryModal v-if="editingAvailable" />
|
<StatusHistoryModal v-if="editingAvailable" />
|
||||||
<SettingsModal :class="layoutModalClass" />
|
<SettingsModal :class="layoutModalClass" />
|
||||||
<UpdateNotification />
|
<UpdateNotification />
|
||||||
|
<GlobalError />
|
||||||
<GlobalNoticeList />
|
<GlobalNoticeList />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
36
src/components/error_modal/error_modal.js
Normal file
36
src/components/error_modal/error_modal.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import DialogModal from 'src/components/dialog_modal/dialog_modal.vue'
|
||||||
|
|
||||||
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
import { faCircleXmark } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
library.add(faCircleXmark)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component emits the following events:
|
||||||
|
* cancelled, emitted when the action should not be performed;
|
||||||
|
* accepted, emitted when the action should be performed;
|
||||||
|
*
|
||||||
|
* The caller should close this dialog after receiving any of the two events.
|
||||||
|
*/
|
||||||
|
const ErrorModal = {
|
||||||
|
components: {
|
||||||
|
DialogModal,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
clearText: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
recoverText: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
type: Error,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['clear', 'recover']
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorModal
|
||||||
100
src/components/error_modal/error_modal.vue
Normal file
100
src/components/error_modal/error_modal.vue
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
<template>
|
||||||
|
<DialogModal
|
||||||
|
v-body-scroll-lock="true"
|
||||||
|
class="error-modal"
|
||||||
|
@cancel="onCancel"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span v-text="title ?? $t('general.generic_error')" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<FAIcon
|
||||||
|
class="error-icon"
|
||||||
|
icon="circle-xmark"
|
||||||
|
size="3x"
|
||||||
|
fixed-width
|
||||||
|
/>
|
||||||
|
<div class="text">
|
||||||
|
<slot>
|
||||||
|
<p>
|
||||||
|
<strong><code v-text="error.name" /></strong>
|
||||||
|
{{ ' - ' }}
|
||||||
|
<span v-text="error.message" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary>{{ $t('general.generic_error_details') }}</summary>
|
||||||
|
<code class="stack pre" v-text="error.stack" />
|
||||||
|
</details>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="below">
|
||||||
|
<slot name="below" />
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<slot name="footerLeft" />
|
||||||
|
|
||||||
|
<button
|
||||||
|
v-if="recoverText"
|
||||||
|
class="btn button-default"
|
||||||
|
@click.prevent="$emit('recover')"
|
||||||
|
v-text="recoverText"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
@click.prevent="$emit('clear')"
|
||||||
|
v-text="clearText ?? $t('general.close')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</DialogModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./error_modal.js"></script>
|
||||||
|
<style lang="scss">
|
||||||
|
.error-modal {
|
||||||
|
.error-icon {
|
||||||
|
margin-left: 0.75rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: left;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0.75em;
|
||||||
|
margin-bottom: 0.75em;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack {
|
||||||
|
margin: 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.below:not(:empty) {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
max-width: 50ch;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
margin-right: 3.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
52
src/components/global_error/global_error.js
Normal file
52
src/components/global_error/global_error.js
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
import ErrorModal from 'src/components/error_modal/error_modal.vue'
|
||||||
|
|
||||||
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
|
|
||||||
|
import { mapState, mapActions } from 'pinia'
|
||||||
|
|
||||||
|
const GlobalError = {
|
||||||
|
components: {
|
||||||
|
ErrorModal,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
title() {
|
||||||
|
if (this.globalError == null) return null
|
||||||
|
return this.globalError.title && this.$t(this.globalError.title)
|
||||||
|
},
|
||||||
|
content() {
|
||||||
|
if (this.globalError == null) return null
|
||||||
|
if (this.globalError.content) {
|
||||||
|
return this.$t(this.globalError.content, [this.globalError.error])
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
details() {
|
||||||
|
if (this.globalError == null) return null
|
||||||
|
if (this.globalError.error != null) {
|
||||||
|
return this.globalError.error.toString() + '\n\n' + this.globalError.error.stack
|
||||||
|
} else {
|
||||||
|
return this.globalError.details
|
||||||
|
}
|
||||||
|
},
|
||||||
|
recoverText() {
|
||||||
|
if (this.globalError == null) return null
|
||||||
|
if (this.globalError.recoverText == null) return null
|
||||||
|
return this.$t(this.globalError.recoverText)
|
||||||
|
},
|
||||||
|
...mapState(useInterfaceStore, ['globalError']),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clear() {
|
||||||
|
this.globalError.clear?.()
|
||||||
|
this.clearGlobalError()
|
||||||
|
},
|
||||||
|
recover() {
|
||||||
|
this.globalError.recover?.()
|
||||||
|
this.clearGlobalError()
|
||||||
|
},
|
||||||
|
...mapActions(useInterfaceStore, ['clearGlobalError']),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GlobalError
|
||||||
23
src/components/global_error/global_error.vue
Normal file
23
src/components/global_error/global_error.vue
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<template>
|
||||||
|
<teleport to="#modal">
|
||||||
|
<ErrorModal
|
||||||
|
v-if="globalError"
|
||||||
|
:error="globalError.error"
|
||||||
|
:title="title"
|
||||||
|
:recover-text="recoverText"
|
||||||
|
@recover="recover"
|
||||||
|
@clear="clear"
|
||||||
|
>
|
||||||
|
<template v-if="content">
|
||||||
|
<p>{{ content }}</p>
|
||||||
|
|
||||||
|
<details v-if="details">
|
||||||
|
<summary>{{ $t('general.generic_error_details') }}</summary>
|
||||||
|
<code class="stack pre" v-text="details" />
|
||||||
|
</details>
|
||||||
|
</template>
|
||||||
|
</ErrorModal>
|
||||||
|
</teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./global_error.js"></script>
|
||||||
|
|
@ -90,7 +90,11 @@
|
||||||
"loading": "Loading…",
|
"loading": "Loading…",
|
||||||
"generic_error": "An error occured",
|
"generic_error": "An error occured",
|
||||||
"generic_error_message": "An error occured: {0}",
|
"generic_error_message": "An error occured: {0}",
|
||||||
|
"generic_error_details": "Technical info:",
|
||||||
"error_retry": "Please try again",
|
"error_retry": "Please try again",
|
||||||
|
"refresh_required": "Refresh required",
|
||||||
|
"refresh_required_content": "Frontend was updated on server, you need to refresh the page.",
|
||||||
|
"refresh_required_refresh": "Refresh",
|
||||||
"retry": "Try again",
|
"retry": "Try again",
|
||||||
"optional": "optional",
|
"optional": "optional",
|
||||||
"show_more": "Show more",
|
"show_more": "Show more",
|
||||||
|
|
|
||||||
|
|
@ -177,8 +177,29 @@ export const useInterfaceStore = defineStore('interface', {
|
||||||
removeGlobalNotice(notice) {
|
removeGlobalNotice(notice) {
|
||||||
this.globalNotices = this.globalNotices.filter((n) => n !== notice)
|
this.globalNotices = this.globalNotices.filter((n) => n !== notice)
|
||||||
},
|
},
|
||||||
setGlobalError(data) {
|
setGlobalError({ error, instance, info }) {
|
||||||
this.globalError = data
|
console.log(info)
|
||||||
|
switch (info) {
|
||||||
|
case 'https://vuejs.org/error-reference/#runtime-13': {
|
||||||
|
this.globalError = {
|
||||||
|
title: 'general.refresh_required',
|
||||||
|
content: 'general.refresh_required_content',
|
||||||
|
// `true` disables cache on Firefox (non-standard)
|
||||||
|
recover: () => window.location.reload(true),
|
||||||
|
recoverText: 'general.refresh_required_refresh',
|
||||||
|
error,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
this.globalError = { error }
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(this.globalError)
|
||||||
|
},
|
||||||
|
clearGlobalError() {
|
||||||
|
this.globalError = null;
|
||||||
},
|
},
|
||||||
pushGlobalNotice({
|
pushGlobalNotice({
|
||||||
messageKey,
|
messageKey,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue