feat: load update conversations progressively (Closes #761)
This commit is contained in:
1 parent
7c86f28346
commit
a9d586e689
8 files changed
+123
-33
No files matched your search
+10
-1
@@ -761,8 +761,9 @@
|
||||
}
|
||||
|
||||
async function fetchNotificationConversation(notificationId, page) {
|
||||
const pageQuery = Number.isInteger(page) ? '&page=' + encodeURIComponent(page) : '';
|
||||
const response = await fetch('api/v1/notifications/' + encodeURIComponent(notificationId) +
|
||||
'/conversation?page=' + encodeURIComponent(page) + '&limit=20', {
|
||||
'/conversation?limit=20' + pageQuery, {
|
||||
headers: { Accept: 'application/json' },
|
||||
});
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
@@ -936,6 +937,7 @@
|
||||
qs('#update-sheet-title').textContent = item.title || 'Unread update';
|
||||
qs('#update-comments').textContent = '';
|
||||
qs('#update-conversation-status').textContent = '';
|
||||
qs('#retry-update-conversation').hidden = true;
|
||||
qs('#load-older-update-comments').hidden = true;
|
||||
qs('#update-subject-body').textContent = '';
|
||||
qs('#update-subject-type').textContent = item.subject_type || 'Update';
|
||||
@@ -975,6 +977,10 @@
|
||||
qs('#retry-update-load').hidden = true;
|
||||
},
|
||||
onConversation: renderUpdateConversation,
|
||||
onConversationStatus: message => {
|
||||
qs('#update-conversation-status').textContent = message;
|
||||
qs('#retry-update-conversation').hidden = !message.startsWith('Conversation temporarily unavailable.');
|
||||
},
|
||||
onItems: items => {
|
||||
const readId = selectedUpdate?.notification_id;
|
||||
lastMyWork = items;
|
||||
@@ -5527,6 +5533,9 @@
|
||||
qs('#retry-update-load').addEventListener('click', () => {
|
||||
if (selectedUpdate) notificationReader.open(selectedUpdate, lastMyWork);
|
||||
});
|
||||
qs('#retry-update-conversation').addEventListener('click', () => {
|
||||
notificationReader.retryConversation();
|
||||
});
|
||||
qs('#load-older-update-comments').addEventListener('click', async () => {
|
||||
const button = qs('#load-older-update-comments');
|
||||
const panel = qs('#update-sheet .update-sheet-panel');
|
||||
|
||||
@@ -763,6 +763,7 @@
|
||||
<button class="update-new-activity-jump" id="jump-update-new-activity" type="button" hidden>Jump to new activity</button>
|
||||
<button class="conversation-more" id="load-older-update-comments" type="button" hidden>Load older messages</button>
|
||||
<div id="update-conversation-status" class="small" aria-live="assertive"></div>
|
||||
<button class="update-retry" id="retry-update-conversation" type="button" hidden>Retry conversation</button>
|
||||
<details>
|
||||
<summary><h2>Subject context</h2></summary>
|
||||
<div class="update-sheet-content muted markdown-content" id="update-subject-body"></div>
|
||||
|
||||
@@ -379,6 +379,7 @@ function createNotificationReader({
|
||||
loadSaved = () => null,
|
||||
loadConversation = null,
|
||||
onConversation = () => {},
|
||||
onConversationStatus = () => {},
|
||||
createPager = typeof createConversationPager === 'function' ? createConversationPager : null,
|
||||
getScope = () => '',
|
||||
}) {
|
||||
@@ -390,6 +391,29 @@ function createNotificationReader({
|
||||
let prefetched = null;
|
||||
let prefetchKey = '';
|
||||
|
||||
async function hydrateConversation(item, version) {
|
||||
if (!loadConversation || !createPager || !item || offlineHydrated) return false;
|
||||
onConversationStatus('Loading conversation…');
|
||||
try {
|
||||
const initial = await loadConversation(item.notification_id, null);
|
||||
if (selected !== item || version !== loadVersion) return false;
|
||||
conversationPager = createPager({
|
||||
loadPage: page => loadConversation(item.notification_id, page),
|
||||
});
|
||||
const state = conversationPager.reset(initial);
|
||||
onConversation(state);
|
||||
onConversationStatus(state.comments.length + ' of ' +
|
||||
Math.max(state.total || 0, state.comments.length) + ' messages loaded.');
|
||||
return true;
|
||||
} catch (_error) {
|
||||
if (selected === item && version === loadVersion) {
|
||||
conversationPager = null;
|
||||
onConversationStatus('Conversation temporarily unavailable. Retry.');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function prefetch(item) {
|
||||
if (!item) { prefetched = null; prefetchKey = ''; return false; }
|
||||
const notificationId = item?.notification_id;
|
||||
@@ -446,6 +470,9 @@ function createNotificationReader({
|
||||
conversationPager = null;
|
||||
}
|
||||
onStatus('Update ready.');
|
||||
if (!offlineHydrated && detail.conversation_available) {
|
||||
void hydrateConversation(item, version);
|
||||
}
|
||||
return true;
|
||||
} catch (_error) {
|
||||
if (selected === item && version === loadVersion) {
|
||||
@@ -458,6 +485,10 @@ function createNotificationReader({
|
||||
return {
|
||||
open,
|
||||
prefetch,
|
||||
retryConversation() {
|
||||
if (!selected || offlineHydrated) return Promise.resolve(false);
|
||||
return hydrateConversation(selected, loadVersion);
|
||||
},
|
||||
commentPager() {
|
||||
return conversationPager;
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user