2012-09-02 04:27:48 +00:00
|
|
|
{- git-annex assistant webapp core
|
2012-07-31 05:11:32 +00:00
|
|
|
-
|
|
|
|
- Copyright 2012 Joey Hess <joey@kitenet.net>
|
|
|
|
-
|
2012-09-24 18:48:47 +00:00
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
2012-07-31 05:11:32 +00:00
|
|
|
-}
|
|
|
|
|
|
|
|
{-# LANGUAGE TypeFamilies, QuasiQuotes, MultiParamTypeClasses, TemplateHaskell, OverloadedStrings, RankNTypes #-}
|
|
|
|
|
|
|
|
module Assistant.WebApp where
|
|
|
|
|
2012-09-02 04:27:48 +00:00
|
|
|
import Assistant.WebApp.Types
|
2012-07-31 05:11:32 +00:00
|
|
|
import Assistant.Common
|
|
|
|
import Assistant.DaemonStatus
|
|
|
|
import Utility.NotificationBroadcaster
|
|
|
|
import Utility.Yesod
|
2012-09-18 21:50:07 +00:00
|
|
|
import Locations.UserConfig
|
2012-07-31 05:11:32 +00:00
|
|
|
|
|
|
|
import Yesod
|
|
|
|
import Text.Hamlet
|
2012-09-02 04:27:48 +00:00
|
|
|
import Data.Text (Text)
|
2012-07-31 05:11:32 +00:00
|
|
|
import Control.Concurrent.STM
|
2012-09-08 23:57:15 +00:00
|
|
|
import Control.Concurrent
|
2012-07-31 05:11:32 +00:00
|
|
|
|
2012-07-31 06:30:26 +00:00
|
|
|
data NavBarItem = DashBoard | Config | About
|
|
|
|
deriving (Eq)
|
|
|
|
|
|
|
|
navBarName :: NavBarItem -> Text
|
|
|
|
navBarName DashBoard = "Dashboard"
|
|
|
|
navBarName Config = "Configuration"
|
|
|
|
navBarName About = "About"
|
|
|
|
|
|
|
|
navBarRoute :: NavBarItem -> Route WebApp
|
|
|
|
navBarRoute DashBoard = HomeR
|
|
|
|
navBarRoute Config = ConfigR
|
|
|
|
navBarRoute About = AboutR
|
2012-07-31 05:11:32 +00:00
|
|
|
|
2012-07-31 18:23:17 +00:00
|
|
|
defaultNavBar :: [NavBarItem]
|
|
|
|
defaultNavBar = [DashBoard, Config, About]
|
|
|
|
|
|
|
|
firstRunNavBar :: [NavBarItem]
|
|
|
|
firstRunNavBar = [Config, About]
|
|
|
|
|
|
|
|
selectNavBar :: Handler [NavBarItem]
|
|
|
|
selectNavBar = ifM (inFirstRun) (return firstRunNavBar, return defaultNavBar)
|
|
|
|
|
|
|
|
inFirstRun :: Handler Bool
|
2012-08-03 13:44:43 +00:00
|
|
|
inFirstRun = isNothing . relDir <$> getYesod
|
2012-07-31 06:30:26 +00:00
|
|
|
|
|
|
|
{- Used instead of defaultContent; highlights the current page if it's
|
|
|
|
- on the navbar. -}
|
|
|
|
bootstrap :: Maybe NavBarItem -> Widget -> Handler RepHtml
|
|
|
|
bootstrap navbaritem content = do
|
|
|
|
webapp <- getYesod
|
2012-07-31 18:23:17 +00:00
|
|
|
navbar <- map navdetails <$> selectNavBar
|
2012-07-31 06:30:26 +00:00
|
|
|
page <- widgetToPageContent $ do
|
|
|
|
addStylesheet $ StaticR css_bootstrap_css
|
|
|
|
addStylesheet $ StaticR css_bootstrap_responsive_css
|
|
|
|
addScript $ StaticR jquery_full_js
|
|
|
|
addScript $ StaticR js_bootstrap_dropdown_js
|
|
|
|
addScript $ StaticR js_bootstrap_modal_js
|
|
|
|
$(widgetFile "page")
|
|
|
|
hamletToRepHtml $(hamletFile $ hamletTemplate "bootstrap")
|
2012-07-31 18:23:17 +00:00
|
|
|
where
|
|
|
|
navdetails i = (navBarName i, navBarRoute i, Just i == navbaritem)
|
2012-07-31 06:30:26 +00:00
|
|
|
|
2012-07-31 05:11:32 +00:00
|
|
|
newWebAppState :: IO (TMVar WebAppState)
|
2012-09-18 21:50:07 +00:00
|
|
|
newWebAppState = do
|
|
|
|
otherrepos <- listOtherRepos
|
|
|
|
atomically $ newTMVar $ WebAppState
|
|
|
|
{ showIntro = True
|
|
|
|
, otherRepos = otherrepos }
|
2012-07-31 05:11:32 +00:00
|
|
|
|
2012-10-29 04:15:43 +00:00
|
|
|
getAssistantY :: forall sub a. (AssistantData -> a) -> GHandler sub WebApp a
|
|
|
|
getAssistantY f = f <$> (assistantData <$> getYesod)
|
|
|
|
|
2012-10-29 18:07:12 +00:00
|
|
|
runAssistantY :: forall sub a. (Assistant a) -> GHandler sub WebApp a
|
|
|
|
runAssistantY a = liftIO . runAssistant a =<< assistantData <$> getYesod
|
|
|
|
|
2012-07-31 05:11:32 +00:00
|
|
|
getWebAppState :: forall sub. GHandler sub WebApp WebAppState
|
|
|
|
getWebAppState = liftIO . atomically . readTMVar =<< webAppState <$> getYesod
|
|
|
|
|
|
|
|
modifyWebAppState :: forall sub. (WebAppState -> WebAppState) -> GHandler sub WebApp ()
|
|
|
|
modifyWebAppState a = go =<< webAppState <$> getYesod
|
|
|
|
where
|
|
|
|
go s = liftIO $ atomically $ do
|
|
|
|
v <- takeTMVar s
|
|
|
|
putTMVar s $ a v
|
|
|
|
|
2012-07-31 15:19:40 +00:00
|
|
|
{- Runs an Annex action from the webapp.
|
|
|
|
-
|
|
|
|
- When the webapp is run outside a git-annex repository, the fallback
|
|
|
|
- value is returned.
|
|
|
|
-}
|
|
|
|
runAnnex :: forall sub a. a -> Annex a -> GHandler sub WebApp a
|
2012-10-29 04:15:43 +00:00
|
|
|
runAnnex fallback a = ifM (noAnnex <$> getYesod)
|
|
|
|
( return fallback
|
2012-10-29 23:07:10 +00:00
|
|
|
, runAssistantY $ liftAnnex a
|
2012-10-29 04:15:43 +00:00
|
|
|
)
|
2012-07-31 15:19:40 +00:00
|
|
|
|
2012-07-31 05:11:32 +00:00
|
|
|
waitNotifier :: forall sub. (DaemonStatus -> NotificationBroadcaster) -> NotificationId -> GHandler sub WebApp ()
|
|
|
|
waitNotifier selector nid = do
|
|
|
|
notifier <- getNotifier selector
|
|
|
|
liftIO $ waitNotification $ notificationHandleFromId notifier nid
|
|
|
|
|
|
|
|
newNotifier :: forall sub. (DaemonStatus -> NotificationBroadcaster) -> GHandler sub WebApp NotificationId
|
|
|
|
newNotifier selector = do
|
|
|
|
notifier <- getNotifier selector
|
|
|
|
liftIO $ notificationHandleToId <$> newNotificationHandle notifier
|
|
|
|
|
|
|
|
getNotifier :: forall sub. (DaemonStatus -> NotificationBroadcaster) -> GHandler sub WebApp NotificationBroadcaster
|
2012-10-30 18:44:18 +00:00
|
|
|
getNotifier selector = selector <$> runAssistantY getDaemonStatus
|
2012-07-31 05:11:32 +00:00
|
|
|
|
2012-07-31 21:57:08 +00:00
|
|
|
{- Adds the auth parameter as a hidden field on a form. Must be put into
|
|
|
|
- every form. -}
|
|
|
|
webAppFormAuthToken :: Widget
|
|
|
|
webAppFormAuthToken = do
|
|
|
|
webapp <- lift getYesod
|
|
|
|
[whamlet|<input type="hidden" name="auth" value="#{secretToken webapp}">|]
|
2012-08-08 21:07:38 +00:00
|
|
|
|
2012-09-27 16:55:00 +00:00
|
|
|
{- A button with an icon, and maybe label or tooltip, that can be
|
|
|
|
- clicked to perform some action.
|
2012-08-08 21:07:38 +00:00
|
|
|
- With javascript, clicking it POSTs the Route, and remains on the same
|
|
|
|
- page.
|
|
|
|
- With noscript, clicking it GETs the Route. -}
|
2012-09-27 16:55:00 +00:00
|
|
|
actionButton :: Route WebApp -> (Maybe String) -> (Maybe String) -> String -> String -> Widget
|
|
|
|
actionButton route label tooltip buttonclass iconclass = $(widgetFile "actionbutton")
|
2012-09-08 23:57:15 +00:00
|
|
|
|
|
|
|
type UrlRenderFunc = Route WebApp -> [(Text, Text)] -> Text
|
|
|
|
type UrlRenderer = MVar (UrlRenderFunc)
|
|
|
|
|
|
|
|
newUrlRenderer :: IO UrlRenderer
|
|
|
|
newUrlRenderer = newEmptyMVar
|
|
|
|
|
|
|
|
setUrlRenderer :: UrlRenderer -> (UrlRenderFunc) -> IO ()
|
|
|
|
setUrlRenderer = putMVar
|
|
|
|
|
|
|
|
{- Blocks until the webapp is running and has called setUrlRenderer. -}
|
|
|
|
renderUrl :: UrlRenderer -> Route WebApp -> [(Text, Text)] -> IO Text
|
|
|
|
renderUrl urlrenderer route params = do
|
|
|
|
r <- readMVar urlrenderer
|
|
|
|
return $ r route params
|
2012-09-09 05:02:44 +00:00
|
|
|
|
|
|
|
{- Redirects back to the referring page, or if there's none, HomeR -}
|
|
|
|
redirectBack :: Handler ()
|
|
|
|
redirectBack = do
|
|
|
|
clearUltDest
|
|
|
|
setUltDestReferer
|
|
|
|
redirectUltDest HomeR
|
2012-09-18 21:50:07 +00:00
|
|
|
|
|
|
|
{- List of other known repsitories, and link to add a new one. -}
|
|
|
|
otherReposWidget :: Widget
|
|
|
|
otherReposWidget = do
|
|
|
|
repolist <- lift $ otherRepos <$> getWebAppState
|
|
|
|
$(widgetFile "otherrepos")
|
|
|
|
|
|
|
|
listOtherRepos :: IO [(String, String)]
|
|
|
|
listOtherRepos = do
|
|
|
|
f <- autoStartFile
|
2012-10-14 19:19:34 +00:00
|
|
|
dirs <- nub <$> ifM (doesFileExist f) ( lines <$> readFile f, return [])
|
2012-09-18 21:50:07 +00:00
|
|
|
names <- mapM relHome dirs
|
|
|
|
return $ sort $ zip names dirs
|