show alerts in the sidebar
This has a bug -- it seems long polling can only wait on one page at a time. Need to re-unify the notifiers.
This commit is contained in:
parent
5271d699d2
commit
c2f3e66d8c
4 changed files with 59 additions and 27 deletions
|
@ -14,12 +14,23 @@ import Yesod
|
||||||
type Widget = forall sub master. GWidget sub master ()
|
type Widget = forall sub master. GWidget sub master ()
|
||||||
|
|
||||||
{- Different classes of alerts are displayed differently. -}
|
{- Different classes of alerts are displayed differently. -}
|
||||||
data AlertClass = Activity | Warning | Error | Message
|
data AlertClass = Activity | Warning | Error | Success | Message
|
||||||
|
deriving (Eq)
|
||||||
|
|
||||||
{- An alert can be a simple message, or a Yesod Widget -}
|
{- An alert can be a simple message, or an arbitrary Yesod Widget -}
|
||||||
data AlertMessage = StringAlert String | WidgetAlert Widget
|
data AlertMessage = StringAlert String | WidgetAlert Widget
|
||||||
|
|
||||||
data Alert = Alert
|
data Alert = Alert
|
||||||
{ alertClass :: AlertClass
|
{ alertClass :: AlertClass
|
||||||
|
, alertHeader :: Maybe String
|
||||||
, alertMessage :: AlertMessage
|
, alertMessage :: AlertMessage
|
||||||
|
, alertBlockDisplay :: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
activityAlert :: Maybe String -> String -> Alert
|
||||||
|
activityAlert header message = Alert
|
||||||
|
{ alertClass = Activity
|
||||||
|
, alertHeader = header
|
||||||
|
, alertMessage = StringAlert message
|
||||||
|
, alertBlockDisplay = False
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import Assistant.ThreadedMonad
|
||||||
import Assistant.DaemonStatus
|
import Assistant.DaemonStatus
|
||||||
import Assistant.Changes
|
import Assistant.Changes
|
||||||
import Assistant.TransferQueue
|
import Assistant.TransferQueue
|
||||||
|
import Assistant.Alert
|
||||||
import Logs.Transfer
|
import Logs.Transfer
|
||||||
import Utility.DirWatcher
|
import Utility.DirWatcher
|
||||||
import Utility.Types.DirWatcher
|
import Utility.Types.DirWatcher
|
||||||
|
@ -60,7 +61,7 @@ watchThread st dstatus transferqueue changechan = do
|
||||||
void $ watchDir "." ignored hooks startup
|
void $ watchDir "." ignored hooks startup
|
||||||
debug thisThread [ "watching", "."]
|
debug thisThread [ "watching", "."]
|
||||||
where
|
where
|
||||||
startup = statupScan st dstatus
|
startup = startupScan st dstatus
|
||||||
hook a = Just $ runHandler thisThread st dstatus transferqueue changechan a
|
hook a = Just $ runHandler thisThread st dstatus transferqueue changechan a
|
||||||
hooks = WatchHooks
|
hooks = WatchHooks
|
||||||
{ addHook = hook onAdd
|
{ addHook = hook onAdd
|
||||||
|
@ -71,11 +72,12 @@ watchThread st dstatus transferqueue changechan = do
|
||||||
}
|
}
|
||||||
|
|
||||||
{- Initial scartup scan. The action should return once the scan is complete. -}
|
{- Initial scartup scan. The action should return once the scan is complete. -}
|
||||||
statupScan :: ThreadState -> DaemonStatusHandle -> IO a -> IO a
|
startupScan :: ThreadState -> DaemonStatusHandle -> IO a -> IO a
|
||||||
statupScan st dstatus scanner = do
|
startupScan st dstatus scanner = do
|
||||||
runThreadState st $
|
runThreadState st $
|
||||||
showAction "scanning"
|
showAction "scanning"
|
||||||
r <- scanner
|
let alert = activityAlert Nothing "Performing startup scan"
|
||||||
|
r <- alertWhile dstatus alert scanner
|
||||||
modifyDaemonStatus_ dstatus $ \s -> s { scanComplete = True }
|
modifyDaemonStatus_ dstatus $ \s -> s { scanComplete = True }
|
||||||
|
|
||||||
-- Notice any files that were deleted before watching was started.
|
-- Notice any files that were deleted before watching was started.
|
||||||
|
|
|
@ -14,6 +14,7 @@ import Assistant.Common
|
||||||
import Assistant.ThreadedMonad
|
import Assistant.ThreadedMonad
|
||||||
import Assistant.DaemonStatus
|
import Assistant.DaemonStatus
|
||||||
import Assistant.TransferQueue
|
import Assistant.TransferQueue
|
||||||
|
import Assistant.Alert hiding (Widget)
|
||||||
import Utility.NotificationBroadcaster
|
import Utility.NotificationBroadcaster
|
||||||
import Utility.WebApp
|
import Utility.WebApp
|
||||||
import Utility.Yesod
|
import Utility.Yesod
|
||||||
|
@ -33,7 +34,7 @@ import Network.Socket (PortNumber)
|
||||||
import Text.Blaze.Renderer.String
|
import Text.Blaze.Renderer.String
|
||||||
import Data.Text (Text, pack, unpack)
|
import Data.Text (Text, pack, unpack)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Data.Time.Clock
|
import Data.Function
|
||||||
|
|
||||||
thisThread :: String
|
thisThread :: String
|
||||||
thisThread = "WebApp"
|
thisThread = "WebApp"
|
||||||
|
@ -151,14 +152,47 @@ getTransfersR nid = do
|
||||||
|
|
||||||
sideBarDisplay :: Bool -> Widget
|
sideBarDisplay :: Bool -> Widget
|
||||||
sideBarDisplay noScript = do
|
sideBarDisplay noScript = do
|
||||||
date <- liftIO $ show <$> getCurrentTime
|
let content = do
|
||||||
|
{- Any yesod message appears as the first alert. -}
|
||||||
|
maybe noop rendermessage =<< lift getMessage
|
||||||
|
|
||||||
|
{- Add newest 10 alerts to the sidebar. -}
|
||||||
|
webapp <- lift getYesod
|
||||||
|
alerts <- M.toList . alertMap
|
||||||
|
<$> liftIO (getDaemonStatus $ daemonStatus webapp)
|
||||||
|
mapM_ renderalert $
|
||||||
|
take 10 $ reverse $ sortBy (compare `on` fst) alerts
|
||||||
ident <- lift newIdent
|
ident <- lift newIdent
|
||||||
mmsg <- lift getMessage
|
|
||||||
$(widgetFile "sidebar")
|
$(widgetFile "sidebar")
|
||||||
|
|
||||||
unless noScript $ do
|
unless noScript $ do
|
||||||
{- Set up automatic updates of the sidebar. -}
|
{- Set up automatic updates of the sidebar
|
||||||
nid <- lift $ newNotifier transferNotifier
|
- when alerts come in. -}
|
||||||
|
nid <- lift $ newNotifier alertNotifier
|
||||||
autoUpdate ident (SideBarR nid) (10 :: Int) (10 :: Int)
|
autoUpdate ident (SideBarR nid) (10 :: Int) (10 :: Int)
|
||||||
|
where
|
||||||
|
bootstrapclass Activity = "alert-info"
|
||||||
|
bootstrapclass Warning = "alert"
|
||||||
|
bootstrapclass Error = "alert-error"
|
||||||
|
bootstrapclass Success = "alert-success"
|
||||||
|
bootstrapclass Message = "alert-info"
|
||||||
|
|
||||||
|
renderalert (alertid, alert) = addalert
|
||||||
|
(show alertid)
|
||||||
|
-- Activity alerts auto-close
|
||||||
|
(not noScript && alertClass alert /= Activity)
|
||||||
|
(alertBlockDisplay alert)
|
||||||
|
(bootstrapclass $ alertClass alert)
|
||||||
|
(alertHeader alert)
|
||||||
|
$ case alertMessage alert of
|
||||||
|
StringAlert s -> [whamlet|#{s}|]
|
||||||
|
WidgetAlert w -> w
|
||||||
|
|
||||||
|
rendermessage msg = addalert "yesodmessage" True False
|
||||||
|
"alert-info" Nothing [whamlet|#{msg}|]
|
||||||
|
|
||||||
|
addalert :: String -> Bool -> Bool -> Text -> Maybe String -> Widget -> Widget
|
||||||
|
addalert alertid closable block divclass heading widget = $(widgetFile "alert")
|
||||||
|
|
||||||
{- Called by client to get a sidebar display.
|
{- Called by client to get a sidebar display.
|
||||||
-
|
-
|
||||||
|
|
|
@ -1,18 +1,3 @@
|
||||||
<div .span3 ##{ident}>
|
<div .span3 ##{ident}>
|
||||||
<div .sidebar-nav>
|
<div .sidebar-nav>
|
||||||
$maybe msg <- mmsg
|
^{content}
|
||||||
<div .alert .alert-info>
|
|
||||||
<a .close data-dismiss="alert" href="#">×</a>
|
|
||||||
#{msg}
|
|
||||||
<div .alert .alert-info>
|
|
||||||
<a .close data-dismiss="alert" href="#">×</a>
|
|
||||||
<b>This is just a demo.</b> If this were not just a demo,
|
|
||||||
I'd not be filling this sidebar with silly alerts.
|
|
||||||
<div .alert .alert-success>
|
|
||||||
<a .close data-dismiss="alert" href="#">×</a>
|
|
||||||
<b>Well done!</b>
|
|
||||||
You successfully read this important alert message.
|
|
||||||
<div .alert .alert-error>
|
|
||||||
<a .close data-dismiss="alert" href="#">×</a>
|
|
||||||
<b>Whoops!</b>
|
|
||||||
Unable to connect to blah blah.. #{date}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue