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
6 changes: 6 additions & 0 deletions graphcode/Sources/Features/App/AppSidebarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,12 @@ struct AppSidebarView: View {
.frame(width: 3, height: 14)
Text(node.title).font(.system(size: 12.5)).lineLimit(1)
Spacer(minLength: 4)
if let watching = MailroomWatchPresentation.tooltip(for: node) {
Image(systemName: MailroomWatchPresentation.symbolName)
.font(.system(size: 10))
.foregroundStyle(.white.opacity(0.45))
.help(watching)
}
Text(LoopCardPresentation.duration(sidebarNow.timeIntervalSince(node.createdAt)))
.font(.system(size: 10.5, design: .monospaced))
.foregroundStyle(.white.opacity(0.5))
Expand Down
6 changes: 6 additions & 0 deletions graphcode/Sources/Features/Canvas/LoopCardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ struct LoopCardView: View {
if isRemote {
Image(systemName: "network").font(.system(size: 9)).foregroundStyle(.white.opacity(0.4))
}
if let watching = MailroomWatchPresentation.tooltip(for: node) {
Image(systemName: MailroomWatchPresentation.symbolName)
.font(.system(size: 9))
.foregroundStyle(.white.opacity(0.4))
.help(watching)
}
switch entryRole {
case .entry: EntryChip()
case .cycleOnly: CycleChip()
Expand Down
18 changes: 18 additions & 0 deletions graphcode/Sources/Features/Canvas/MailroomWatchPresentation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import GraphcodeKit
import MailroomKit

/// The envelope that marks a loop watching its project's Mailroom, and its tooltip.
///
/// Hidden on a resolved loop: `mailroomWatch` outlives the session that set it, but a
/// loop that has finished for good cannot be rung.
enum MailroomWatchPresentation {
static let symbolName = "envelope"

static func showsGlyph(for node: LoopNode) -> Bool { tooltip(for: node) != nil }

static func tooltip(for node: LoopNode) -> String? {
guard let watch = node.mailroomWatch, !node.isResolved else { return nil }
guard let topic = watch.topic else { return "Watching the Mailroom" }
return "Watching the Mailroom · topic \(topic)"
}
}
46 changes: 46 additions & 0 deletions graphcode/Tests/MailroomWatchPresentationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Foundation
import GraphcodeKit
import MailroomKit
import Testing

@testable import graphcode

@Suite
struct MailroomWatchPresentationTests {
private func node(watch: MailroomWatch?, state: LoopState = .running) -> LoopNode {
LoopNode(title: "Triage", loopType: .goalBased, mailroomWatch: watch, state: state)
}

@Test
func aLoopWithoutAWatchShowsNothing() {
let plain = node(watch: nil)

#expect(!MailroomWatchPresentation.showsGlyph(for: plain))
#expect(MailroomWatchPresentation.tooltip(for: plain) == nil)
}

@Test
func aWatchOnEveryPostSaysSoWithoutATopic() {
let hearingAll = node(watch: MailroomWatch())

#expect(MailroomWatchPresentation.showsGlyph(for: hearingAll))
#expect(MailroomWatchPresentation.tooltip(for: hearingAll) == "Watching the Mailroom")
}

@Test
func aWatchOnOneTopicNamesIt() {
let narrowed = node(watch: MailroomWatch(topic: "design"))

#expect(MailroomWatchPresentation.showsGlyph(for: narrowed))
#expect(
MailroomWatchPresentation.tooltip(for: narrowed) == "Watching the Mailroom · topic design")
}

@Test(arguments: [LoopState.succeeded, .failed, .stalled, .stopped])
func aResolvedLoopHidesItsWatch(state: LoopState) {
let finished = node(watch: MailroomWatch(topic: "design"), state: state)

#expect(!MailroomWatchPresentation.showsGlyph(for: finished))
#expect(MailroomWatchPresentation.tooltip(for: finished) == nil)
}
}
Loading