Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions wework/src/features/workbench/runtimeTaskReminders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ describe('runtimeTaskReminders', () => {

const snapshot = buildRuntimeTaskReminderSnapshot({
runtimeWork: runtimeWork([completedTask]),
currentRuntimeTask: null,
previousRunningTaskKeys: new Set([key]),
storedUnreadTaskKeys: new Set(),
})
Expand All @@ -63,6 +64,7 @@ describe('runtimeTaskReminders', () => {

const snapshot = buildRuntimeTaskReminderSnapshot({
runtimeWork: runtimeWork([completedTask]),
currentRuntimeTask: null,
previousRunningTaskKeys: new Set([key]),
storedUnreadTaskKeys: new Set(),
})
Expand All @@ -77,6 +79,7 @@ describe('runtimeTaskReminders', () => {

const snapshot = buildRuntimeTaskReminderSnapshot({
runtimeWork: runtimeWork([activeTask]),
currentRuntimeTask: null,
previousRunningTaskKeys: new Set(),
storedUnreadTaskKeys: new Set(),
})
Expand All @@ -85,45 +88,67 @@ describe('runtimeTaskReminders', () => {
expect(snapshot.completedUnreadItems).toEqual([])
})

test('marks the currently selected completed task unread', () => {
test('marks the current completed task unread when the window is not focused', () => {
const completedTask = task({ running: false })
const taskWorkspace = workspace([completedTask])
const key = getRuntimeTaskReminderItemKey(taskWorkspace, completedTask)

const snapshot = buildRuntimeTaskReminderSnapshot({
runtimeWork: runtimeWork([completedTask]),
currentRuntimeTask: { deviceId: 'local-device', taskId: 'task-1' },
previousRunningTaskKeys: new Set([key]),
storedUnreadTaskKeys: new Set(),
currentRuntimeTaskVisible: false,
})

expect(snapshot.unreadTaskKeys.has(key)).toBe(true)
expect(snapshot.completedUnreadItems.map(item => item.key)).toEqual([key])
})

test('does not auto-clear unread for a completed current task', () => {
test('treats the focused current task as read when it completes', () => {
const completedTask = task({ running: false })
const taskWorkspace = workspace([completedTask])
const key = getRuntimeTaskReminderItemKey(taskWorkspace, completedTask)

const snapshot = buildRuntimeTaskReminderSnapshot({
runtimeWork: runtimeWork([completedTask]),
currentRuntimeTask: { deviceId: 'local-device', taskId: 'task-1' },
previousRunningTaskKeys: new Set([key]),
storedUnreadTaskKeys: new Set(),
currentRuntimeTaskVisible: true,
})

expect(snapshot.unreadTaskKeys.has(key)).toBe(true)
expect(snapshot.completedUnreadItems.map(item => item.key)).toEqual([key])
expect(snapshot.unreadTaskKeys.has(key)).toBe(false)
expect(snapshot.completedUnreadItems).toEqual([])
})

test('clears stored unread for the focused current task', () => {
const completedTask = task({ running: false })
const taskWorkspace = workspace([completedTask])
const key = getRuntimeTaskReminderItemKey(taskWorkspace, completedTask)

const snapshot = buildRuntimeTaskReminderSnapshot({
runtimeWork: runtimeWork([completedTask]),
currentRuntimeTask: { deviceId: 'local-device', taskId: 'task-1' },
previousRunningTaskKeys: new Set(),
storedUnreadTaskKeys: new Set([key]),
currentRuntimeTaskVisible: true,
})

expect(snapshot.unreadTaskKeys.has(key)).toBe(false)
})

test('keeps stored unread for the current task until explicit read', () => {
test('keeps stored unread for the current task when the window is not focused', () => {
const completedTask = task({ running: false })
const taskWorkspace = workspace([completedTask])
const key = getRuntimeTaskReminderItemKey(taskWorkspace, completedTask)

const snapshot = buildRuntimeTaskReminderSnapshot({
runtimeWork: runtimeWork([completedTask]),
currentRuntimeTask: { deviceId: 'local-device', taskId: 'task-1' },
previousRunningTaskKeys: new Set(),
storedUnreadTaskKeys: new Set([key]),
currentRuntimeTaskVisible: false,
})

expect(snapshot.unreadTaskKeys.has(key)).toBe(true)
Expand All @@ -132,6 +157,7 @@ describe('runtimeTaskReminders', () => {
test('keeps unread keys for tasks that are temporarily missing from runtime work', () => {
const snapshot = buildRuntimeTaskReminderSnapshot({
runtimeWork: runtimeWork([]),
currentRuntimeTask: null,
previousRunningTaskKeys: new Set(),
storedUnreadTaskKeys: new Set(['local-device\0archived-task']),
})
Expand Down
53 changes: 52 additions & 1 deletion wework/src/features/workbench/runtimeTaskReminders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,24 +177,37 @@ function collectRuntimeTaskReminderItems(

export function buildRuntimeTaskReminderSnapshot({
runtimeWork,
currentRuntimeTask,
previousRunningTaskKeys,
storedUnreadTaskKeys,
currentRuntimeTaskVisible = false,
}: {
runtimeWork: RuntimeWorkListResponse | null | undefined
currentRuntimeTask: RuntimeTaskAddress | null | undefined
previousRunningTaskKeys: ReadonlySet<string>
storedUnreadTaskKeys: ReadonlySet<string>
currentRuntimeTaskVisible?: boolean
}): RuntimeTaskReminderSnapshot {
const items = collectRuntimeTaskReminderItems(runtimeWork)
const currentRuntimeTaskKey = currentRuntimeTask
? getRuntimeTaskReminderKey(currentRuntimeTask)
: null
const runningTaskKeys = new Set(
items.filter(item => isRuntimeTaskActive(item.task)).map(item => item.key)
)
const unreadTaskKeys = new Set(storedUnreadTaskKeys)
const completedUnreadItems: RuntimeTaskReminderItem[] = []
if (currentRuntimeTaskVisible && currentRuntimeTaskKey) {
unreadTaskKeys.delete(currentRuntimeTaskKey)
}

for (const item of items) {
if (!isRuntimeTaskTerminal(item.task) || !previousRunningTaskKeys.has(item.key)) {
continue
}
if (currentRuntimeTaskVisible && item.key === currentRuntimeTaskKey) {
continue
}
if (!unreadTaskKeys.has(item.key)) {
completedUnreadItems.push(item)
}
Expand All @@ -204,16 +217,23 @@ export function buildRuntimeTaskReminderSnapshot({
return { unreadTaskKeys, runningTaskKeys, completedUnreadItems, items }
}

function getWindowFocused(): boolean {
if (typeof document === 'undefined') return false
return document.visibilityState === 'visible' && document.hasFocus()
}

export function useRuntimeTaskReminders({
userId,
runtimeWork,
currentRuntimeTask,
}: {
userId: number | string | null | undefined
runtimeWork: RuntimeWorkListResponse | null | undefined
currentRuntimeTask: RuntimeTaskAddress | null | undefined
}): RuntimeTaskReminderState {
const [preferences, setPreferences] = useState<AppPreferences>(defaultAppPreferences)
const [storageVersion, setStorageVersion] = useState(0)
const [windowFocused, setWindowFocused] = useState(getWindowFocused)
const notifiedTaskKeysRef = useRef<Set<string>>(new Set())
const runningTaskKeysStorageKey = getReminderStorageKey(userId, 'runningTaskKeys')
const unreadTaskKeysStorageKey = getReminderStorageKey(userId, 'unreadTaskKeys')
Expand All @@ -238,6 +258,19 @@ export function useRuntimeTaskReminders({
}
}, [])

useEffect(() => {
const refreshFocused = () => setWindowFocused(getWindowFocused())
window.addEventListener('focus', refreshFocused)
window.addEventListener('blur', refreshFocused)
document.addEventListener('visibilitychange', refreshFocused)
refreshFocused()
return () => {
window.removeEventListener('focus', refreshFocused)
window.removeEventListener('blur', refreshFocused)
document.removeEventListener('visibilitychange', refreshFocused)
}
}, [])

const storedUnreadTaskKeys = useMemo(() => {
void storageVersion
return readStoredStringSet(unreadTaskKeysStorageKey)
Expand All @@ -246,10 +279,18 @@ export function useRuntimeTaskReminders({
() =>
buildRuntimeTaskReminderSnapshot({
runtimeWork,
currentRuntimeTask,
previousRunningTaskKeys: readStoredStringSet(runningTaskKeysStorageKey),
storedUnreadTaskKeys,
currentRuntimeTaskVisible: windowFocused,
}),
[runningTaskKeysStorageKey, runtimeWork, storedUnreadTaskKeys]
[
currentRuntimeTask,
runningTaskKeysStorageKey,
runtimeWork,
storedUnreadTaskKeys,
windowFocused,
]
)

useEffect(() => {
Expand All @@ -262,6 +303,14 @@ export function useRuntimeTaskReminders({
if (unreadChanged || runningChanged || snapshot.completedUnreadItems.length > 0) {
logRuntimeTaskReminderState('persist', {
userId,
currentRuntimeTask: currentRuntimeTask
? {
deviceId: currentRuntimeTask.deviceId,
taskId: currentRuntimeTask.taskId,
workspacePath: currentRuntimeTask.workspacePath ?? null,
}
: null,
currentRuntimeTaskVisible: windowFocused,
taskCompletionNotificationsEnabled: preferences.taskCompletionNotificationsEnabled,
previousUnreadTaskKeys: debugReminderKeys(previousUnreadTaskKeys),
nextUnreadTaskKeys: debugReminderKeys(snapshot.unreadTaskKeys),
Expand Down Expand Up @@ -297,10 +346,12 @@ export function useRuntimeTaskReminders({
}
}, [
preferences.taskCompletionNotificationsEnabled,
currentRuntimeTask,
runtimeWork,
runningTaskKeysStorageKey,
snapshot,
unreadTaskKeysStorageKey,
windowFocused,
userId,
])

Expand Down
Loading