diff options
Diffstat (limited to 'Omni/Jr')
| -rw-r--r-- | Omni/Jr/Web.hs | 48 | ||||
| -rw-r--r-- | Omni/Jr/Web/Style.hs | 69 |
2 files changed, 117 insertions, 0 deletions
diff --git a/Omni/Jr/Web.hs b/Omni/Jr/Web.hs index b751ee9..6d0fa20 100644 --- a/Omni/Jr/Web.hs +++ b/Omni/Jr/Web.hs @@ -429,6 +429,8 @@ instance Lucid.ToHtml TaskDetailPage where Lucid.div_ [Lucid.class_ "container"] <| do Lucid.h1_ <| Lucid.toHtml (TaskCore.taskTitle task) + renderRetryContextBanner maybeRetry + Lucid.div_ [Lucid.class_ "task-detail"] <| do Lucid.div_ [Lucid.class_ "detail-row"] <| do Lucid.span_ [Lucid.class_ "detail-label"] "ID:" @@ -679,6 +681,52 @@ instance Lucid.ToHtml TaskDetailPage where let dollars = fromIntegral cents / 100.0 :: Double in "$" <> Text.pack (showFFloat (Just 2) dollars "") +renderRetryContextBanner :: (Monad m) => Maybe TaskCore.RetryContext -> Lucid.HtmlT m () +renderRetryContextBanner Nothing = pure () +renderRetryContextBanner (Just ctx) = + Lucid.div_ [Lucid.class_ bannerClass] <| do + Lucid.div_ [Lucid.class_ "retry-banner-header"] <| do + Lucid.span_ [Lucid.class_ "retry-icon"] retryIcon + Lucid.span_ [Lucid.class_ "retry-attempt"] (Lucid.toHtml attemptText) + when maxRetriesExceeded + <| Lucid.span_ [Lucid.class_ "retry-warning-badge"] "Needs Human Intervention" + + Lucid.div_ [Lucid.class_ "retry-banner-details"] <| do + Lucid.div_ [Lucid.class_ "retry-detail-row"] <| do + Lucid.span_ [Lucid.class_ "retry-label"] "Failure Reason:" + Lucid.span_ [Lucid.class_ "retry-value"] (Lucid.toHtml (summarizeReason (TaskCore.retryReason ctx))) + + let commit = TaskCore.retryOriginalCommit ctx + unless (Text.null commit) <| do + Lucid.div_ [Lucid.class_ "retry-detail-row"] <| do + Lucid.span_ [Lucid.class_ "retry-label"] "Original Commit:" + Lucid.code_ [Lucid.class_ "retry-commit"] (Lucid.toHtml (Text.take 8 commit)) + + let conflicts = TaskCore.retryConflictFiles ctx + unless (null conflicts) <| do + Lucid.div_ [Lucid.class_ "retry-detail-row"] <| do + Lucid.span_ [Lucid.class_ "retry-label"] "Conflict Files:" + Lucid.ul_ [Lucid.class_ "retry-conflict-list"] + <| traverse_ (Lucid.li_ <. Lucid.toHtml) conflicts + + when maxRetriesExceeded + <| Lucid.div_ + [Lucid.class_ "retry-warning-message"] + "This task has exceeded the maximum number of retries. A human must review the failure and either fix the issue manually or reset the retry count." + where + attempt = TaskCore.retryAttempt ctx + maxRetriesExceeded = attempt >= 3 + bannerClass = if maxRetriesExceeded then "retry-banner retry-banner-critical" else "retry-banner retry-banner-warning" + retryIcon = if maxRetriesExceeded then "⚠" else "↻" + attemptText = "Attempt " <> tshow attempt <> " of 3" + + summarizeReason :: Text -> Text + summarizeReason reason + | "rejected:" `Text.isPrefixOf` reason = "Rejected: " <> Text.strip (Text.drop 9 reason) + | "Test failure:" `Text.isPrefixOf` reason = "Test failure (see details below)" + | "MERGE CONFLICT" `Text.isPrefixOf` reason = "Merge conflict with concurrent changes" + | otherwise = Text.take 100 reason <> if Text.length reason > 100 then "..." else "" + instance Lucid.ToHtml TaskReviewPage where toHtmlRaw = Lucid.toHtml toHtml (ReviewPageNotFound tid) = diff --git a/Omni/Jr/Web/Style.hs b/Omni/Jr/Web/Style.hs index 19fc371..9ec03d6 100644 --- a/Omni/Jr/Web/Style.hs +++ b/Omni/Jr/Web/Style.hs @@ -32,6 +32,7 @@ stylesheet = do activityTimelineStyles commitStyles markdownStyles + retryBannerStyles responsiveStyles darkModeStyles @@ -706,6 +707,74 @@ markdownStyles = do padding (px 1) (px 4) (px 1) (px 4) borderRadius (px 2) (px 2) (px 2) (px 2) +retryBannerStyles :: Css +retryBannerStyles = do + ".retry-banner" ? do + borderRadius (px 4) (px 4) (px 4) (px 4) + padding (px 12) (px 16) (px 12) (px 16) + margin (px 0) (px 0) (px 16) (px 0) + ".retry-banner-warning" ? do + backgroundColor "#fef3c7" + border (px 1) solid "#f59e0b" + ".retry-banner-critical" ? do + backgroundColor "#fee2e2" + border (px 1) solid "#ef4444" + ".retry-banner-header" ? do + display flex + alignItems center + Stylesheet.key "gap" ("8px" :: Text) + marginBottom (px 8) + ".retry-icon" ? do + fontSize (px 18) + fontWeight bold + ".retry-attempt" ? do + fontSize (px 14) + fontWeight (weight 600) + color "#374151" + ".retry-warning-badge" ? do + backgroundColor "#dc2626" + color white + fontSize (px 11) + fontWeight (weight 600) + padding (px 2) (px 8) (px 2) (px 8) + borderRadius (px 2) (px 2) (px 2) (px 2) + marginLeft auto + ".retry-banner-details" ? do + fontSize (px 13) + color "#374151" + ".retry-detail-row" ? do + display flex + alignItems flexStart + Stylesheet.key "gap" ("8px" :: Text) + margin (px 4) (px 0) (px 4) (px 0) + ".retry-label" ? do + fontWeight (weight 500) + minWidth (px 110) + flexShrink 0 + ".retry-value" ? do + color "#4b5563" + ".retry-commit" ? do + fontFamily ["SF Mono", "Monaco", "Consolas", "monospace"] [monospace] + fontSize (em 0.9) + backgroundColor "#f3f4f6" + padding (px 1) (px 4) (px 1) (px 4) + borderRadius (px 2) (px 2) (px 2) (px 2) + ".retry-conflict-list" ? do + margin (px 0) (px 0) (px 0) (px 0) + padding (px 0) (px 0) (px 0) (px 16) + (".retry-conflict-list" ** li) ? do + fontFamily ["SF Mono", "Monaco", "Consolas", "monospace"] [monospace] + fontSize (px 12) + margin (px 2) (px 0) (px 2) (px 0) + ".retry-warning-message" ? do + marginTop (px 12) + padding (px 10) (px 12) (px 10) (px 12) + backgroundColor "#fecaca" + borderRadius (px 2) (px 2) (px 2) (px 2) + fontSize (px 12) + color "#991b1b" + fontWeight (weight 500) + responsiveStyles :: Css responsiveStyles = do query Media.screen [Media.maxWidth (px 600)] <| do |
