diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte
index e94cf5da93..5207f293b1 100644
--- a/packages/frontend-core/src/components/grid/layout/Grid.svelte
+++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte
@@ -68,6 +68,7 @@
rowHeight,
contentLines,
gridFocused,
+ error,
} = context
// Keep config store up to date with props
@@ -149,8 +150,15 @@
+ {:else if $error}
+
+
There was a problem loading your grid
+
+ {$error}
+
+
{/if}
- {#if $loading}
+ {#if $loading && !$error}
@@ -273,6 +281,25 @@
opacity: 0.6;
}
+ /* Error */
+ .grid-error {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 8px;
+ }
+ .grid-error-title {
+ font-size: 18px;
+ font-weight: 600;
+ }
+ .grid-error-subtitle {
+ font-size: 16px;
+ }
+
/* Disable checkbox animation anywhere in the grid data */
.grid-data-outer :global(.spectrum-Checkbox-box:before),
.grid-data-outer :global(.spectrum-Checkbox-box:after),
diff --git a/packages/frontend-core/src/components/grid/stores/rows.js b/packages/frontend-core/src/components/grid/stores/rows.js
index 1a98ef1848..d348d5caa5 100644
--- a/packages/frontend-core/src/components/grid/stores/rows.js
+++ b/packages/frontend-core/src/components/grid/stores/rows.js
@@ -14,6 +14,7 @@ export const createStores = () => {
const rowChangeCache = writable({})
const inProgressChanges = writable({})
const hasNextPage = writable(false)
+ const error = writable(null)
// Generate a lookup map to quick find a row by ID
const rowLookupMap = derived(
@@ -47,6 +48,7 @@ export const createStores = () => {
rowChangeCache,
inProgressChanges,
hasNextPage,
+ error,
}
}
@@ -68,6 +70,7 @@ export const deriveStores = context => {
inProgressChanges,
previousFocusedRowId,
hasNextPage,
+ error,
} = context
const instanceLoaded = writable(false)
const fetch = writable(null)
@@ -122,7 +125,17 @@ export const deriveStores = context => {
// Subscribe to changes of this fetch model
unsubscribe = newFetch.subscribe(async $fetch => {
- if ($fetch.loaded && !$fetch.loading) {
+ if ($fetch.error) {
+ // Present a helpful error to the user
+ let message = "An unknown error occurred"
+ if ($fetch.error.status === 403) {
+ message = "You don't have access to this data"
+ } else if ($fetch.error.message) {
+ message = $fetch.error.message
+ }
+ error.set(message)
+ } else if ($fetch.loaded && !$fetch.loading) {
+ error.set(null)
hasNextPage.set($fetch.hasNextPage)
const $instanceLoaded = get(instanceLoaded)
const resetRows = $fetch.resetKey !== lastResetKey
diff --git a/packages/frontend-core/src/fetch/DataFetch.js b/packages/frontend-core/src/fetch/DataFetch.js
index b456753d4a..f9d7fd2624 100644
--- a/packages/frontend-core/src/fetch/DataFetch.js
+++ b/packages/frontend-core/src/fetch/DataFetch.js
@@ -57,6 +57,7 @@ export default class DataFetch {
cursor: null,
cursors: [],
resetKey: Math.random(),
+ error: null,
})
// Merge options with their default values
@@ -252,6 +253,10 @@ export default class DataFetch {
try {
return await this.API.fetchTableDefinition(datasource.tableId)
} catch (error) {
+ this.store.update(state => ({
+ ...state,
+ error,
+ }))
return null
}
}