Skip to content

Commit 6796c9e

Browse files
authored
feat: Add info panel options prefetchImage, prefetchVideo, prefetchAudio to pre-fetch media content in the info panel (#3009)
1 parent f83a975 commit 6796c9e

File tree

3 files changed

+96
-5
lines changed

3 files changed

+96
-5
lines changed

README.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,9 @@ Each class in `columnPreference` can have an array of column configurations:
224224
| `cloudCodeFunction` | String | no | - | `"getUserDetails"` | Cloud Function receiving selected object. |
225225
| `prefetchObjects` | Number | yes | `0` | `2` | Number of next rows to prefetch. |
226226
| `prefetchStale` | Number | yes | `0` | `10` | Seconds after which prefetched data is stale. |
227+
| `prefetchImage` | Boolean | yes | `true` | `false` | Whether to prefetch image content. |
228+
| `prefetchVideo` | Boolean | yes | `true` | `false` | Whether to prefetch video content. |
229+
| `prefetchAudio` | Boolean | yes | `true` | `false` | Whether to prefetch audio content. |
227230

228231

229232
##### User Configuration (`users[]`)
@@ -1020,7 +1023,10 @@ The following example dashboard configuration shows an info panel for the `_User
10201023
"classes": ["_User"],
10211024
"cloudCodeFunction": "getUserDetails",
10221025
"prefetchObjects": 2,
1023-
"prefetchStale": 10
1026+
"prefetchStale": 10,
1027+
"prefetchImage": true,
1028+
"prefetchVideo": true,
1029+
"prefetchAudio": true
10241030
}
10251031
]
10261032
}
@@ -1321,13 +1327,18 @@ Example:
13211327

13221328
To reduce the time for info panel data to appear, data can be prefetched.
13231329

1324-
| Parameter | Type | Optional | Default | Example | Description |
1325-
|--------------------------------|--------|----------|---------|---------|-----------------------------------------------------------------------------------------------------------------------------------|
1326-
| `infoPanel[*].prefetchObjects` | Number | yes | `0` | `2` | Number of next rows to prefetch when browsing sequential rows. For example, `2` means the next 2 rows will be fetched in advance. |
1327-
| `infoPanel[*].prefetchStale` | Number | yes | `0` | `10` | Duration in seconds after which prefetched data is discarded as stale. |
1330+
| Parameter | Type | Optional | Default | Example | Description |
1331+
|--------------------------------|---------|----------|---------|---------|-----------------------------------------------------------------------------------------------------------------------------------|
1332+
| `infoPanel[*].prefetchObjects` | Number | yes | `0` | `2` | Number of next rows to prefetch when browsing sequential rows. For example, `2` means the next 2 rows will be fetched in advance. |
1333+
| `infoPanel[*].prefetchStale` | Number | yes | `0` | `10` | Duration in seconds after which prefetched data is discarded as stale. |
1334+
| `infoPanel[*].prefetchImage` | Boolean | yes | `true` | `false` | Whether to prefetch image content when prefetching objects. Only applies when `prefetchObjects` is enabled. |
1335+
| `infoPanel[*].prefetchVideo` | Boolean | yes | `true` | `false` | Whether to prefetch video content when prefetching objects. Only applies when `prefetchObjects` is enabled. |
1336+
| `infoPanel[*].prefetchAudio` | Boolean | yes | `true` | `false` | Whether to prefetch audio content when prefetching objects. Only applies when `prefetchObjects` is enabled. |
13281337

13291338
Prefetching is particularly useful when navigating through lists of objects. To optimize performance and avoid unnecessary data loading, prefetching is triggered only after the user has moved through 3 consecutive rows using the keyboard down-arrow key or by mouse click.
13301339

1340+
When `prefetchObjects` is enabled, media content (images, videos, and audio) in the info panel can also be prefetched to improve loading performance. By default, all media types are prefetched, but you can selectively disable prefetching for specific media types using the `prefetchImage`, `prefetchVideo`, and `prefetchAudio` options.
1341+
13311342
### Freeze Columns
13321343

13331344
▶️ *Core > Browser > Freeze column*

src/dashboard/Data/Browser/Browser.react.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,9 @@ class Browser extends DashboardView {
465465
classes: panel.classes,
466466
prefetchObjects: panel.prefetchObjects || 0,
467467
prefetchStale: panel.prefetchStale || 0,
468+
prefetchImage: panel.prefetchImage ?? true,
469+
prefetchVideo: panel.prefetchVideo ?? true,
470+
prefetchAudio: panel.prefetchAudio ?? true,
468471
});
469472
});
470473
});

src/dashboard/Data/Browser/DataBrowser.react.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,9 @@ export default class DataBrowser extends React.Component {
768768
return {
769769
prefetchObjects: config?.prefetchObjects || 0,
770770
prefetchStale: config?.prefetchStale || 0,
771+
prefetchImage: config?.prefetchImage ?? true,
772+
prefetchVideo: config?.prefetchVideo ?? true,
773+
prefetchAudio: config?.prefetchAudio ?? true,
771774
};
772775
}
773776

@@ -809,6 +812,66 @@ export default class DataBrowser extends React.Component {
809812
}
810813
}
811814

815+
isSafeHttpUrl(url) {
816+
try {
817+
const parsed = new URL(url);
818+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
819+
} catch {
820+
return false;
821+
}
822+
}
823+
824+
extractMediaUrls(data) {
825+
const urls = { images: new Set(), videos: new Set(), audios: new Set() };
826+
827+
if (!data?.panel?.segments) {
828+
return urls;
829+
}
830+
831+
data.panel.segments.forEach(segment => {
832+
if (segment.items) {
833+
segment.items.forEach(item => {
834+
if (item.type === 'image' && item.url && this.isSafeHttpUrl(item.url)) {
835+
urls.images.add(item.url);
836+
} else if (item.type === 'video' && item.url && this.isSafeHttpUrl(item.url)) {
837+
urls.videos.add(item.url);
838+
} else if (item.type === 'audio' && item.url && this.isSafeHttpUrl(item.url)) {
839+
urls.audios.add(item.url);
840+
}
841+
});
842+
}
843+
});
844+
845+
return urls;
846+
}
847+
848+
prefetchMedia(urls, mediaType) {
849+
if (!urls || urls.size === 0) {
850+
return;
851+
}
852+
853+
urls.forEach(url => {
854+
// Use link-based prefetching for better browser optimization and caching
855+
const link = document.createElement('link');
856+
link.rel = mediaType === 'image' ? 'preload' : 'prefetch';
857+
link.as = mediaType;
858+
link.href = url;
859+
860+
link.onload = () => {
861+
// Resource successfully cached, safe to remove the link element
862+
link.remove();
863+
};
864+
865+
link.onerror = () => {
866+
console.error(`Failed to prefetch ${mediaType}: ${url}`);
867+
// Failed to fetch, remove the link element
868+
link.remove();
869+
};
870+
871+
document.head.appendChild(link);
872+
});
873+
}
874+
812875
prefetchObject(objectId) {
813876
const { className, app } = this.props;
814877
const cloudCodeFunction =
@@ -831,6 +894,20 @@ export default class DataBrowser extends React.Component {
831894
[objectId]: { data: result, timestamp: Date.now() },
832895
},
833896
}));
897+
898+
// Prefetch media if enabled
899+
const { prefetchImage, prefetchVideo, prefetchAudio } = this.getPrefetchSettings();
900+
const mediaUrls = this.extractMediaUrls(result);
901+
902+
if (prefetchImage && mediaUrls.images.size > 0) {
903+
this.prefetchMedia(mediaUrls.images, 'image');
904+
}
905+
if (prefetchVideo && mediaUrls.videos.size > 0) {
906+
this.prefetchMedia(mediaUrls.videos, 'video');
907+
}
908+
if (prefetchAudio && mediaUrls.audios.size > 0) {
909+
this.prefetchMedia(mediaUrls.audios, 'audio');
910+
}
834911
}).catch(error => {
835912
console.error(`Failed to prefetch object ${objectId}:`, error);
836913
});

0 commit comments

Comments
 (0)