diff --git a/libs/web/tracker/application/src/lib/stores/issue.store.ts b/libs/web/tracker/application/src/lib/stores/issue.store.ts index 1b2356f..1e620af 100644 --- a/libs/web/tracker/application/src/lib/stores/issue.store.ts +++ b/libs/web/tracker/application/src/lib/stores/issue.store.ts @@ -237,6 +237,41 @@ export const IssueStore = signalStore( debounceTime(150), switchMap(({ payload }) => fetchIssue(payload.issueId)), ), + /** + * What this page just changed, shown without waiting for the live + * update, which a dropped socket loses or a slow one delays. The + * API projects its read model a moment after answering, so the + * ticket, its comments and its subtasks are asked for twice. + */ + catchUp$: events + .on(issueApiEvents.commandSucceeded, issueApiEvents.checklistSaved) + .pipe( + map(() => store.issue()), + filter((issue): issue is Issue => !!issue), + switchMap((issue) => + merge( + ...[300, 1500].map((ms) => + timer(ms).pipe( + switchMap(() => + merge( + fetchIssue(issue.id), + comments + .list(issue.id) + .pipe( + map((list) => issueApiEvents.commentsLoaded(list)), + ), + [ + issueRealtimeEvents.childrenTouched({ + issueId: issue.id, + }), + ], + ), + ), + ), + ), + ), + ), + ), liveComments$: events.on(issuePageEvents.opened).pipe( switchMap(() => loaded$.pipe(map(({ payload }) => payload.id))), filter((id, index) => index === 0 || id !== store.issue()?.id), diff --git a/libs/web/tracker/presenters/src/lib/pages/issue.page.scss b/libs/web/tracker/presenters/src/lib/pages/issue.page.scss index 2feb3c5..d351991 100644 --- a/libs/web/tracker/presenters/src/lib/pages/issue.page.scss +++ b/libs/web/tracker/presenters/src/lib/pages/issue.page.scss @@ -47,11 +47,15 @@ .ts-issue__title-row { display: flex; + flex-wrap: wrap; align-items: flex-start; - gap: 0.5rem; + gap: 0.75rem 1rem; + margin-top: 0.75rem; h1 { - margin: 0.75rem 0 0; + flex: 1 1 20rem; + min-width: 0; + margin: 0; font-size: clamp(1.625rem, 1.2rem + 1.4vw, 2.375rem); font-weight: 700; line-height: 1.1; @@ -59,6 +63,15 @@ } } +// Follow and edit, together, level with the title's first line. +.ts-issue__actions { + display: flex; + flex-shrink: 0; + gap: 0.5rem; + align-items: center; + margin-top: 0.25rem; +} + // Workflow: one button per allowed destination, in that status' colour. .ts-transitions { display: flex; diff --git a/libs/web/tracker/presenters/src/lib/pages/issue.page.ts b/libs/web/tracker/presenters/src/lib/pages/issue.page.ts index 4c6f883..e555df2 100644 --- a/libs/web/tracker/presenters/src/lib/pages/issue.page.ts +++ b/libs/web/tracker/presenters/src/lib/pages/issue.page.ts @@ -136,29 +136,37 @@ const MAX_FILE_BYTES = 25 * 1024 * 1024;