Add a way to display error dialogs

This commit is contained in:
Jonatan Heyman 2024-07-24 12:31:19 +02:00
parent 49dd273b92
commit c14c700791
9 changed files with 225 additions and 27 deletions

View File

@ -50,6 +50,7 @@ Menu.setApplicationMenu(menu)
export let win: BrowserWindow | null = null
let tray: Tray | null = null;
let initErrors: string[] = []
// Here, you can also use other preload
const preload = join(__dirname, '../preload/index.js')
const url = process.env.VITE_DEV_SERVER_URL
@ -350,6 +351,9 @@ ipcMain.handle('dark-mode:get', () => nativeTheme.themeSource)
// load buffer on app start
loadBuffer()
ipcMain.handle("getInitErrors", () => {
return initErrors
})
ipcMain.handle('settings:set', async (event, settings) => {

View File

@ -103,7 +103,11 @@ contextBridge.exposeInMainWorld("heynote", {
async getVersion() {
return await ipcRenderer.invoke("getVersion")
}
},
async getInitErrors() {
return await ipcRenderer.invoke("getInitErrors")
},
})

88
package-lock.json generated
View File

@ -10,6 +10,7 @@
"license": "Commons Clause MIT",
"dependencies": {
"electron-log": "^5.0.1",
"pinia": "^2.1.7",
"semver": "^7.6.3"
},
"devDependencies": {
@ -242,7 +243,6 @@
"version": "7.23.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz",
"integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
},
@ -1013,8 +1013,7 @@
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@lezer/common": {
"version": "1.2.1",
@ -1732,7 +1731,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.11.tgz",
"integrity": "sha512-h97/TGWBilnLuRaj58sxNrsUU66fwdRKLOLQ9N/5iNDfp+DZhYH9Obhe0bXxhedl8fjAgpRANpiZfbgWyruQ0w==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.23.5",
"@vue/shared": "3.3.11",
@ -1744,7 +1742,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.11.tgz",
"integrity": "sha512-zoAiUIqSKqAJ81WhfPXYmFGwDRuO+loqLxvXmfUdR5fOitPoUiIeFI9cTTyv9MU5O1+ZZglJVTusWzy+wfk5hw==",
"dev": true,
"dependencies": {
"@vue/compiler-core": "3.3.11",
"@vue/shared": "3.3.11"
@ -1754,7 +1751,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.11.tgz",
"integrity": "sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.23.5",
"@vue/compiler-core": "3.3.11",
@ -1772,12 +1768,16 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.11.tgz",
"integrity": "sha512-Zd66ZwMvndxRTgVPdo+muV4Rv9n9DwQ4SSgWWKWkPFebHQfVYRrVjeygmmDmPewsHyznCNvJ2P2d6iOOhdv8Qg==",
"dev": true,
"dependencies": {
"@vue/compiler-dom": "3.3.11",
"@vue/shared": "3.3.11"
}
},
"node_modules/@vue/devtools-api": {
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.3.tgz",
"integrity": "sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw=="
},
"node_modules/@vue/language-core": {
"version": "1.8.25",
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.25.tgz",
@ -1831,7 +1831,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.11.tgz",
"integrity": "sha512-D5tcw091f0nuu+hXq5XANofD0OXnBmaRqMYl5B3fCR+mX+cXJIGNw/VNawBqkjLNWETrFW0i+xH9NvDbTPVh7g==",
"dev": true,
"dependencies": {
"@vue/shared": "3.3.11"
}
@ -1840,7 +1839,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.11.tgz",
"integrity": "sha512-fPGjH0wqJo68A0wQ1k158utDq/cRyZNlFoxGwNScE28aUFOKFEnCBsvyD8jHn+0kd0UKVpuGuaZEQ6r9FJRqCg==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.23.5",
"@vue/compiler-core": "3.3.11",
@ -1853,7 +1851,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.11.tgz",
"integrity": "sha512-g9ztHGwEbS5RyWaOpXuyIVFTschclnwhqEbdy5AwGhYOgc7m/q3NFwr50MirZwTTzX55JY8pSkeib9BX04NIpw==",
"dev": true,
"dependencies": {
"@vue/reactivity": "3.3.11",
"@vue/shared": "3.3.11"
@ -1863,7 +1860,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.11.tgz",
"integrity": "sha512-OlhtV1PVpbgk+I2zl+Y5rQtDNcCDs12rsRg71XwaA2/Rbllw6mBLMi57VOn8G0AjOJ4Mdb4k56V37+g8ukShpQ==",
"dev": true,
"dependencies": {
"@vue/runtime-core": "3.3.11",
"@vue/shared": "3.3.11",
@ -1874,7 +1870,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.11.tgz",
"integrity": "sha512-AIWk0VwwxCAm4wqtJyxBylRTXSy1wCLOKbWxHaHiu14wjsNYtiRCSgVuqEPVuDpErOlRdNnuRgipQfXRLjLN5A==",
"dev": true,
"dependencies": {
"@vue/compiler-ssr": "3.3.11",
"@vue/shared": "3.3.11"
@ -1886,8 +1881,7 @@
"node_modules/@vue/shared": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.11.tgz",
"integrity": "sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==",
"dev": true
"integrity": "sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw=="
},
"node_modules/@xmldom/xmldom": {
"version": "0.8.10",
@ -2756,8 +2750,7 @@
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"dev": true
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/de-indent": {
"version": "1.0.2",
@ -3570,8 +3563,7 @@
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"node_modules/extract-zip": {
"version": "2.0.1",
@ -4444,7 +4436,6 @@
"version": "0.30.5",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
"integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
@ -4611,7 +4602,6 @@
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"dev": true,
"funding": [
{
"type": "github",
@ -4846,8 +4836,7 @@
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"dev": true
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@ -4861,6 +4850,56 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pinia": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz",
"integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==",
"dependencies": {
"@vue/devtools-api": "^6.5.0",
"vue-demi": ">=0.14.5"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"@vue/composition-api": "^1.4.0",
"typescript": ">=4.4.4",
"vue": "^2.6.14 || ^3.3.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/vue-demi": {
"version": "0.14.8",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz",
"integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/pkg-up": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
@ -4935,7 +4974,6 @@
"version": "8.4.32",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
"integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
"dev": true,
"funding": [
{
"type": "opencollective",
@ -5443,7 +5481,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -5749,7 +5786,7 @@
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
"devOptional": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@ -6295,7 +6332,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.11.tgz",
"integrity": "sha512-d4oBctG92CRO1cQfVBZp6WJAs0n8AK4Xf5fNjQCBeKCvMI1efGQ5E3Alt1slFJS9fZuPcFoiAiqFvQlv1X7t/w==",
"dev": true,
"dependencies": {
"@vue/compiler-dom": "3.3.11",
"@vue/compiler-sfc": "3.3.11",

View File

@ -79,6 +79,7 @@
},
"dependencies": {
"electron-log": "^5.0.1",
"pinia": "^2.1.7",
"semver": "^7.6.3"
}
}

View File

@ -0,0 +1,114 @@
<script>
import { mapState, mapActions } from 'pinia'
import { useErrorStore } from "../stores/error-store"
export default {
computed: {
...mapState(useErrorStore, ["errors"]),
},
methods: {
...mapActions(useErrorStore, ["popError"]),
pluralize(count, singular, plural) {
return count === 1 ? singular : plural
},
},
}
</script>
<template>
<div
class="error-messages"
v-if="errors && errors.length > 0"
>
<div class="dialog">
<div class="dialog-content">
<h1>Error</h1>
<p>
{{ errors[0] }}
</p>
</div>
<div class="bottom-bar">
<div style="flex-grow:1;">
<div
v-if="errors.length > 1"
class="count"
>
{{ errors.length-1 }} more {{ pluralize(errors.length-1, "error", "errors") }}
</div>
</div>
<button
@click="popError"
class="close"
>Close</button>
</div>
</div>
<div class="shader"></div>
</div>
</template>
<style lang="sass" scoped>
.error-messages
position: fixed
top: 0
left: 0
bottom: 0
right: 0
.shader
z-index: 1
position: absolute
top: 0
left: 0
bottom: 0
right: 0
background: rgba(0, 0, 0, 0.5)
.dialog
box-sizing: border-box
z-index: 2
position: absolute
left: 50%
top: 50%
transform: translate(-50%, -50%)
width: 440px
height: 200px
max-width: 100%
max-height: 100%
display: flex
flex-direction: column
border-radius: 5px
background: #fff
color: #333
box-shadow: 0 0 25px rgba(0, 0, 0, 0.2)
overflow-y: auto
&:active, &:selected, &:focus, &:focus-visible
border: none
outline: none
+dark-mode
background: #333
color: #eee
box-shadow: 0 0 25px rgba(0, 0, 0, 0.3)
.dialog-content
flex-grow: 1
padding: 30px
h1
font-size: 14px
font-weight: 700
display: block
margin-bottom: 1em
.bottom-bar
border-radius: 0 0 5px 5px
background: #eee
padding: 10px 20px
display: flex
align-items: center
+dark-mode
background: #222
.close
height: 28px
</style>

View File

@ -1,17 +1,27 @@
import './css/application.sass'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './components/App.vue'
import { loadCurrencies } from './currency'
import { useErrorStore } from './stores/error-store'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app').$nextTick(() => {
// hide loading screen
postMessage({ payload: 'removeLoading' }, '*')
})
const errorStore = useErrorStore()
window.heynote.getInitErrors().then((errors) => {
errors.forEach((e) => errorStore.addError(e))
})

21
src/stores/error-store.js Normal file
View File

@ -0,0 +1,21 @@
import { defineStore } from 'pinia'
export const useErrorStore = defineStore("errors", {
state: () => ({
errors: [],
}),
actions: {
setErrors(errors) {
this.errors = errors
},
addError(error) {
this.errors.push(error)
},
popError() {
this.errors.splice(0, 1)
},
},
})

View File

@ -152,6 +152,10 @@ const Heynote = {
async getVersion() {
return __APP_VERSION__ + " (" + __GIT_HASH__ + ")"
},
async getInitErrors() {
},
}
export { Heynote, ipcRenderer}

View File

@ -1,10 +1,14 @@
import '../src/css/application.sass'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from '../src/components/App.vue'
import { loadCurrencies } from '../src/currency'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
//console.log("test:", app.hej.test)