Skip to content

Commit b1d3ac7

Browse files
committed
show error messages in ui for nonexistent context, table, view
Signed-off-by: silverkszlo <paguaro@posteo.eu>
1 parent 0a87b4e commit b1d3ac7

3 files changed

Lines changed: 228 additions & 56 deletions

File tree

‎src/pages/Context.vue‎

Lines changed: 83 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55
<template>
66
<div class="row">
77
<div v-if="loading" class="icon-loading" />
8-
<div v-if="!loading && context">
8+
9+
<div v-else-if="errorMessage" class="error-container">
10+
<IconTables :size="64" style="margin-bottom: 1rem;" />
11+
<p>{{ errorMessage }}</p>
12+
</div>
13+
14+
<div v-else>
915
<div class="content context">
1016
<div class="row first-row">
1117
<h1 class="context__title" data-cy="context-title">
@@ -50,11 +56,13 @@ import exportTableMixin from '../shared/components/ncTable/mixins/exportTableMix
5056
import svgHelper from '../shared/components/ncIconPicker/mixins/svgHelper.js'
5157
import { useTablesStore } from '../store/store.js'
5258
import { useDataStore } from '../store/data.js'
59+
import IconTables from '../shared/assets/icons/IconTables.vue'
5360
5461
export default {
5562
components: {
5663
MainModals,
5764
NcIconSvgWrapper,
65+
IconTables,
5866
TableWrapper,
5967
CustomView,
6068
},
@@ -73,6 +81,7 @@ export default {
7381
viewSetting: {},
7482
context: null,
7583
contextResources: [],
84+
errorMessage: null,
7685
}
7786
},
7887
@@ -146,49 +155,66 @@ export default {
146155
return
147156
}
148157
this.loading = true
149-
this.icon = await this.getContextIcon(this.activeContext.iconName)
150158
this.contextResources = []
151-
await this.loadContext({ id: this.activeContextId })
152-
const index = this.contexts.findIndex(c => parseInt(c.id) === parseInt(this.activeContextId))
153-
this.context = this.contexts[index]
154159
155-
if (this.context && this.context.nodes) {
156-
for (const [, node] of Object.entries(this.context.nodes)) {
157-
const nodeType = parseInt(node.node_type)
158-
if (nodeType === NODE_TYPE_TABLE) {
159-
const table = this.tables.find(table => table.id === node.node_id)
160-
if (table) {
161-
await this.loadColumnsFromBE({
162-
view: null,
163-
tableId: table.id,
164-
})
165-
await this.loadRowsFromBE({
166-
viewId: null,
167-
tableId: table.id,
168-
})
169-
table.key = (table.id).toString()
170-
table.isView = false
171-
this.contextResources.push(table)
172-
}
160+
try {
161+
await this.loadContext({ id: this.activeContextId })
162+
const index = this.contexts.findIndex(c => parseInt(c.id) === parseInt(this.activeContextId))
163+
this.context = this.contexts[index]
164+
165+
if (!this.context) {
166+
this.errorMessage = t('tables', 'This application could not be found')
167+
return
168+
}
173169
174-
} else if (nodeType === NODE_TYPE_VIEW) {
175-
const view = this.views.find(view => view.id === node.node_id)
176-
if (view) {
177-
await this.loadColumnsFromBE({
178-
view,
179-
})
180-
await this.loadRowsFromBE({
181-
viewId: view.id,
182-
tableId: view.tableId,
183-
})
184-
view.key = 'view-' + (view.id).toString()
185-
view.isView = true
186-
this.contextResources.push(view)
170+
this.icon = await this.getContextIcon(this.activeContext.iconName)
171+
172+
if (this.context && this.context.nodes) {
173+
for (const [, node] of Object.entries(this.context.nodes)) {
174+
const nodeType = parseInt(node.node_type)
175+
if (nodeType === NODE_TYPE_TABLE) {
176+
const table = this.tables.find(table => table.id === node.node_id)
177+
if (table) {
178+
await this.loadColumnsFromBE({
179+
view: null,
180+
tableId: table.id,
181+
})
182+
await this.loadRowsFromBE({
183+
viewId: null,
184+
tableId: table.id,
185+
})
186+
table.key = (table.id).toString()
187+
table.isView = false
188+
this.contextResources.push(table)
189+
}
190+
191+
} else if (nodeType === NODE_TYPE_VIEW) {
192+
const view = this.views.find(view => view.id === node.node_id)
193+
if (view) {
194+
await this.loadColumnsFromBE({
195+
view,
196+
})
197+
await this.loadRowsFromBE({
198+
viewId: view.id,
199+
tableId: view.tableId,
200+
})
201+
view.key = 'view-' + (view.id).toString()
202+
view.isView = true
203+
this.contextResources.push(view)
204+
}
187205
}
188206
}
189207
}
208+
} catch (e) {
209+
if (e.message === 'NOT_FOUND') {
210+
this.errorMessage = t('tables', 'This application could not be found')
211+
} else {
212+
this.errorMessage = t('tables', 'An error occurred while loading the application')
213+
console.error(e)
214+
}
215+
} finally {
216+
this.loading = false
190217
}
191-
this.loading = false
192218
},
193219
createColumn(isView, element) {
194220
emit('tables:column:create', { isView, element })
@@ -235,4 +261,24 @@ export default {
235261
padding-left: 0px;
236262
}
237263
}
264+
265+
.error-container {
266+
display: flex;
267+
flex-direction: column;
268+
align-items: center;
269+
justify-content: center;
270+
text-align: center;
271+
padding: 2rem;
272+
height: 100dvh;
273+
min-height: 100%;
274+
color: var(--color-text);
275+
opacity: 0.6;
276+
277+
p {
278+
font-size: clamp(1.2rem, 4vw, 2rem);
279+
font-weight: 600;
280+
max-width: 90%;
281+
word-wrap: break-word;
282+
}
283+
}
238284
</style>

‎src/pages/Table.vue‎

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,83 @@
44
-->
55
<template>
66
<div class="main-table-view">
7-
<MainWrapper :element="activeTable" :is-view="false" />
8-
<MainModals />
7+
<div v-if="errorMessage" class="error-container">
8+
<IconTables :size="64" style="margin-bottom: 1rem;" />
9+
<p>{{ errorMessage }}</p>
10+
</div>
11+
12+
<div v-else-if="!activeTable">
13+
<div class="icon-loading" />
14+
</div>
15+
16+
<div v-else>
17+
<MainWrapper :element="activeTable" :is-view="false" />
18+
<MainModals />
19+
</div>
920
</div>
1021
</template>
1122

1223
<script>
13-
import { mapState } from 'pinia'
24+
import { mapState, mapActions } from 'pinia'
1425
import { useTablesStore } from '../store/store.js'
1526
import MainWrapper from '../modules/main/sections/MainWrapper.vue'
1627
import MainModals from '../modules/modals/Modals.vue'
28+
import IconTables from '../shared/assets/icons/IconTables.vue'
1729
1830
export default {
1931
components: {
2032
MainWrapper,
2133
MainModals,
34+
IconTables,
35+
},
36+
37+
data() {
38+
return {
39+
errorMessage: null,
40+
}
2241
},
2342
2443
computed: {
2544
...mapState(useTablesStore, ['activeTableId', 'activeTable']),
2645
},
2746
2847
watch: {
29-
activeTableId() {
30-
if (this.activeTableId && !this.activeTable) {
31-
// table does not exists, go to startpage
32-
this.$router.push('/').catch(err => err)
33-
}
48+
'$route.params.tableId': {
49+
immediate: true,
50+
handler() {
51+
this.errorMessage = null // reset previous error
52+
this.checkTable()
53+
},
3454
},
35-
activeTable() {
36-
if (this.activeTableId && !this.activeTable) {
37-
// table does not exists, go to startpage
38-
this.$router.push('/').catch(err => err)
55+
},
56+
57+
methods: {
58+
...mapActions(useTablesStore, ['loadContextTable', 'setActiveTableId']),
59+
60+
async checkTable() {
61+
const id = this.activeTableId || this.$route.params.tableId
62+
if (!id) return
63+
64+
try {
65+
if (!this.activeTableId) {
66+
this.setActiveTableId(parseInt(id))
67+
}
68+
69+
if (!this.activeTable) {
70+
await this.loadContextTable({ id })
71+
}
72+
} catch (e) {
73+
if (e.message === 'NOT_FOUND') {
74+
this.errorMessage = t('tables', 'This table could not be found')
75+
} else {
76+
this.errorMessage = t('tables', 'An error occurred while loading the table')
77+
console.error(e)
78+
}
3979
}
4080
},
4181
},
4282
}
83+
4384
</script>
4485
<style lang="scss">
4586
.main-table-view {
@@ -52,6 +93,26 @@ export default {
5293
margin: 5mm;
5394
}
5495
96+
.error-container {
97+
display: flex;
98+
flex-direction: column;
99+
align-items: center;
100+
justify-content: center;
101+
text-align: center;
102+
padding: 2rem;
103+
height: 100dvh;
104+
min-height: 100%;
105+
color: var(--color-text);
106+
opacity: 0.6;
107+
108+
p {
109+
font-size: clamp(1.2rem, 4vw, 2rem);
110+
font-weight: 600;
111+
max-width: 90%;
112+
word-wrap: break-word;
113+
}
114+
}
115+
55116
@media print {
56117
html, body {
57118
background: var(--color-main-background, white) !important;

‎src/pages/View.vue‎

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,78 @@
44
-->
55
<template>
66
<div class="main-view-view">
7-
<MainWrapper :element="activeView" :is-view="true" />
8-
<MainModals />
7+
<div v-if="!activeView && errorMessage" class="error-container">
8+
<IconTables :size="64" style="margin-bottom: 1rem;" />
9+
<p>{{ errorMessage }}</p>
10+
</div>
11+
12+
<div v-else-if="!activeView">
13+
<div class="icon-loading" />
14+
</div>
15+
16+
<div v-else>
17+
<MainWrapper :element="activeView" :is-view="true" />
18+
<MainModals />
19+
</div>
920
</div>
1021
</template>
1122

1223
<script>
13-
import { mapState } from 'pinia'
24+
import { mapState, mapActions } from 'pinia'
1425
import { useTablesStore } from '../store/store.js'
1526
import MainWrapper from '../modules/main/sections/MainWrapper.vue'
1627
import MainModals from '../modules/modals/Modals.vue'
28+
import IconTables from '../shared/assets/icons/IconTables.vue'
1729
1830
export default {
1931
2032
components: {
2133
MainWrapper,
2234
MainModals,
35+
IconTables,
36+
},
37+
38+
data() {
39+
return {
40+
errorMessage: null,
41+
}
2342
},
2443
2544
computed: {
2645
...mapState(useTablesStore, ['activeViewId', 'activeView']),
2746
},
2847
2948
watch: {
30-
activeViewId() {
31-
if (this.activeViewId && !this.activeView) {
32-
// view does not exist, go to startpage
33-
this.$router.push('/').catch(err => err)
49+
'$route.params.viewId': {
50+
immediate: true,
51+
handler() {
52+
this.errorMessage = null
53+
this.checkView()
54+
},
55+
},
56+
},
57+
58+
methods: {
59+
...mapActions(useTablesStore, ['setActiveViewId', 'loadContextView']),
60+
async checkView() {
61+
const id = this.activeViewId || this.$route.params.viewId
62+
if (!id) return
63+
64+
try {
65+
if (!this.activeViewId) {
66+
this.setActiveViewId(parseInt(id))
67+
}
68+
69+
if (!this.activeView) {
70+
await this.loadContextView({ id })
71+
}
72+
} catch (e) {
73+
if (e.message === 'NOT_FOUND') {
74+
this.errorMessage = t('tables', 'This view could not be found')
75+
} else {
76+
this.errorMessage = t('tables', 'An error occurred while loading the view')
77+
console.error(e)
78+
}
3479
}
3580
},
3681
},
@@ -40,5 +85,25 @@ export default {
4085
.main-view-view {
4186
width: max-content;
4287
min-width: var(--app-content-width, 100%);
88+
89+
.error-container {
90+
display: flex;
91+
flex-direction: column;
92+
align-items: center;
93+
justify-content: center;
94+
text-align: center;
95+
padding: 2rem;
96+
height: 100dvh;
97+
min-height: 100%;
98+
color: var(--color-text);
99+
opacity: 0.6;
100+
101+
p {
102+
font-size: clamp(1.2rem, 4vw, 2rem);
103+
font-weight: 600;
104+
max-width: 90%;
105+
word-wrap: break-word;
106+
}
107+
}
43108
}
44109
</style>

0 commit comments

Comments
 (0)