hledger-web 1.9.2 → 1.10
raw patch · 51 files changed
+1636/−1913 lines, 51 filesdep +case-insensitivedep +conduitdep +semigroupsdep −base-compatdep −hspecdep −parsecdep ~basedep ~hledgerdep ~hledger-libPVP ok
version bump matches the API change (PVP)
Dependencies added: case-insensitive, conduit, semigroups
Dependencies removed: base-compat, hspec, parsec, safe, yesod-test
Dependency ranges changed: base, hledger, hledger-lib, megaparsec
API changes (from Hackage documentation)
- Application: getApplicationDev :: IO (Int, Application)
- Application: instance Yesod.Core.Class.Dispatch.YesodDispatch Foundation.App
- Application: makeApplication :: WebOpts -> Journal -> AppConfig DefaultEnv Extra -> IO Application
- Application: makeFoundation :: AppConfig DefaultEnv Extra -> WebOpts -> IO App
- Foundation: App :: AppConfig DefaultEnv Extra -> Static -> Manager -> WebOpts -> IORef Journal -> App
- Foundation: MsgHello :: AppMessage
- Foundation: VD :: WebOpts -> AppRoute -> Maybe Html -> Day -> Journal -> String -> Query -> [QueryOpt] -> Query -> [QueryOpt] -> Bool -> Bool -> ViewData
- Foundation: [am] :: ViewData -> Query
- Foundation: [aopts] :: ViewData -> [QueryOpt]
- Foundation: [appJournal] :: App -> IORef Journal
- Foundation: [appOpts] :: App -> WebOpts
- Foundation: [getStatic] :: App -> Static
- Foundation: [here] :: ViewData -> AppRoute
- Foundation: [httpManager] :: App -> Manager
- Foundation: [j] :: ViewData -> Journal
- Foundation: [m] :: ViewData -> Query
- Foundation: [msg] :: ViewData -> Maybe Html
- Foundation: [opts] :: ViewData -> WebOpts
- Foundation: [q] :: ViewData -> String
- Foundation: [qopts] :: ViewData -> [QueryOpt]
- Foundation: [settings] :: App -> AppConfig DefaultEnv Extra
- Foundation: [showpostings] :: ViewData -> Bool
- Foundation: [showsidebar] :: ViewData -> Bool
- Foundation: [today] :: ViewData -> Day
- Foundation: addform :: Text -> ViewData -> HtmlUrl AppRoute
- Foundation: data App
- Foundation: data AppMessage
- Foundation: data ViewData
- Foundation: getExtra :: Handler Extra
- Foundation: getLastMessage :: Handler (Maybe Html)
- Foundation: getViewData :: Handler ViewData
- Foundation: instance GHC.Classes.Eq (Yesod.Routes.Class.Route Foundation.App)
- Foundation: instance GHC.Read.Read (Yesod.Routes.Class.Route Foundation.App)
- Foundation: instance GHC.Show.Show (Yesod.Routes.Class.Route Foundation.App)
- Foundation: instance GHC.Show.Show Foundation.ViewData
- Foundation: instance GHC.Show.Show Text.Blaze.Internal.Markup
- Foundation: instance Text.Shakespeare.I18N.RenderMessage Foundation.App Foundation.AppMessage
- Foundation: instance Text.Shakespeare.I18N.RenderMessage Foundation.App Yesod.Form.Types.FormMessage
- Foundation: instance Yesod.Core.Class.Yesod.Yesod Foundation.App
- Foundation: instance Yesod.Routes.Class.ParseRoute Foundation.App
- Foundation: instance Yesod.Routes.Class.RenderRoute Foundation.App
- Foundation: instance Yesod.Routes.Class.RouteAttrs Foundation.App
- Foundation: journalradio :: [FilePath] -> HtmlUrl AppRoute
- Foundation: journalselect :: [FilePath] -> HtmlUrl AppRoute
- Foundation: nullviewdata :: ViewData
- Foundation: resourcesApp :: [ResourceTree String]
- Foundation: type AppRoute = Route App
- Foundation: type Form x = Html -> MForm (HandlerFor App) (FormResult x, Widget)
- Foundation: type Handler = HandlerFor App
- Foundation: type Widget = WidgetFor App ()
- Foundation: viewdataWithDateAndParams :: Day -> String -> String -> String -> ViewData
- Handler.AddForm: AddForm :: Day -> Maybe Text -> Maybe Text -> AddForm
- Handler.AddForm: [addFormDate] :: AddForm -> Day
- Handler.AddForm: [addFormDescription] :: AddForm -> Maybe Text
- Handler.AddForm: [addFormJournalFile] :: AddForm -> Maybe Text
- Handler.AddForm: data AddForm
- Handler.AddForm: instance GHC.Show.Show Handler.AddForm.AddForm
- Handler.AddForm: postAddForm :: Handler Html
- Handler.Common: accountOnlyQuery :: AccountName -> String
- Handler.Common: accountQuery :: AccountName -> String
- Handler.Common: accountUrl :: AppRoute -> AccountName -> (AppRoute, [(Text, Text)])
- Handler.Common: balanceReportAsHtml :: WebOpts -> ViewData -> BalanceReport -> HtmlUrl AppRoute
- Handler.Common: helplink :: String -> String -> HtmlUrl AppRoute
- Handler.Common: hledgerLayout :: ViewData -> String -> HtmlUrl AppRoute -> HandlerFor App Html
- Handler.Common: mixedAmountAsHtml :: MixedAmount -> Html
- Handler.Common: nulltemplate :: HtmlUrl AppRoute
- Handler.Common: numberTransactionsReportItems :: [TransactionsReportItem] -> [(Int, Bool, Bool, Bool, TransactionsReportItem)]
- Handler.Common: searchform :: ViewData -> HtmlUrl AppRoute
- Handler.Common: sidebar :: ViewData -> HtmlUrl AppRoute
- Handler.Common: topbar :: ViewData -> HtmlUrl AppRoute
- Handler.JournalR: getJournalR :: Handler Html
- Handler.JournalR: journalTransactionsReportAsHtml :: WebOpts -> ViewData -> TransactionsReport -> HtmlUrl AppRoute
- Handler.JournalR: postJournalR :: Handler Html
- Handler.RegisterR: getRegisterR :: Handler Html
- Handler.RegisterR: postRegisterR :: Handler Html
- Handler.RegisterR: registerChartHtml :: [(CommoditySymbol, (String, [TransactionsReportItem]))] -> HtmlUrl AppRoute
- Handler.RegisterR: registerItemsHtml :: WebOpts -> ViewData -> TransactionsReport -> HtmlUrl AppRoute
- Handler.RegisterR: registerReportHtml :: WebOpts -> ViewData -> TransactionsReport -> HtmlUrl AppRoute
- Handler.RootR: getRootR :: Handler Html
- Handler.SidebarR: getSidebarR :: Handler Html
- Handler.Utils: dayToJsTimestamp :: Day -> Integer
- Handler.Utils: numbered :: [a] -> [(Int, a)]
- Hledger.Web.Main: withJournalDo' :: WebOpts -> (WebOpts -> Journal -> IO ()) -> IO ()
- Settings: Extra :: Text -> Maybe Text -> Maybe Text -> Extra
- Settings: [extraAnalytics] :: Extra -> Maybe Text
- Settings: [extraCopyright] :: Extra -> Text
- Settings: [extraStaticRoot] :: Extra -> Maybe Text
- Settings: data Extra
- Settings: defbaseurl :: String -> Int -> String
- Settings: defhost :: String
- Settings: defport :: Int
- Settings: hledgerorgurl :: String
- Settings: instance GHC.Show.Show Settings.Extra
- Settings: manualurl :: String
- Settings: parseExtra :: DefaultEnv -> Object -> Parser Extra
- Settings: staticDir :: FilePath
- Settings: staticRoot :: AppConfig DefaultEnv Extra -> Text
- Settings: widgetFile :: String -> Q Exp
- Settings: widgetFileSettings :: WidgetFileSettings
- Settings.Development: development :: Bool
- Settings.Development: production :: Bool
- Settings.StaticFiles: css_bootstrap_css :: StaticRoute
- Settings.StaticFiles: css_bootstrap_css_map :: StaticRoute
- Settings.StaticFiles: css_bootstrap_datepicker_standalone_min_css :: StaticRoute
- Settings.StaticFiles: css_bootstrap_min_css :: StaticRoute
- Settings.StaticFiles: css_bootstrap_theme_css :: StaticRoute
- Settings.StaticFiles: css_bootstrap_theme_css_map :: StaticRoute
- Settings.StaticFiles: css_bootstrap_theme_min_css :: StaticRoute
- Settings.StaticFiles: fonts_glyphicons_halflings_regular_eot :: StaticRoute
- Settings.StaticFiles: fonts_glyphicons_halflings_regular_svg :: StaticRoute
- Settings.StaticFiles: fonts_glyphicons_halflings_regular_ttf :: StaticRoute
- Settings.StaticFiles: fonts_glyphicons_halflings_regular_woff :: StaticRoute
- Settings.StaticFiles: hledger_css :: StaticRoute
- Settings.StaticFiles: hledger_js :: StaticRoute
- Settings.StaticFiles: js_bootstrap_datepicker_min_js :: StaticRoute
- Settings.StaticFiles: js_bootstrap_js :: StaticRoute
- Settings.StaticFiles: js_bootstrap_min_js :: StaticRoute
- Settings.StaticFiles: js_excanvas_js :: StaticRoute
- Settings.StaticFiles: js_excanvas_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_cookie_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_canvas_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_canvas_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_categories_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_categories_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_crosshair_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_crosshair_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_errorbars_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_errorbars_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_fillbetween_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_fillbetween_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_image_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_image_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_navigate_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_navigate_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_pie_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_pie_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_resize_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_resize_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_selection_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_selection_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_stack_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_stack_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_symbol_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_symbol_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_threshold_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_threshold_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_time_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_time_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_tooltip_js :: StaticRoute
- Settings.StaticFiles: js_jquery_flot_tooltip_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_hotkeys_js :: StaticRoute
- Settings.StaticFiles: js_jquery_js :: StaticRoute
- Settings.StaticFiles: js_jquery_min_js :: StaticRoute
- Settings.StaticFiles: js_jquery_url_js :: StaticRoute
- Settings.StaticFiles: js_typeahead_bundle_js :: StaticRoute
- Settings.StaticFiles: js_typeahead_bundle_min_js :: StaticRoute
- Settings.StaticFiles: staticSite :: IO Static
+ Hledger.Web.Application: instance Yesod.Core.Class.Dispatch.YesodDispatch Hledger.Web.Foundation.App
+ Hledger.Web.Application: makeApplication :: WebOpts -> Journal -> AppConfig DefaultEnv Extra -> IO Application
+ Hledger.Web.Application: makeFoundation :: AppConfig DefaultEnv Extra -> WebOpts -> IO App
+ Hledger.Web.Foundation: App :: AppConfig DefaultEnv Extra -> Static -> Manager -> WebOpts -> IORef Journal -> App
+ Hledger.Web.Foundation: VD :: WebOpts -> Day -> Journal -> Text -> Query -> [QueryOpt] -> [Capability] -> ViewData
+ Hledger.Web.Foundation: [appJournal] :: App -> IORef Journal
+ Hledger.Web.Foundation: [appOpts] :: App -> WebOpts
+ Hledger.Web.Foundation: [caps] :: ViewData -> [Capability]
+ Hledger.Web.Foundation: [getStatic] :: App -> Static
+ Hledger.Web.Foundation: [httpManager] :: App -> Manager
+ Hledger.Web.Foundation: [j] :: ViewData -> Journal
+ Hledger.Web.Foundation: [m] :: ViewData -> Query
+ Hledger.Web.Foundation: [opts] :: ViewData -> WebOpts
+ Hledger.Web.Foundation: [q] :: ViewData -> Text
+ Hledger.Web.Foundation: [qopts] :: ViewData -> [QueryOpt]
+ Hledger.Web.Foundation: [settings] :: App -> AppConfig DefaultEnv Extra
+ Hledger.Web.Foundation: [today] :: ViewData -> Day
+ Hledger.Web.Foundation: data App
+ Hledger.Web.Foundation: data ViewData
+ Hledger.Web.Foundation: getCurrentJournal :: IORef Journal -> CliOpts -> Day -> Handler (Journal, Maybe String)
+ Hledger.Web.Foundation: getViewData :: Handler ViewData
+ Hledger.Web.Foundation: instance GHC.Classes.Eq (Yesod.Routes.Class.Route Hledger.Web.Foundation.App)
+ Hledger.Web.Foundation: instance GHC.Read.Read (Yesod.Routes.Class.Route Hledger.Web.Foundation.App)
+ Hledger.Web.Foundation: instance GHC.Show.Show (Yesod.Routes.Class.Route Hledger.Web.Foundation.App)
+ Hledger.Web.Foundation: instance GHC.Show.Show Hledger.Web.Foundation.ViewData
+ Hledger.Web.Foundation: instance GHC.Show.Show Text.Blaze.Internal.Markup
+ Hledger.Web.Foundation: instance Text.Shakespeare.I18N.RenderMessage Hledger.Web.Foundation.App Yesod.Form.Types.FormMessage
+ Hledger.Web.Foundation: instance Yesod.Core.Class.Yesod.Yesod Hledger.Web.Foundation.App
+ Hledger.Web.Foundation: instance Yesod.Routes.Class.ParseRoute Hledger.Web.Foundation.App
+ Hledger.Web.Foundation: instance Yesod.Routes.Class.RenderRoute Hledger.Web.Foundation.App
+ Hledger.Web.Foundation: instance Yesod.Routes.Class.RouteAttrs Hledger.Web.Foundation.App
+ Hledger.Web.Foundation: resourcesApp :: [ResourceTree String]
+ Hledger.Web.Foundation: shouldShowSidebar :: Handler Bool
+ Hledger.Web.Foundation: type AppRoute = Route App
+ Hledger.Web.Foundation: type Form x = Html -> MForm (HandlerFor App) (FormResult x, Widget)
+ Hledger.Web.Foundation: type Handler = HandlerFor App
+ Hledger.Web.Foundation: type Widget = WidgetFor App ()
+ Hledger.Web.Handler.AddR: getAddR :: Handler ()
+ Hledger.Web.Handler.AddR: postAddR :: Handler ()
+ Hledger.Web.Handler.Common: getDownloadR :: FilePath -> Handler TypedContent
+ Hledger.Web.Handler.Common: getFaviconR :: MonadHandler m => m ()
+ Hledger.Web.Handler.Common: getManageR :: Handler Html
+ Hledger.Web.Handler.Common: getRobotsR :: MonadHandler m => m ()
+ Hledger.Web.Handler.Common: getRootR :: Handler Html
+ Hledger.Web.Handler.EditR: getEditR :: FilePath -> Handler ()
+ Hledger.Web.Handler.EditR: postEditR :: FilePath -> Handler ()
+ Hledger.Web.Handler.JournalR: getJournalR :: Handler Html
+ Hledger.Web.Handler.RegisterR: dayToJsTimestamp :: Day -> Integer
+ Hledger.Web.Handler.RegisterR: getRegisterR :: Handler Html
+ Hledger.Web.Handler.RegisterR: registerChartHtml :: [(CommoditySymbol, (String, [TransactionsReportItem]))] -> HtmlUrl AppRoute
+ Hledger.Web.Handler.UploadR: getUploadR :: FilePath -> Handler ()
+ Hledger.Web.Handler.UploadR: postUploadR :: FilePath -> Handler ()
+ Hledger.Web.Import: (!!) :: () => [a] -> Int -> a
+ Hledger.Web.Import: (!=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
+ Hledger.Web.Import: ($!) :: () => a -> b -> a -> b
+ Hledger.Web.Import: ($) :: () => a -> b -> a -> b
+ Hledger.Web.Import: (&&) :: Bool -> Bool -> Bool
+ Hledger.Web.Import: (*) :: Num a => a -> a -> a
+ Hledger.Web.Import: (**) :: Floating a => a -> a -> a
+ Hledger.Web.Import: (*=.) :: PersistField typ => EntityField v typ -> typ -> Update v
+ Hledger.Web.Import: (*>) :: Applicative f => f a -> f b -> f b
+ Hledger.Web.Import: (+) :: Num a => a -> a -> a
+ Hledger.Web.Import: (++) :: () => [a] -> [a] -> [a]
+ Hledger.Web.Import: (+=.) :: PersistField typ => EntityField v typ -> typ -> Update v
+ Hledger.Web.Import: (-) :: Num a => a -> a -> a
+ Hledger.Web.Import: (-=.) :: PersistField typ => EntityField v typ -> typ -> Update v
+ Hledger.Web.Import: (.) :: () => b -> c -> a -> b -> a -> c
+ Hledger.Web.Import: (.:) :: FromJSON a => Object -> Text -> Parser a
+ Hledger.Web.Import: (.=) :: (KeyValue kv, ToJSON v) => Text -> v -> kv
+ Hledger.Web.Import: (/) :: Fractional a => a -> a -> a
+ Hledger.Web.Import: (/<-.) :: PersistField typ => EntityField v typ -> [typ] -> Filter v
+ Hledger.Web.Import: (/=) :: Eq a => a -> a -> Bool
+ Hledger.Web.Import: (/=.) :: PersistField typ => EntityField v typ -> typ -> Update v
+ Hledger.Web.Import: (:#:) :: a -> b -> Fragment a b
+ Hledger.Web.Import: (<$!>) :: Monad m => a -> b -> m a -> m b
+ Hledger.Web.Import: (<$) :: Functor f => a -> f b -> f a
+ Hledger.Web.Import: (<$>) :: Functor f => a -> b -> f a -> f b
+ Hledger.Web.Import: (<) :: Ord a => a -> a -> Bool
+ Hledger.Web.Import: (<*) :: Applicative f => f a -> f b -> f a
+ Hledger.Web.Import: (<*>) :: Applicative f => f a -> b -> f a -> f b
+ Hledger.Web.Import: (<-.) :: PersistField typ => EntityField v typ -> [typ] -> Filter v
+ Hledger.Web.Import: (<.) :: PersistField typ => EntityField v typ -> typ -> Filter v
+ Hledger.Web.Import: (<=) :: Ord a => a -> a -> Bool
+ Hledger.Web.Import: (<=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
+ Hledger.Web.Import: (<=<) :: Monad m => b -> m c -> a -> m b -> a -> m c
+ Hledger.Web.Import: (<>) :: Semigroup a => a -> a -> a
+ Hledger.Web.Import: (=.) :: PersistField typ => EntityField v typ -> typ -> Update v
+ Hledger.Web.Import: (=<<) :: Monad m => a -> m b -> m a -> m b
+ Hledger.Web.Import: (==) :: Eq a => a -> a -> Bool
+ Hledger.Web.Import: (==.) :: PersistField typ => EntityField v typ -> typ -> Filter v
+ Hledger.Web.Import: (>) :: Ord a => a -> a -> Bool
+ Hledger.Web.Import: (>.) :: PersistField typ => EntityField v typ -> typ -> Filter v
+ Hledger.Web.Import: (>=) :: Ord a => a -> a -> Bool
+ Hledger.Web.Import: (>=.) :: PersistField typ => EntityField v typ -> typ -> Filter v
+ Hledger.Web.Import: (>=>) :: Monad m => a -> m b -> b -> m c -> a -> m c
+ Hledger.Web.Import: (>>) :: Monad m => m a -> m b -> m b
+ Hledger.Web.Import: (>>=) :: Monad m => m a -> a -> m b -> m b
+ Hledger.Web.Import: (^) :: (Num a, Integral b) => a -> b -> a
+ Hledger.Web.Import: (^^) :: (Fractional a, Integral b) => a -> b -> a
+ Hledger.Web.Import: (||) :: Bool -> Bool -> Bool
+ Hledger.Web.Import: (||.) :: () => [Filter v] -> [Filter v] -> [Filter v]
+ Hledger.Web.Import: AForm :: (HandlerSite m, [Text]) -> Maybe (Env, FileEnv) -> Ints -> m (FormResult a, [FieldView HandlerSite m] -> [FieldView HandlerSite m], Ints, Enctype) -> AForm a
+ Hledger.Web.Import: Active :: Checkmark
+ Hledger.Web.Import: Add :: PersistUpdate
+ Hledger.Web.Import: AddCookie :: !SetCookie -> Header
+ Hledger.Web.Import: App :: AppConfig DefaultEnv Extra -> Static -> Manager -> WebOpts -> IORef Journal -> App
+ Hledger.Web.Import: ApprootMaster :: !master -> Text -> Approot master
+ Hledger.Web.Import: ApprootRelative :: Approot master
+ Hledger.Web.Import: ApprootRequest :: !master -> Request -> Text -> Approot master
+ Hledger.Web.Import: ApprootStatic :: !Text -> Approot master
+ Hledger.Web.Import: Array :: !Array -> Value
+ Hledger.Web.Import: Assign :: PersistUpdate
+ Hledger.Web.Import: AuthenticationRequired :: AuthResult
+ Hledger.Web.Import: Authorized :: AuthResult
+ Hledger.Web.Import: BackendSpecificFilter :: Text -> PersistFilter
+ Hledger.Web.Import: BackendSpecificUpdate :: Text -> PersistUpdate
+ Hledger.Web.Import: BadMethod :: !Method -> ErrorResponse
+ Hledger.Web.Import: Bool :: !Bool -> Value
+ Hledger.Web.Import: BottomOfBody :: ScriptLoadPosition master
+ Hledger.Web.Import: BottomOfHeadAsync :: !BottomOfHeadAsync master -> ScriptLoadPosition master
+ Hledger.Web.Import: BottomOfHeadBlocking :: ScriptLoadPosition master
+ Hledger.Web.Import: ByMaybeAttr :: WhyNullable
+ Hledger.Web.Import: ByNullableAttr :: WhyNullable
+ Hledger.Web.Import: CapAdd :: Capability
+ Hledger.Web.Import: CapManage :: Capability
+ Hledger.Web.Import: CapView :: Capability
+ Hledger.Web.Import: CompositeDef :: ![FieldDef] -> ![Attr] -> CompositeDef
+ Hledger.Web.Import: CompositeRef :: CompositeDef -> ReferenceDef
+ Hledger.Web.Import: ContentBuilder :: !Builder -> !Maybe Int -> Content
+ Hledger.Web.Import: ContentDontEvaluate :: !Content -> Content
+ Hledger.Web.Import: ContentFile :: !FilePath -> !Maybe FilePart -> Content
+ Hledger.Web.Import: ContentSource :: !ConduitT () Flush Builder ResourceT IO () -> Content
+ Hledger.Web.Import: CssBuilder :: Builder -> CssBuilder
+ Hledger.Web.Import: DBName :: Text -> DBName
+ Hledger.Web.Import: DBRunner :: forall a. () => YesodDB site a -> HandlerFor site a -> DBRunner site
+ Hledger.Web.Import: DeleteCookie :: !ByteString -> !ByteString -> Header
+ Hledger.Web.Import: Divide :: PersistUpdate
+ Hledger.Web.Import: DontFullyEvaluate :: a -> DontFullyEvaluate a
+ Hledger.Web.Import: EQ :: Ordering
+ Hledger.Web.Import: EmbedEntityDef :: !HaskellName -> ![EmbedFieldDef] -> EmbedEntityDef
+ Hledger.Web.Import: EmbedFieldDef :: !DBName -> Maybe EmbedEntityDef -> Maybe HaskellName -> EmbedFieldDef
+ Hledger.Web.Import: EmbedRef :: EmbedEntityDef -> ReferenceDef
+ Hledger.Web.Import: Entity :: Key record -> record -> Entity record
+ Hledger.Web.Import: EntityDef :: !HaskellName -> !DBName -> !FieldDef -> ![Attr] -> ![FieldDef] -> ![UniqueDef] -> ![ForeignDef] -> ![Text] -> !Map Text [ExtraLine] -> !Bool -> EntityDef
+ Hledger.Web.Import: EntityJSON :: Name -> Name -> EntityJSON
+ Hledger.Web.Import: Eq :: PersistFilter
+ Hledger.Web.Import: Extra :: Text -> Maybe Text -> Maybe Text -> Extra
+ Hledger.Web.Import: FTApp :: FieldType -> FieldType -> FieldType
+ Hledger.Web.Import: FTList :: FieldType -> FieldType
+ Hledger.Web.Import: FTTypeCon :: Maybe Text -> Text -> FieldType
+ Hledger.Web.Import: False :: Bool
+ Hledger.Web.Import: Field :: [Text] -> [FileInfo] -> m Either SomeMessage HandlerSite m Maybe a -> FieldViewFunc m a -> Enctype -> Field a
+ Hledger.Web.Import: FieldDef :: !HaskellName -> !DBName -> !FieldType -> !SqlType -> ![Attr] -> !Bool -> !ReferenceDef -> FieldDef
+ Hledger.Web.Import: FieldSettings :: SomeMessage master -> Maybe SomeMessage master -> Maybe Text -> Maybe Text -> [(Text, Text)] -> FieldSettings master
+ Hledger.Web.Import: FieldView :: Markup -> Maybe Markup -> Text -> WidgetFor site () -> Maybe Markup -> Bool -> FieldView site
+ Hledger.Web.Import: FileUploadDisk :: !InternalState -> BackEnd FilePath -> FileUpload
+ Hledger.Web.Import: FileUploadMemory :: !BackEnd ByteString -> FileUpload
+ Hledger.Web.Import: FileUploadSource :: !BackEnd ConduitT () ByteString ResourceT IO () -> FileUpload
+ Hledger.Web.Import: ForeignDef :: !HaskellName -> !DBName -> !HaskellName -> !DBName -> ![(ForeignFieldDef, ForeignFieldDef)] -> ![Attr] -> Bool -> ForeignDef
+ Hledger.Web.Import: ForeignRef :: !HaskellName -> !FieldType -> ReferenceDef
+ Hledger.Web.Import: FormFailure :: [Text] -> FormResult a
+ Hledger.Web.Import: FormInput :: HandlerSite m -> [Text] -> Env -> FileEnv -> m Either DText a -> FormInput a
+ Hledger.Web.Import: FormMissing :: FormResult a
+ Hledger.Web.Import: FormSuccess :: a -> FormResult a
+ Hledger.Web.Import: GT :: Ordering
+ Hledger.Web.Import: Ge :: PersistFilter
+ Hledger.Web.Import: Gt :: PersistFilter
+ Hledger.Web.Import: HaskellName :: Text -> HaskellName
+ Hledger.Web.Import: Header :: !CI ByteString -> !ByteString -> Header
+ Hledger.Web.Import: In :: PersistFilter
+ Hledger.Web.Import: Inactive :: Checkmark
+ Hledger.Web.Import: IntCons :: Int -> Ints -> Ints
+ Hledger.Web.Import: IntSingle :: Int -> Ints
+ Hledger.Web.Import: InternalError :: !Text -> ErrorResponse
+ Hledger.Web.Import: InvalidArgs :: ![Text] -> ErrorResponse
+ Hledger.Web.Import: Just :: a -> Maybe a
+ Hledger.Web.Import: KeyNotFound :: String -> UpdateException
+ Hledger.Web.Import: LT :: Ordering
+ Hledger.Web.Import: Le :: PersistFilter
+ Hledger.Web.Import: Left :: a -> Either a b
+ Hledger.Web.Import: LevelDebug :: LogLevel
+ Hledger.Web.Import: LevelError :: LogLevel
+ Hledger.Web.Import: LevelInfo :: LogLevel
+ Hledger.Web.Import: LevelOther :: Text -> LogLevel
+ Hledger.Web.Import: LevelWarn :: LogLevel
+ Hledger.Web.Import: LiteApp :: Method -> [Text] -> Maybe LiteHandler TypedContent -> LiteApp
+ Hledger.Web.Import: LocalTime :: Day -> TimeOfDay -> LocalTime
+ Hledger.Web.Import: Lt :: PersistFilter
+ Hledger.Web.Import: ModJulianDate :: Rational -> UniversalTime
+ Hledger.Web.Import: ModifiedJulianDay :: Integer -> Day
+ Hledger.Web.Import: MsgBoolNo :: FormMessage
+ Hledger.Web.Import: MsgBoolYes :: FormMessage
+ Hledger.Web.Import: MsgCsrfWarning :: FormMessage
+ Hledger.Web.Import: MsgDelete :: FormMessage
+ Hledger.Web.Import: MsgInputNotFound :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidBool :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidDay :: FormMessage
+ Hledger.Web.Import: MsgInvalidEmail :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidEntry :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidHour :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidInteger :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidMinute :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidNumber :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidSecond :: Text -> FormMessage
+ Hledger.Web.Import: MsgInvalidTimeFormat :: FormMessage
+ Hledger.Web.Import: MsgInvalidUrl :: Text -> FormMessage
+ Hledger.Web.Import: MsgSelectNone :: FormMessage
+ Hledger.Web.Import: MsgValueRequired :: FormMessage
+ Hledger.Web.Import: Multipart :: Enctype
+ Hledger.Web.Import: Multiply :: PersistUpdate
+ Hledger.Web.Import: Ne :: PersistFilter
+ Hledger.Web.Import: NoReference :: ReferenceDef
+ Hledger.Web.Import: NotAuthenticated :: ErrorResponse
+ Hledger.Web.Import: NotFound :: ErrorResponse
+ Hledger.Web.Import: NotIn :: PersistFilter
+ Hledger.Web.Import: NotNullable :: IsNullable
+ Hledger.Web.Import: Nothing :: Maybe a
+ Hledger.Web.Import: Null :: Value
+ Hledger.Web.Import: Nullable :: !WhyNullable -> IsNullable
+ Hledger.Web.Import: Number :: !Scientific -> Value
+ Hledger.Web.Import: Object :: !Object -> Value
+ Hledger.Web.Import: OnlyUniqueException :: String -> OnlyUniqueException
+ Hledger.Web.Import: Option :: Text -> a -> Text -> Option a
+ Hledger.Web.Import: OptionList :: [Option a] -> Text -> Maybe a -> OptionList a
+ Hledger.Web.Import: PageContent :: !Html -> !HtmlUrl url -> !HtmlUrl url -> PageContent url
+ Hledger.Web.Import: PermissionDenied :: !Text -> ErrorResponse
+ Hledger.Web.Import: PersistBool :: Bool -> PersistValue
+ Hledger.Web.Import: PersistByteString :: ByteString -> PersistValue
+ Hledger.Web.Import: PersistDay :: Day -> PersistValue
+ Hledger.Web.Import: PersistDbSpecific :: ByteString -> PersistValue
+ Hledger.Web.Import: PersistDouble :: Double -> PersistValue
+ Hledger.Web.Import: PersistError :: Text -> PersistException
+ Hledger.Web.Import: PersistForeignConstraintUnmet :: Text -> PersistException
+ Hledger.Web.Import: PersistInt64 :: Int64 -> PersistValue
+ Hledger.Web.Import: PersistInvalidField :: Text -> PersistException
+ Hledger.Web.Import: PersistList :: [PersistValue] -> PersistValue
+ Hledger.Web.Import: PersistMap :: [(Text, PersistValue)] -> PersistValue
+ Hledger.Web.Import: PersistMarshalError :: Text -> PersistException
+ Hledger.Web.Import: PersistMongoDBError :: Text -> PersistException
+ Hledger.Web.Import: PersistMongoDBUnsupported :: Text -> PersistException
+ Hledger.Web.Import: PersistNull :: PersistValue
+ Hledger.Web.Import: PersistObjectId :: ByteString -> PersistValue
+ Hledger.Web.Import: PersistRational :: Rational -> PersistValue
+ Hledger.Web.Import: PersistText :: Text -> PersistValue
+ Hledger.Web.Import: PersistTimeOfDay :: TimeOfDay -> PersistValue
+ Hledger.Web.Import: PersistUTCTime :: UTCTime -> PersistValue
+ Hledger.Web.Import: RepJson :: Content -> RepJson
+ Hledger.Web.Import: RepPlain :: Content -> RepPlain
+ Hledger.Web.Import: RepXml :: Content -> RepXml
+ Hledger.Web.Import: Right :: b -> Either a b
+ Hledger.Web.Import: SelfReference :: ReferenceDef
+ Hledger.Web.Import: SessionBackend :: Request -> IO (SessionMap, SaveSession) -> SessionBackend
+ Hledger.Web.Import: SqlBlob :: SqlType
+ Hledger.Web.Import: SqlBool :: SqlType
+ Hledger.Web.Import: SqlDay :: SqlType
+ Hledger.Web.Import: SqlDayTime :: SqlType
+ Hledger.Web.Import: SqlInt32 :: SqlType
+ Hledger.Web.Import: SqlInt64 :: SqlType
+ Hledger.Web.Import: SqlNumeric :: Word32 -> Word32 -> SqlType
+ Hledger.Web.Import: SqlOther :: Text -> SqlType
+ Hledger.Web.Import: SqlReal :: SqlType
+ Hledger.Web.Import: SqlString :: SqlType
+ Hledger.Web.Import: SqlTime :: SqlType
+ Hledger.Web.Import: String :: !Text -> Value
+ Hledger.Web.Import: Subtract :: PersistUpdate
+ Hledger.Web.Import: Textarea :: Text -> Textarea
+ Hledger.Web.Import: TimeLocale :: [(String, String)] -> [(String, String)] -> (String, String) -> String -> String -> String -> String -> [TimeZone] -> TimeLocale
+ Hledger.Web.Import: TimeOfDay :: Int -> Int -> Pico -> TimeOfDay
+ Hledger.Web.Import: TimeZone :: Int -> Bool -> String -> TimeZone
+ Hledger.Web.Import: True :: Bool
+ Hledger.Web.Import: TypedContent :: !ContentType -> !Content -> TypedContent
+ Hledger.Web.Import: UTCTime :: Day -> DiffTime -> UTCTime
+ Hledger.Web.Import: Unauthorized :: !Text -> AuthResult
+ Hledger.Web.Import: UniqueDef :: !HaskellName -> !DBName -> ![(HaskellName, DBName)] -> ![Attr] -> UniqueDef
+ Hledger.Web.Import: UpsertError :: String -> UpdateException
+ Hledger.Web.Import: UrlEncoded :: Enctype
+ Hledger.Web.Import: VD :: WebOpts -> Day -> Journal -> Text -> Query -> [QueryOpt] -> [Capability] -> ViewData
+ Hledger.Web.Import: WaiSubsite :: Application -> WaiSubsite
+ Hledger.Web.Import: WaiSubsiteWithAuth :: Application -> WaiSubsiteWithAuth
+ Hledger.Web.Import: YesodRequest :: ![(Text, Text)] -> ![(Text, Text)] -> !Request -> ![Text] -> !Maybe Text -> !SessionMap -> ![ContentType] -> YesodRequest
+ Hledger.Web.Import: ZonedTime :: LocalTime -> TimeZone -> ZonedTime
+ Hledger.Web.Import: [Asc] :: SelectOpt record
+ Hledger.Web.Import: [BackendFilter] :: Filter record
+ Hledger.Web.Import: [BackendUpdate] :: Update record
+ Hledger.Web.Import: [Desc] :: SelectOpt record
+ Hledger.Web.Import: [FilterAnd] :: Filter record
+ Hledger.Web.Import: [FilterOr] :: Filter record
+ Hledger.Web.Import: [Filter] :: Filter record
+ Hledger.Web.Import: [LimitTo] :: SelectOpt record
+ Hledger.Web.Import: [OffsetBy] :: SelectOpt record
+ Hledger.Web.Import: [SomeMessage] :: SomeMessage master
+ Hledger.Web.Import: [SomePersistField] :: SomePersistField
+ Hledger.Web.Import: [Update] :: Update record
+ Hledger.Web.Import: [amPm] :: TimeLocale -> (String, String)
+ Hledger.Web.Import: [appJournal] :: App -> IORef Journal
+ Hledger.Web.Import: [appOpts] :: App -> WebOpts
+ Hledger.Web.Import: [caps] :: ViewData -> [Capability]
+ Hledger.Web.Import: [compositeAttrs] :: CompositeDef -> ![Attr]
+ Hledger.Web.Import: [compositeFields] :: CompositeDef -> ![FieldDef]
+ Hledger.Web.Import: [dateFmt] :: TimeLocale -> String
+ Hledger.Web.Import: [dateTimeFmt] :: TimeLocale -> String
+ Hledger.Web.Import: [emFieldCycle] :: EmbedFieldDef -> Maybe HaskellName
+ Hledger.Web.Import: [emFieldDB] :: EmbedFieldDef -> !DBName
+ Hledger.Web.Import: [emFieldEmbed] :: EmbedFieldDef -> Maybe EmbedEntityDef
+ Hledger.Web.Import: [embeddedFields] :: EmbedEntityDef -> ![EmbedFieldDef]
+ Hledger.Web.Import: [embeddedHaskell] :: EmbedEntityDef -> !HaskellName
+ Hledger.Web.Import: [entityAttrs] :: EntityDef -> ![Attr]
+ Hledger.Web.Import: [entityDB] :: EntityDef -> !DBName
+ Hledger.Web.Import: [entityDerives] :: EntityDef -> ![Text]
+ Hledger.Web.Import: [entityExtra] :: EntityDef -> !Map Text [ExtraLine]
+ Hledger.Web.Import: [entityFields] :: EntityDef -> ![FieldDef]
+ Hledger.Web.Import: [entityForeigns] :: EntityDef -> ![ForeignDef]
+ Hledger.Web.Import: [entityFromJSON] :: EntityJSON -> Name
+ Hledger.Web.Import: [entityHaskell] :: EntityDef -> !HaskellName
+ Hledger.Web.Import: [entityId] :: EntityDef -> !FieldDef
+ Hledger.Web.Import: [entityKey] :: Entity record -> Key record
+ Hledger.Web.Import: [entitySum] :: EntityDef -> !Bool
+ Hledger.Web.Import: [entityToJSON] :: EntityJSON -> Name
+ Hledger.Web.Import: [entityUniques] :: EntityDef -> ![UniqueDef]
+ Hledger.Web.Import: [entityVal] :: Entity record -> record
+ Hledger.Web.Import: [extraAnalytics] :: Extra -> Maybe Text
+ Hledger.Web.Import: [extraCopyright] :: Extra -> Text
+ Hledger.Web.Import: [extraStaticRoot] :: Extra -> Maybe Text
+ Hledger.Web.Import: [fieldAttrs] :: FieldDef -> ![Attr]
+ Hledger.Web.Import: [fieldDB] :: FieldDef -> !DBName
+ Hledger.Web.Import: [fieldEnctype] :: Field a -> Enctype
+ Hledger.Web.Import: [fieldHaskell] :: FieldDef -> !HaskellName
+ Hledger.Web.Import: [fieldParse] :: Field a -> [Text] -> [FileInfo] -> m Either SomeMessage HandlerSite m Maybe a
+ Hledger.Web.Import: [fieldReference] :: FieldDef -> !ReferenceDef
+ Hledger.Web.Import: [fieldSqlType] :: FieldDef -> !SqlType
+ Hledger.Web.Import: [fieldStrict] :: FieldDef -> !Bool
+ Hledger.Web.Import: [fieldType] :: FieldDef -> !FieldType
+ Hledger.Web.Import: [fieldView] :: Field a -> FieldViewFunc m a
+ Hledger.Web.Import: [foreignAttrs] :: ForeignDef -> ![Attr]
+ Hledger.Web.Import: [foreignConstraintNameDBName] :: ForeignDef -> !DBName
+ Hledger.Web.Import: [foreignConstraintNameHaskell] :: ForeignDef -> !HaskellName
+ Hledger.Web.Import: [foreignFields] :: ForeignDef -> ![(ForeignFieldDef, ForeignFieldDef)]
+ Hledger.Web.Import: [foreignNullable] :: ForeignDef -> Bool
+ Hledger.Web.Import: [foreignRefTableDBName] :: ForeignDef -> !DBName
+ Hledger.Web.Import: [foreignRefTableHaskell] :: ForeignDef -> !HaskellName
+ Hledger.Web.Import: [fsAttrs] :: FieldSettings master -> [(Text, Text)]
+ Hledger.Web.Import: [fsId] :: FieldSettings master -> Maybe Text
+ Hledger.Web.Import: [fsLabel] :: FieldSettings master -> SomeMessage master
+ Hledger.Web.Import: [fsName] :: FieldSettings master -> Maybe Text
+ Hledger.Web.Import: [fsTooltip] :: FieldSettings master -> Maybe SomeMessage master
+ Hledger.Web.Import: [fvErrors] :: FieldView site -> Maybe Markup
+ Hledger.Web.Import: [fvId] :: FieldView site -> Text
+ Hledger.Web.Import: [fvInput] :: FieldView site -> WidgetFor site ()
+ Hledger.Web.Import: [fvLabel] :: FieldView site -> Markup
+ Hledger.Web.Import: [fvRequired] :: FieldView site -> Bool
+ Hledger.Web.Import: [fvTooltip] :: FieldView site -> Maybe Markup
+ Hledger.Web.Import: [getModJulianDate] :: UniversalTime -> Rational
+ Hledger.Web.Import: [getStatic] :: App -> Static
+ Hledger.Web.Import: [httpManager] :: App -> Manager
+ Hledger.Web.Import: [j] :: ViewData -> Journal
+ Hledger.Web.Import: [knownTimeZones] :: TimeLocale -> [TimeZone]
+ Hledger.Web.Import: [localDay] :: LocalTime -> Day
+ Hledger.Web.Import: [localTimeOfDay] :: LocalTime -> TimeOfDay
+ Hledger.Web.Import: [m] :: ViewData -> Query
+ Hledger.Web.Import: [months] :: TimeLocale -> [(String, String)]
+ Hledger.Web.Import: [olOptions] :: OptionList a -> [Option a]
+ Hledger.Web.Import: [olReadExternal] :: OptionList a -> Text -> Maybe a
+ Hledger.Web.Import: [optionDisplay] :: Option a -> Text
+ Hledger.Web.Import: [optionExternalValue] :: Option a -> Text
+ Hledger.Web.Import: [optionInternalValue] :: Option a -> a
+ Hledger.Web.Import: [opts] :: ViewData -> WebOpts
+ Hledger.Web.Import: [pageBody] :: PageContent url -> !HtmlUrl url
+ Hledger.Web.Import: [pageHead] :: PageContent url -> !HtmlUrl url
+ Hledger.Web.Import: [pageTitle] :: PageContent url -> !Html
+ Hledger.Web.Import: [q] :: ViewData -> Text
+ Hledger.Web.Import: [qopts] :: ViewData -> [QueryOpt]
+ Hledger.Web.Import: [reqAccept] :: YesodRequest -> ![ContentType]
+ Hledger.Web.Import: [reqCookies] :: YesodRequest -> ![(Text, Text)]
+ Hledger.Web.Import: [reqGetParams] :: YesodRequest -> ![(Text, Text)]
+ Hledger.Web.Import: [reqLangs] :: YesodRequest -> ![Text]
+ Hledger.Web.Import: [reqSession] :: YesodRequest -> !SessionMap
+ Hledger.Web.Import: [reqToken] :: YesodRequest -> !Maybe Text
+ Hledger.Web.Import: [reqWaiRequest] :: YesodRequest -> !Request
+ Hledger.Web.Import: [runDBRunner] :: DBRunner site -> forall a. () => YesodDB site a -> HandlerFor site a
+ Hledger.Web.Import: [runWaiSubsiteWithAuth] :: WaiSubsiteWithAuth -> Application
+ Hledger.Web.Import: [runWaiSubsite] :: WaiSubsite -> Application
+ Hledger.Web.Import: [sbLoadSession] :: SessionBackend -> Request -> IO (SessionMap, SaveSession)
+ Hledger.Web.Import: [settings] :: App -> AppConfig DefaultEnv Extra
+ Hledger.Web.Import: [time12Fmt] :: TimeLocale -> String
+ Hledger.Web.Import: [timeFmt] :: TimeLocale -> String
+ Hledger.Web.Import: [timeZoneMinutes] :: TimeZone -> Int
+ Hledger.Web.Import: [timeZoneName] :: TimeZone -> String
+ Hledger.Web.Import: [timeZoneSummerOnly] :: TimeZone -> Bool
+ Hledger.Web.Import: [toModifiedJulianDay] :: Day -> Integer
+ Hledger.Web.Import: [todHour] :: TimeOfDay -> Int
+ Hledger.Web.Import: [todMin] :: TimeOfDay -> Int
+ Hledger.Web.Import: [todSec] :: TimeOfDay -> Pico
+ Hledger.Web.Import: [today] :: ViewData -> Day
+ Hledger.Web.Import: [unAForm] :: AForm a -> (HandlerSite m, [Text]) -> Maybe (Env, FileEnv) -> Ints -> m (FormResult a, [FieldView HandlerSite m] -> [FieldView HandlerSite m], Ints, Enctype)
+ Hledger.Web.Import: [unCssBuilder] :: CssBuilder -> Builder
+ Hledger.Web.Import: [unDBName] :: DBName -> Text
+ Hledger.Web.Import: [unDontFullyEvaluate] :: DontFullyEvaluate a -> a
+ Hledger.Web.Import: [unFormInput] :: FormInput a -> HandlerSite m -> [Text] -> Env -> FileEnv -> m Either DText a
+ Hledger.Web.Import: [unHaskellName] :: HaskellName -> Text
+ Hledger.Web.Import: [unLiteApp] :: LiteApp -> Method -> [Text] -> Maybe LiteHandler TypedContent
+ Hledger.Web.Import: [unTextarea] :: Textarea -> Text
+ Hledger.Web.Import: [uniqueAttrs] :: UniqueDef -> ![Attr]
+ Hledger.Web.Import: [uniqueDBName] :: UniqueDef -> !DBName
+ Hledger.Web.Import: [uniqueFields] :: UniqueDef -> ![(HaskellName, DBName)]
+ Hledger.Web.Import: [uniqueHaskell] :: UniqueDef -> !HaskellName
+ Hledger.Web.Import: [utctDayTime] :: UTCTime -> DiffTime
+ Hledger.Web.Import: [utctDay] :: UTCTime -> Day
+ Hledger.Web.Import: [wDays] :: TimeLocale -> [(String, String)]
+ Hledger.Web.Import: [zonedTimeToLocalTime] :: ZonedTime -> LocalTime
+ Hledger.Web.Import: [zonedTimeZone] :: ZonedTime -> TimeZone
+ Hledger.Web.Import: aFormToForm :: (Monad m, HandlerSite m ~ site) => AForm m a -> MForm m (FormResult a, [FieldView site] -> [FieldView site])
+ Hledger.Web.Import: abs :: Num a => a -> a
+ Hledger.Web.Import: acceptsJson :: MonadHandler m => m Bool
+ Hledger.Web.Import: acos :: Floating a => a -> a
+ Hledger.Web.Import: acosh :: Floating a => a -> a
+ Hledger.Web.Import: addContentDispositionFileName :: MonadHandler m => Text -> m ()
+ Hledger.Web.Import: addDays :: Integer -> Day -> Day
+ Hledger.Web.Import: addGregorianMonthsClip :: Integer -> Day -> Day
+ Hledger.Web.Import: addGregorianMonthsRollOver :: Integer -> Day -> Day
+ Hledger.Web.Import: addGregorianYearsClip :: Integer -> Day -> Day
+ Hledger.Web.Import: addGregorianYearsRollOver :: Integer -> Day -> Day
+ Hledger.Web.Import: addHeader :: MonadHandler m => Text -> Text -> m ()
+ Hledger.Web.Import: addMessage :: MonadHandler m => Text -> Html -> m ()
+ Hledger.Web.Import: addMessageI :: (MonadHandler m, RenderMessage HandlerSite m msg) => Text -> msg -> m ()
+ Hledger.Web.Import: addScript :: MonadWidget m => Route HandlerSite m -> m ()
+ Hledger.Web.Import: addScriptAttrs :: MonadWidget m => Route HandlerSite m -> [(Text, Text)] -> m ()
+ Hledger.Web.Import: addScriptEither :: MonadWidget m => Either Route HandlerSite m Text -> m ()
+ Hledger.Web.Import: addScriptRemote :: MonadWidget m => Text -> m ()
+ Hledger.Web.Import: addScriptRemoteAttrs :: MonadWidget m => Text -> [(Text, Text)] -> m ()
+ Hledger.Web.Import: addStaticContent :: Yesod site => Text -> Text -> ByteString -> HandlerFor site Maybe Either Text (Route site, [(Text, Text)])
+ Hledger.Web.Import: addStylesheet :: MonadWidget m => Route HandlerSite m -> m ()
+ Hledger.Web.Import: addStylesheetAttrs :: MonadWidget m => Route HandlerSite m -> [(Text, Text)] -> m ()
+ Hledger.Web.Import: addStylesheetEither :: MonadWidget m => Either Route HandlerSite m Text -> m ()
+ Hledger.Web.Import: addStylesheetRemote :: MonadWidget m => Text -> m ()
+ Hledger.Web.Import: addStylesheetRemoteAttrs :: MonadWidget m => Text -> [(Text, Text)] -> m ()
+ Hledger.Web.Import: addUTCTime :: NominalDiffTime -> UTCTime -> UTCTime
+ Hledger.Web.Import: all :: Foldable t => a -> Bool -> t a -> Bool
+ Hledger.Web.Import: alreadyExpired :: MonadHandler m => m ()
+ Hledger.Web.Import: and :: Foldable t => t Bool -> Bool
+ Hledger.Web.Import: any :: Foldable t => a -> Bool -> t a -> Bool
+ Hledger.Web.Import: aopt :: MonadHandler m => Field m a -> FieldSettings HandlerSite m -> Maybe Maybe a -> AForm m Maybe a
+ Hledger.Web.Import: ap :: Monad m => m a -> b -> m a -> m b
+ Hledger.Web.Import: appendFile :: FilePath -> String -> IO ()
+ Hledger.Web.Import: applyEnv :: PersistConfig c => c -> IO c
+ Hledger.Web.Import: approot :: Yesod site => Approot site
+ Hledger.Web.Import: areq :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m) => Field m a -> FieldSettings site -> Maybe a -> AForm m a
+ Hledger.Web.Import: array :: ToJSON a => [a] -> Value
+ Hledger.Web.Import: asTypeOf :: () => a -> a -> a
+ Hledger.Web.Import: asWidgetT :: () => WidgetT site m () -> WidgetT site m ()
+ Hledger.Web.Import: asin :: Floating a => a -> a
+ Hledger.Web.Import: asinh :: Floating a => a -> a
+ Hledger.Web.Import: askFiles :: Monad m => MForm m Maybe FileEnv
+ Hledger.Web.Import: askParams :: Monad m => MForm m Maybe Env
+ Hledger.Web.Import: askUnliftIO :: MonadUnliftIO m => m UnliftIO m
+ Hledger.Web.Import: asum :: (Foldable t, Alternative f) => t f a -> f a
+ Hledger.Web.Import: atan :: Floating a => a -> a
+ Hledger.Web.Import: atan2 :: RealFloat a => a -> a -> a
+ Hledger.Web.Import: atanh :: Floating a => a -> a
+ Hledger.Web.Import: authRoute :: Yesod site => site -> Maybe Route site
+ Hledger.Web.Import: authorizationCheck :: Yesod site => HandlerFor site ()
+ Hledger.Web.Import: badMethod :: MonadHandler m => m a
+ Hledger.Web.Import: belongsTo :: (PersistStoreRead backend, PersistEntity ent1, PersistRecordBackend ent2 backend, MonadIO m) => ent1 -> Maybe Key ent2 -> ent1 -> ReaderT backend m Maybe ent2
+ Hledger.Web.Import: belongsToJust :: (PersistStoreRead backend, PersistEntity ent1, PersistRecordBackend ent2 backend, MonadIO m) => ent1 -> Key ent2 -> ent1 -> ReaderT backend m ent2
+ Hledger.Web.Import: bimap :: Bifunctor p => a -> b -> c -> d -> p a c -> p b d
+ Hledger.Web.Import: boolField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Bool
+ Hledger.Web.Import: breadcrumb :: YesodBreadcrumbs site => Route site -> HandlerFor site (Text, Maybe Route site)
+ Hledger.Web.Import: breadcrumbs :: YesodBreadcrumbs site => HandlerFor site (Text, [(Route site, Text)])
+ Hledger.Web.Import: break :: () => a -> Bool -> [a] -> ([a], [a])
+ Hledger.Web.Import: buildTime :: ParseTime t => TimeLocale -> [(Char, String)] -> Maybe t
+ Hledger.Web.Import: cacheSeconds :: MonadHandler m => Int -> m ()
+ Hledger.Web.Import: cached :: (MonadHandler m, Typeable a) => m a -> m a
+ Hledger.Web.Import: cachedBy :: (MonadHandler m, Typeable a) => ByteString -> m a -> m a
+ Hledger.Web.Import: cassius :: QuasiQuoter
+ Hledger.Web.Import: catMaybes :: () => [Maybe a] -> [a]
+ Hledger.Web.Import: ceiling :: (RealFrac a, Integral b) => a -> b
+ Hledger.Web.Import: check :: (Monad m, RenderMessage HandlerSite m msg) => a -> Either msg a -> Field m a -> Field m a
+ Hledger.Web.Import: checkBool :: (Monad m, RenderMessage HandlerSite m msg) => a -> Bool -> msg -> Field m a -> Field m a
+ Hledger.Web.Import: checkBoxField :: Monad m => Field m Bool
+ Hledger.Web.Import: checkCsrfHeaderNamed :: MonadHandler m => CI ByteString -> m ()
+ Hledger.Web.Import: checkCsrfHeaderOrParam :: (MonadHandler m, MonadLogger m) => CI ByteString -> Text -> m ()
+ Hledger.Web.Import: checkCsrfParamNamed :: MonadHandler m => Text -> m ()
+ Hledger.Web.Import: checkM :: (Monad m, RenderMessage HandlerSite m msg) => a -> m Either msg a -> Field m a -> Field m a
+ Hledger.Web.Import: checkMMap :: (Monad m, RenderMessage HandlerSite m msg) => a -> m Either msg b -> b -> a -> Field m a -> Field m b
+ Hledger.Web.Import: checkUnique :: (MonadIO m, PersistRecordBackend record backend, PersistUniqueRead backend) => record -> ReaderT backend m Maybe Unique record
+ Hledger.Web.Import: checkboxesField :: Eq a => HandlerFor site OptionList a -> Field HandlerFor site [a]
+ Hledger.Web.Import: checkboxesFieldList :: (Eq a, RenderMessage site msg) => [(msg, a)] -> Field HandlerFor site [a]
+ Hledger.Web.Import: class Functor f => Applicative (f :: * -> *)
+ Hledger.Web.Import: class BackendCompatible sup sub
+ Hledger.Web.Import: class Bifunctor (p :: * -> * -> *)
+ Hledger.Web.Import: class Bounded a
+ Hledger.Web.Import: class Default a
+ Hledger.Web.Import: class (PersistStoreWrite backend, PersistEntity record, BaseBackend backend ~ PersistEntityBackend record) => DeleteCascade record backend
+ Hledger.Web.Import: class Enum a
+ Hledger.Web.Import: class Eq a
+ Hledger.Web.Import: class Fractional a => Floating a
+ Hledger.Web.Import: class Foldable (t :: * -> *)
+ Hledger.Web.Import: class FormatTime t
+ Hledger.Web.Import: class Num a => Fractional a
+ Hledger.Web.Import: class FromJSON a
+ Hledger.Web.Import: class Functor (f :: * -> *)
+ Hledger.Web.Import: class ToTypedContent a => HasContentType a
+ Hledger.Web.Import: class HasPersistBackend backend where {
+ Hledger.Web.Import: class (Real a, Enum a) => Integral a
+ Hledger.Web.Import: class HasPersistBackend backend => IsPersistBackend backend
+ Hledger.Web.Import: class Applicative m => Monad (m :: * -> *)
+ Hledger.Web.Import: class (MonadResource m, MonadLogger m) => MonadHandler (m :: * -> *) where {
+ Hledger.Web.Import: class Monad m => MonadIO (m :: * -> *)
+ Hledger.Web.Import: class Monad m => MonadLogger (m :: * -> *)
+ Hledger.Web.Import: class (Alternative m, Monad m) => MonadPlus (m :: * -> *)
+ Hledger.Web.Import: class MonadIO m => MonadResource (m :: * -> *)
+ Hledger.Web.Import: class MonadTrans (t :: * -> * -> * -> *)
+ Hledger.Web.Import: class MonadIO m => MonadUnliftIO (m :: * -> *)
+ Hledger.Web.Import: class MonadHandler m => MonadWidget (m :: * -> *)
+ Hledger.Web.Import: class Semigroup a => Monoid a
+ Hledger.Web.Import: class Num a
+ Hledger.Web.Import: class Eq a => Ord a
+ Hledger.Web.Import: class RenderRoute a => ParseRoute a
+ Hledger.Web.Import: class ParseTime t
+ Hledger.Web.Import: class PathMultiPiece s
+ Hledger.Web.Import: class PathPiece s
+ Hledger.Web.Import: class PersistConfig c where {
+ Hledger.Web.Import: class PersistCore backend where {
+ Hledger.Web.Import: class (PersistField Key record, ToJSON Key record, FromJSON Key record, Show Key record, Read Key record, Eq Key record, Ord Key record) => PersistEntity record where {
+ Hledger.Web.Import: class PersistField a
+ Hledger.Web.Import: class (PersistCore backend, PersistStoreRead backend) => PersistQueryRead backend
+ Hledger.Web.Import: class (PersistQueryRead backend, PersistStoreWrite backend) => PersistQueryWrite backend
+ Hledger.Web.Import: class (Show BackendKey backend, Read BackendKey backend, Eq BackendKey backend, Ord BackendKey backend, PersistCore backend, PersistField BackendKey backend, ToJSON BackendKey backend, FromJSON BackendKey backend) => PersistStoreRead backend
+ Hledger.Web.Import: class (Show BackendKey backend, Read BackendKey backend, Eq BackendKey backend, Ord BackendKey backend, PersistStoreRead backend, PersistField BackendKey backend, ToJSON BackendKey backend, FromJSON BackendKey backend) => PersistStoreWrite backend
+ Hledger.Web.Import: class (PersistCore backend, PersistStoreRead backend) => PersistUniqueRead backend
+ Hledger.Web.Import: class (PersistUniqueRead backend, PersistStoreWrite backend) => PersistUniqueWrite backend
+ Hledger.Web.Import: class Read a
+ Hledger.Web.Import: class (Num a, Ord a) => Real a
+ Hledger.Web.Import: class (RealFrac a, Floating a) => RealFloat a
+ Hledger.Web.Import: class (Real a, Fractional a) => RealFrac a
+ Hledger.Web.Import: class RedirectUrl master a
+ Hledger.Web.Import: class RenderMessage master message
+ Hledger.Web.Import: class RenderRoute a => RouteAttrs a
+ Hledger.Web.Import: class Semigroup a
+ Hledger.Web.Import: class Show a
+ Hledger.Web.Import: class (PersistEntity record, PersistEntityBackend record ~ backend, PersistCore backend) => ToBackendKey backend record
+ Hledger.Web.Import: class ToContent a
+ Hledger.Web.Import: class ToFlushBuilder a
+ Hledger.Web.Import: class ToJSON a
+ Hledger.Web.Import: class ToMessage a
+ Hledger.Web.Import: class ToContent a => ToTypedContent a
+ Hledger.Web.Import: class ToWidget site a
+ Hledger.Web.Import: class ToWidgetBody site a
+ Hledger.Web.Import: class ToWidgetHead site a
+ Hledger.Web.Import: class ToWidgetMedia site a
+ Hledger.Web.Import: class (Functor t, Foldable t) => Traversable (t :: * -> *)
+ Hledger.Web.Import: class RenderRoute site => Yesod site
+ Hledger.Web.Import: class YesodBreadcrumbs site
+ Hledger.Web.Import: class Yesod site => YesodDispatch site
+ Hledger.Web.Import: class Monad YesodDB site => YesodPersist site where {
+ Hledger.Web.Import: class YesodPersist site => YesodPersistRunner site
+ Hledger.Web.Import: class YesodSubDispatch sub master
+ Hledger.Web.Import: cleanPath :: Yesod site => site -> [Text] -> Either [Text] [Text]
+ Hledger.Web.Import: clearSession :: MonadHandler m => m ()
+ Hledger.Web.Import: clearUltDest :: MonadHandler m => m ()
+ Hledger.Web.Import: clientSessionBackend :: Key -> IO ClientSessionDateCache -> SessionBackend
+ Hledger.Web.Import: clientSessionDateCacher :: NominalDiffTime -> IO (IO ClientSessionDateCache, IO ())
+ Hledger.Web.Import: compare :: Ord a => a -> a -> Ordering
+ Hledger.Web.Import: concat :: Foldable t => t [a] -> [a]
+ Hledger.Web.Import: concatMap :: Foldable t => a -> [b] -> t a -> [b]
+ Hledger.Web.Import: const :: () => a -> b -> a
+ Hledger.Web.Import: contentTypeTypes :: ContentType -> (ByteString, ByteString)
+ Hledger.Web.Import: convertField :: Functor m => a -> b -> b -> a -> Field m a -> Field m b
+ Hledger.Web.Import: cos :: Floating a => a -> a
+ Hledger.Web.Import: cosh :: Floating a => a -> a
+ Hledger.Web.Import: count :: (PersistQueryRead backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> ReaderT backend m Int
+ Hledger.Web.Import: createPoolConfig :: PersistConfig c => c -> IO PersistConfigPool c
+ Hledger.Web.Import: csrfCheckMiddleware :: () => HandlerFor site res -> HandlerFor site Bool -> CI ByteString -> Text -> HandlerFor site res
+ Hledger.Web.Import: csrfSetCookieMiddleware :: () => HandlerFor site res -> SetCookie -> HandlerFor site res
+ Hledger.Web.Import: css_bootstrap_css :: StaticRoute
+ Hledger.Web.Import: css_bootstrap_css_map :: StaticRoute
+ Hledger.Web.Import: css_bootstrap_datepicker_standalone_min_css :: StaticRoute
+ Hledger.Web.Import: css_bootstrap_min_css :: StaticRoute
+ Hledger.Web.Import: css_bootstrap_theme_css :: StaticRoute
+ Hledger.Web.Import: css_bootstrap_theme_css_map :: StaticRoute
+ Hledger.Web.Import: css_bootstrap_theme_min_css :: StaticRoute
+ Hledger.Web.Import: curry :: () => (a, b) -> c -> a -> b -> c
+ Hledger.Web.Import: customErrorMessage :: Monad m => SomeMessage HandlerSite m -> Field m a -> Field m a
+ Hledger.Web.Import: customizeSessionCookies :: SetCookie -> SetCookie -> SessionBackend -> SessionBackend
+ Hledger.Web.Import: cycle :: () => [a] -> [a]
+ Hledger.Web.Import: data App
+ Hledger.Web.Import: data Approot master
+ Hledger.Web.Import: data AuthResult
+ Hledger.Web.Import: data Bool
+ Hledger.Web.Import: data ByteString
+ Hledger.Web.Import: data Capability
+ Hledger.Web.Import: data Char
+ Hledger.Web.Import: data Checkmark
+ Hledger.Web.Import: data CompositeDef
+ Hledger.Web.Import: data Content
+ Hledger.Web.Import: data DiffTime
+ Hledger.Web.Import: data Double
+ Hledger.Web.Import: data Either a b
+ Hledger.Web.Import: data EmbedEntityDef
+ Hledger.Web.Import: data EmbedFieldDef
+ Hledger.Web.Import: data Enctype
+ Hledger.Web.Import: data Entity record
+ Hledger.Web.Import: data EntityDef
+ Hledger.Web.Import: data EntityJSON
+ Hledger.Web.Import: data ErrorResponse
+ Hledger.Web.Import: data Extra
+ Hledger.Web.Import: data Field (m :: * -> *) a
+ Hledger.Web.Import: data FieldDef
+ Hledger.Web.Import: data FieldSettings master
+ Hledger.Web.Import: data FieldType
+ Hledger.Web.Import: data FieldView site
+ Hledger.Web.Import: data FileInfo
+ Hledger.Web.Import: data FileUpload
+ Hledger.Web.Import: data Filter record
+ Hledger.Web.Import: data Float
+ Hledger.Web.Import: data ForeignDef
+ Hledger.Web.Import: data FormMessage
+ Hledger.Web.Import: data FormResult a
+ Hledger.Web.Import: data Fragment a b
+ Hledger.Web.Import: data HandlerFor site a
+ Hledger.Web.Import: data Header
+ Hledger.Web.Import: data IO a
+ Hledger.Web.Import: data Int
+ Hledger.Web.Import: data Integer
+ Hledger.Web.Import: data Ints
+ Hledger.Web.Import: data IsNullable
+ Hledger.Web.Import: data LocalTime
+ Hledger.Web.Import: data LogLevel
+ Hledger.Web.Import: data Maybe a
+ Hledger.Web.Import: data MkPersistSettings
+ Hledger.Web.Import: data NominalDiffTime
+ Hledger.Web.Import: data OnlyUniqueException
+ Hledger.Web.Import: data Option a
+ Hledger.Web.Import: data OptionList a
+ Hledger.Web.Import: data Ordering
+ Hledger.Web.Import: data PageContent url
+ Hledger.Web.Import: data PersistException
+ Hledger.Web.Import: data PersistFilter
+ Hledger.Web.Import: data PersistUpdate
+ Hledger.Web.Import: data PersistValue
+ Hledger.Web.Import: data ProvidedRep (m :: * -> *)
+ Hledger.Web.Import: data ReferenceDef
+ Hledger.Web.Import: data ScriptLoadPosition master
+ Hledger.Web.Import: data SelectOpt record
+ Hledger.Web.Import: data SomeMessage master
+ Hledger.Web.Import: data SomePersistField
+ Hledger.Web.Import: data SqlType
+ Hledger.Web.Import: data SubHandlerFor sub master a
+ Hledger.Web.Import: data Text
+ Hledger.Web.Import: data TimeLocale
+ Hledger.Web.Import: data TimeOfDay
+ Hledger.Web.Import: data TimeZone
+ Hledger.Web.Import: data TypedContent
+ Hledger.Web.Import: data UTCTime
+ Hledger.Web.Import: data UniqueDef
+ Hledger.Web.Import: data Update record
+ Hledger.Web.Import: data UpdateException
+ Hledger.Web.Import: data Value
+ Hledger.Web.Import: data ViewData
+ Hledger.Web.Import: data Void
+ Hledger.Web.Import: data WhyNullable
+ Hledger.Web.Import: data WidgetFor site a
+ Hledger.Web.Import: data Word
+ Hledger.Web.Import: data YesodRequest
+ Hledger.Web.Import: data ZonedTime
+ Hledger.Web.Import: data family Unique record :: *;
+ Hledger.Web.Import: dayField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Day
+ Hledger.Web.Import: dayFractionToTimeOfDay :: Rational -> TimeOfDay
+ Hledger.Web.Import: decodeFloat :: RealFloat a => a -> (Integer, Int)
+ Hledger.Web.Import: def :: Default a => a
+ Hledger.Web.Import: defaultClientSessionBackend :: Int -> FilePath -> IO SessionBackend
+ Hledger.Web.Import: defaultCsrfCheckMiddleware :: Yesod site => HandlerFor site res -> HandlerFor site res
+ Hledger.Web.Import: defaultCsrfCookieName :: ByteString
+ Hledger.Web.Import: defaultCsrfHeaderName :: CI ByteString
+ Hledger.Web.Import: defaultCsrfMiddleware :: Yesod site => HandlerFor site res -> HandlerFor site res
+ Hledger.Web.Import: defaultCsrfParamName :: Text
+ Hledger.Web.Import: defaultCsrfSetCookieMiddleware :: () => HandlerFor site res -> HandlerFor site res
+ Hledger.Web.Import: defaultErrorHandler :: Yesod site => ErrorResponse -> HandlerFor site TypedContent
+ Hledger.Web.Import: defaultFormMessage :: FormMessage -> Text
+ Hledger.Web.Import: defaultGetDBRunner :: (IsSqlBackend backend, YesodPersistBackend site ~ backend) => site -> Pool backend -> HandlerFor site (DBRunner site, HandlerFor site ())
+ Hledger.Web.Import: defaultLayout :: Yesod site => WidgetFor site () -> HandlerFor site Html
+ Hledger.Web.Import: defaultLayoutJson :: (Yesod site, ToJSON a) => WidgetFor site () -> HandlerFor site a -> HandlerFor site TypedContent
+ Hledger.Web.Import: defaultMakeLogger :: IO Logger
+ Hledger.Web.Import: defaultMessageLoggerSource :: LogSource -> LogLevel -> IO Bool -> Logger -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
+ Hledger.Web.Import: defaultMessageWidget :: Yesod site => Html -> HtmlUrl Route site -> WidgetFor site ()
+ Hledger.Web.Import: defaultMiddlewaresNoLogging :: Middleware
+ Hledger.Web.Import: defaultRunDB :: PersistConfig c => site -> c -> site -> PersistConfigPool c -> PersistConfigBackend c HandlerFor site a -> HandlerFor site a
+ Hledger.Web.Import: defaultShouldLogIO :: LogSource -> LogLevel -> IO Bool
+ Hledger.Web.Import: defaultTimeLocale :: TimeLocale
+ Hledger.Web.Import: defaultYesodMiddleware :: Yesod site => HandlerFor site res -> HandlerFor site res
+ Hledger.Web.Import: defbaseurl :: String -> Int -> String
+ Hledger.Web.Import: defhost :: String
+ Hledger.Web.Import: defport :: Int
+ Hledger.Web.Import: delete :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> ReaderT backend m ()
+ Hledger.Web.Import: deleteBy :: (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m ()
+ Hledger.Web.Import: deleteCascade :: (DeleteCascade record backend, MonadIO m) => Key record -> ReaderT backend m ()
+ Hledger.Web.Import: deleteCascadeWhere :: (MonadIO m, DeleteCascade record backend, PersistQueryWrite backend) => [Filter record] -> ReaderT backend m ()
+ Hledger.Web.Import: deleteCookie :: MonadHandler m => Text -> Text -> m ()
+ Hledger.Web.Import: deleteSession :: MonadHandler m => Text -> m ()
+ Hledger.Web.Import: deleteWhere :: (PersistQueryWrite backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> ReaderT backend m ()
+ Hledger.Web.Import: derivePersistField :: String -> Q [Dec]
+ Hledger.Web.Import: derivePersistFieldJSON :: String -> Q [Dec]
+ Hledger.Web.Import: development :: Bool
+ Hledger.Web.Import: diffDays :: Day -> Day -> Integer
+ Hledger.Web.Import: diffTimeToPicoseconds :: DiffTime -> Integer
+ Hledger.Web.Import: diffUTCTime :: UTCTime -> UTCTime -> NominalDiffTime
+ Hledger.Web.Import: dispatchTo :: ToTypedContent a => LiteHandler a -> Writer LiteApp ()
+ Hledger.Web.Import: div :: Integral a => a -> a -> a
+ Hledger.Web.Import: divMod :: Integral a => a -> a -> (a, a)
+ Hledger.Web.Import: doubleField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Double
+ Hledger.Web.Import: drop :: () => Int -> [a] -> [a]
+ Hledger.Web.Import: dropWhile :: () => a -> Bool -> [a] -> [a]
+ Hledger.Web.Import: either :: () => a -> c -> b -> c -> Either a b -> c
+ Hledger.Web.Import: elem :: (Foldable t, Eq a) => a -> t a -> Bool
+ Hledger.Web.Import: emailField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Text
+ Hledger.Web.Import: emptyContent :: Content
+ Hledger.Web.Import: encodeFloat :: RealFloat a => Integer -> Int -> a
+ Hledger.Web.Import: entityDef :: (PersistEntity record, Monad m) => m record -> EntityDef
+ Hledger.Web.Import: entityIdFromJSON :: (PersistEntity record, FromJSON record, FromJSON Key record) => Value -> Parser Entity record
+ Hledger.Web.Import: entityIdToJSON :: (PersistEntity record, ToJSON record, ToJSON Key record) => Entity record -> Value
+ Hledger.Web.Import: entityKeyFields :: EntityDef -> [FieldDef]
+ Hledger.Web.Import: entityPrimary :: EntityDef -> Maybe CompositeDef
+ Hledger.Web.Import: entityValues :: PersistEntity record => Entity record -> [PersistValue]
+ Hledger.Web.Import: enumFrom :: Enum a => a -> [a]
+ Hledger.Web.Import: enumFromThen :: Enum a => a -> a -> [a]
+ Hledger.Web.Import: enumFromThenTo :: Enum a => a -> a -> a -> [a]
+ Hledger.Web.Import: enumFromTo :: Enum a => a -> a -> [a]
+ Hledger.Web.Import: envClientSessionBackend :: Int -> String -> IO SessionBackend
+ Hledger.Web.Import: error :: HasCallStack => [Char] -> a
+ Hledger.Web.Import: errorHandler :: Yesod site => ErrorResponse -> HandlerFor site TypedContent
+ Hledger.Web.Import: errorWithoutStackTrace :: () => [Char] -> a
+ Hledger.Web.Import: even :: Integral a => a -> Bool
+ Hledger.Web.Import: exp :: Floating a => a -> a
+ Hledger.Web.Import: expiresAt :: MonadHandler m => UTCTime -> m ()
+ Hledger.Web.Import: exponent :: RealFloat a => a -> Int
+ Hledger.Web.Import: fail :: Monad m => String -> m a
+ Hledger.Web.Import: fieldLens :: PersistEntity record => EntityField record field -> forall (f :: * -> *). Functor f => field -> f field -> Entity record -> f Entity record
+ Hledger.Web.Import: fieldSettingsLabel :: RenderMessage site msg => msg -> FieldSettings site
+ Hledger.Web.Import: fileAFormOpt :: MonadHandler m => FieldSettings HandlerSite m -> AForm m Maybe FileInfo
+ Hledger.Web.Import: fileAFormReq :: (MonadHandler m, RenderMessage HandlerSite m FormMessage) => FieldSettings HandlerSite m -> AForm m FileInfo
+ Hledger.Web.Import: fileField :: Monad m => Field m FileInfo
+ Hledger.Web.Import: fileSource :: MonadResource m => FileInfo -> ConduitT () ByteString m ()
+ Hledger.Web.Import: fileSourceByteString :: MonadResource m => FileInfo -> m ByteString
+ Hledger.Web.Import: fileUpload :: Yesod site => site -> RequestBodyLength -> FileUpload
+ Hledger.Web.Import: filter :: () => a -> Bool -> [a] -> [a]
+ Hledger.Web.Import: filterM :: Applicative m => a -> m Bool -> [a] -> m [a]
+ Hledger.Web.Import: find :: Foldable t => a -> Bool -> t a -> Maybe a
+ Hledger.Web.Import: first :: Bifunctor p => a -> b -> p a c -> p b c
+ Hledger.Web.Import: flip :: () => a -> b -> c -> b -> a -> c
+ Hledger.Web.Import: floatDigits :: RealFloat a => a -> Int
+ Hledger.Web.Import: floatRadix :: RealFloat a => a -> Integer
+ Hledger.Web.Import: floatRange :: RealFloat a => a -> (Int, Int)
+ Hledger.Web.Import: floor :: (RealFrac a, Integral b) => a -> b
+ Hledger.Web.Import: fmap :: Functor f => a -> b -> f a -> f b
+ Hledger.Web.Import: fmapDefault :: Traversable t => a -> b -> t a -> t b
+ Hledger.Web.Import: fold :: (Foldable t, Monoid m) => t m -> m
+ Hledger.Web.Import: foldM :: (Foldable t, Monad m) => b -> a -> m b -> b -> t a -> m b
+ Hledger.Web.Import: foldM_ :: (Foldable t, Monad m) => b -> a -> m b -> b -> t a -> m ()
+ Hledger.Web.Import: foldMap :: (Foldable t, Monoid m) => a -> m -> t a -> m
+ Hledger.Web.Import: foldMapDefault :: (Traversable t, Monoid m) => a -> m -> t a -> m
+ Hledger.Web.Import: foldl :: Foldable t => b -> a -> b -> b -> t a -> b
+ Hledger.Web.Import: foldl' :: Foldable t => b -> a -> b -> b -> t a -> b
+ Hledger.Web.Import: foldl1 :: Foldable t => a -> a -> a -> t a -> a
+ Hledger.Web.Import: foldlM :: (Foldable t, Monad m) => b -> a -> m b -> b -> t a -> m b
+ Hledger.Web.Import: foldr :: Foldable t => a -> b -> b -> b -> t a -> b
+ Hledger.Web.Import: foldr' :: Foldable t => a -> b -> b -> b -> t a -> b
+ Hledger.Web.Import: foldr1 :: Foldable t => a -> a -> a -> t a -> a
+ Hledger.Web.Import: foldrM :: (Foldable t, Monad m) => a -> b -> m b -> b -> t a -> m b
+ Hledger.Web.Import: fonts_glyphicons_halflings_regular_eot :: StaticRoute
+ Hledger.Web.Import: fonts_glyphicons_halflings_regular_svg :: StaticRoute
+ Hledger.Web.Import: fonts_glyphicons_halflings_regular_ttf :: StaticRoute
+ Hledger.Web.Import: fonts_glyphicons_halflings_regular_woff :: StaticRoute
+ Hledger.Web.Import: for :: (Traversable t, Applicative f) => t a -> a -> f b -> f t b
+ Hledger.Web.Import: forM :: (Traversable t, Monad m) => t a -> a -> m b -> m t b
+ Hledger.Web.Import: forM_ :: (Foldable t, Monad m) => t a -> a -> m b -> m ()
+ Hledger.Web.Import: for_ :: (Foldable t, Applicative f) => t a -> a -> f b -> f ()
+ Hledger.Web.Import: forever :: Applicative f => f a -> f b
+ Hledger.Web.Import: forkHandler :: () => SomeException -> HandlerFor site () -> HandlerFor site () -> HandlerFor site ()
+ Hledger.Web.Import: formToAForm :: (HandlerSite m ~ site, Monad m) => MForm m (FormResult a, [FieldView site]) -> AForm m a
+ Hledger.Web.Import: formatCharacter :: FormatTime t => Char -> Maybe TimeLocale -> Maybe NumericPadOption -> Maybe Int -> t -> String
+ Hledger.Web.Import: formatLogMessage :: IO ZonedDate -> Loc -> LogSource -> LogLevel -> LogStr -> IO LogStr
+ Hledger.Web.Import: formatRFC1123 :: UTCTime -> Text
+ Hledger.Web.Import: formatRFC822 :: UTCTime -> Text
+ Hledger.Web.Import: formatTime :: FormatTime t => TimeLocale -> String -> t -> String
+ Hledger.Web.Import: formatW3 :: UTCTime -> Text
+ Hledger.Web.Import: fromBackendKey :: ToBackendKey backend record => BackendKey backend -> Key record
+ Hledger.Web.Import: fromEnum :: Enum a => a -> Int
+ Hledger.Web.Import: fromGregorian :: Integer -> Int -> Int -> Day
+ Hledger.Web.Import: fromGregorianValid :: Integer -> Int -> Int -> Maybe Day
+ Hledger.Web.Import: fromInteger :: Num a => Integer -> a
+ Hledger.Web.Import: fromIntegral :: (Integral a, Num b) => a -> b
+ Hledger.Web.Import: fromJust :: () => Maybe a -> a
+ Hledger.Web.Import: fromLeft :: () => a -> Either a b -> a
+ Hledger.Web.Import: fromMaybe :: () => a -> Maybe a -> a
+ Hledger.Web.Import: fromPathMultiPiece :: PathMultiPiece s => [Text] -> Maybe s
+ Hledger.Web.Import: fromPathPiece :: PathPiece s => Text -> Maybe s
+ Hledger.Web.Import: fromPersistValue :: PersistField a => PersistValue -> Either Text a
+ Hledger.Web.Import: fromPersistValueJSON :: FromJSON a => PersistValue -> Either Text a
+ Hledger.Web.Import: fromPersistValueText :: PersistValue -> Either Text Text
+ Hledger.Web.Import: fromPersistValues :: PersistEntity record => [PersistValue] -> Either Text record
+ Hledger.Web.Import: fromRational :: Fractional a => Rational -> a
+ Hledger.Web.Import: fromRight :: () => b -> Either a b -> b
+ Hledger.Web.Import: fst :: () => (a, b) -> a
+ Hledger.Web.Import: gcd :: Integral a => a -> a -> a
+ Hledger.Web.Import: generateFormGet :: MonadHandler m => Markup -> MForm m a -> m (a, Enctype)
+ Hledger.Web.Import: generateFormGet' :: MonadHandler m => Markup -> MForm m (FormResult a, xml) -> m (xml, Enctype)
+ Hledger.Web.Import: generateFormPost :: (RenderMessage HandlerSite m FormMessage, MonadHandler m) => Markup -> MForm m (FormResult a, xml) -> m (xml, Enctype)
+ Hledger.Web.Import: get :: (PersistStoreRead backend, MonadIO m, PersistRecordBackend record backend) => Key record -> ReaderT backend m Maybe record
+ Hledger.Web.Import: get404 :: (MonadIO m, PersistStoreRead backend, PersistRecordBackend val backend) => Key val -> ReaderT backend m val
+ Hledger.Web.Import: getApprootText :: () => Approot site -> site -> Request -> Text
+ Hledger.Web.Import: getBy :: (PersistUniqueRead backend, MonadIO m, PersistRecordBackend record backend) => Unique record -> ReaderT backend m Maybe Entity record
+ Hledger.Web.Import: getBy404 :: (PersistUniqueRead backend, PersistRecordBackend val backend, MonadIO m) => Unique val -> ReaderT backend m Entity val
+ Hledger.Web.Import: getByValue :: (MonadIO m, PersistUniqueRead backend, PersistRecordBackend record backend) => record -> ReaderT backend m Maybe Entity record
+ Hledger.Web.Import: getChar :: IO Char
+ Hledger.Web.Import: getContentType :: (HasContentType a, Monad m) => m a -> ContentType
+ Hledger.Web.Import: getContents :: IO String
+ Hledger.Web.Import: getCurrentJournal :: IORef Journal -> CliOpts -> Day -> Handler (Journal, Maybe String)
+ Hledger.Web.Import: getCurrentRoute :: MonadHandler m => m Maybe Route HandlerSite m
+ Hledger.Web.Import: getCurrentTime :: IO UTCTime
+ Hledger.Web.Import: getCurrentTimeZone :: IO TimeZone
+ Hledger.Web.Import: getDBRunner :: YesodPersistRunner site => HandlerFor site (DBRunner site, HandlerFor site ())
+ Hledger.Web.Import: getEntity :: (PersistStoreRead backend, PersistRecordBackend e backend, MonadIO m) => Key e -> ReaderT backend m Maybe Entity e
+ Hledger.Web.Import: getExpires :: MonadIO m => Int -> m UTCTime
+ Hledger.Web.Import: getGetMaxExpires :: IO IO Text
+ Hledger.Web.Import: getJust :: (PersistStoreRead backend, Show Key record, PersistRecordBackend record backend, MonadIO m) => Key record -> ReaderT backend m record
+ Hledger.Web.Import: getJustEntity :: (PersistEntityBackend record ~ BaseBackend backend, MonadIO m, PersistEntity record, PersistStoreRead backend) => Key record -> ReaderT backend m Entity record
+ Hledger.Web.Import: getLine :: IO String
+ Hledger.Web.Import: getMany :: (PersistStoreRead backend, MonadIO m, PersistRecordBackend record backend) => [Key record] -> ReaderT backend m Map Key record record
+ Hledger.Web.Import: getMessage :: MonadHandler m => m Maybe Html
+ Hledger.Web.Import: getMessageRender :: (MonadHandler m, RenderMessage HandlerSite m message) => m message -> Text
+ Hledger.Web.Import: getMessages :: MonadHandler m => m [(Text, Html)]
+ Hledger.Web.Import: getPersistMap :: PersistValue -> Either Text [(Text, PersistValue)]
+ Hledger.Web.Import: getPostParams :: MonadHandler m => m [(Text, Text)]
+ Hledger.Web.Import: getRequest :: MonadHandler m => m YesodRequest
+ Hledger.Web.Import: getRouteToParent :: MonadHandler m => m Route SubHandlerSite m -> Route HandlerSite m
+ Hledger.Web.Import: getSession :: MonadHandler m => m SessionMap
+ Hledger.Web.Import: getSubCurrentRoute :: MonadHandler m => m Maybe Route SubHandlerSite m
+ Hledger.Web.Import: getSubYesod :: MonadHandler m => m SubHandlerSite m
+ Hledger.Web.Import: getTimeZone :: UTCTime -> IO TimeZone
+ Hledger.Web.Import: getTime_resolution :: DiffTime
+ Hledger.Web.Import: getUrlRender :: MonadHandler m => m Route HandlerSite m -> Text
+ Hledger.Web.Import: getUrlRenderParams :: MonadHandler m => m Route HandlerSite m -> [(Text, Text)] -> Text
+ Hledger.Web.Import: getViewData :: Handler ViewData
+ Hledger.Web.Import: getYesod :: MonadHandler m => m HandlerSite m
+ Hledger.Web.Import: getZonedTime :: IO ZonedTime
+ Hledger.Web.Import: getsYesod :: MonadHandler m => HandlerSite m -> a -> m a
+ Hledger.Web.Import: giveUrlRenderer :: MonadHandler m => Route HandlerSite m -> [(Text, Text)] -> Text -> output -> m output
+ Hledger.Web.Import: gregorianMonthLength :: Integer -> Int -> Int
+ Hledger.Web.Import: guard :: Alternative f => Bool -> f ()
+ Hledger.Web.Import: guessApproot :: () => Approot site
+ Hledger.Web.Import: guessApprootOr :: () => Approot site -> Approot site
+ Hledger.Web.Import: hamlet :: QuasiQuoter
+ Hledger.Web.Import: hamletToRepHtml :: MonadHandler m => HtmlUrl Route HandlerSite m -> m Html
+ Hledger.Web.Import: handlerToIO :: MonadIO m => HandlerFor site HandlerFor site a -> m a
+ Hledger.Web.Import: handlerToWidget :: () => HandlerFor site a -> WidgetFor site a
+ Hledger.Web.Import: hasValidCsrfHeaderNamed :: MonadHandler m => CI ByteString -> m Bool
+ Hledger.Web.Import: hasValidCsrfParamNamed :: MonadHandler m => Text -> m Bool
+ Hledger.Web.Import: hiddenField :: (Monad m, PathPiece p, RenderMessage HandlerSite m FormMessage) => Field m p
+ Hledger.Web.Import: hledger_css :: StaticRoute
+ Hledger.Web.Import: hledger_js :: StaticRoute
+ Hledger.Web.Import: hledgerorgurl :: Text
+ Hledger.Web.Import: hoursToTimeZone :: Int -> TimeZone
+ Hledger.Web.Import: htmlField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Html
+ Hledger.Web.Import: id :: () => a -> a
+ Hledger.Web.Import: identifyForm :: Monad m => Text -> Markup -> MForm m (FormResult a, WidgetFor HandlerSite m ()) -> Markup -> MForm m (FormResult a, WidgetFor HandlerSite m ())
+ Hledger.Web.Import: ihamletToHtml :: (MonadHandler m, RenderMessage HandlerSite m message) => HtmlUrlI18n message Route HandlerSite m -> m Html
+ Hledger.Web.Import: ihamletToRepHtml :: (MonadHandler m, RenderMessage HandlerSite m message) => HtmlUrlI18n message Route HandlerSite m -> m Html
+ Hledger.Web.Import: infix 4 ==.
+ Hledger.Web.Import: infixl 3 ||.
+ Hledger.Web.Import: infixl 4 <$!>
+ Hledger.Web.Import: infixl 9 !!
+ Hledger.Web.Import: infixr 0 $!
+ Hledger.Web.Import: infixr 1 =<<
+ Hledger.Web.Import: infixr 2 ||
+ Hledger.Web.Import: infixr 3 =.
+ Hledger.Web.Import: infixr 5 ++
+ Hledger.Web.Import: infixr 8 ^
+ Hledger.Web.Import: infixr 9 .
+ Hledger.Web.Import: insert :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => record -> ReaderT backend m Key record
+ Hledger.Web.Import: insert400 :: (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend val backend) => val -> ReaderT backend m Key val
+ Hledger.Web.Import: insert400_ :: (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend val backend) => val -> ReaderT backend m ()
+ Hledger.Web.Import: insertBy :: (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend record backend) => record -> ReaderT backend m Either Entity record Key record
+ Hledger.Web.Import: insertEntity :: (PersistStoreWrite backend, PersistRecordBackend e backend, MonadIO m) => e -> ReaderT backend m Entity e
+ Hledger.Web.Import: insertEntityMany :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => [Entity record] -> ReaderT backend m ()
+ Hledger.Web.Import: insertKey :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()
+ Hledger.Web.Import: insertMany :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => [record] -> ReaderT backend m [Key record]
+ Hledger.Web.Import: insertMany_ :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => [record] -> ReaderT backend m ()
+ Hledger.Web.Import: insertRecord :: (PersistEntityBackend record ~ BaseBackend backend, PersistEntity record, MonadIO m, PersistStoreWrite backend) => record -> ReaderT backend m record
+ Hledger.Web.Import: insertUnique :: (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend) => record -> ReaderT backend m Maybe Key record
+ Hledger.Web.Import: insertUniqueEntity :: (MonadIO m, PersistRecordBackend record backend, PersistUniqueWrite backend) => record -> ReaderT backend m Maybe Entity record
+ Hledger.Web.Import: insert_ :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => record -> ReaderT backend m ()
+ Hledger.Web.Import: intField :: (Monad m, Integral i, RenderMessage HandlerSite m FormMessage) => Field m i
+ Hledger.Web.Import: interact :: String -> String -> IO ()
+ Hledger.Web.Import: invalidArgs :: MonadHandler m => [Text] -> m a
+ Hledger.Web.Import: invalidArgsI :: (MonadHandler m, RenderMessage HandlerSite m msg) => [msg] -> m a
+ Hledger.Web.Import: ioError :: () => IOError -> IO a
+ Hledger.Web.Import: iopt :: Monad m => Field m a -> Text -> FormInput m Maybe a
+ Hledger.Web.Import: ireq :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m a -> Text -> FormInput m a
+ Hledger.Web.Import: isAuthorized :: Yesod site => Route site -> Bool -> HandlerFor site AuthResult
+ Hledger.Web.Import: isDenormalized :: RealFloat a => a -> Bool
+ Hledger.Web.Import: isIEEE :: RealFloat a => a -> Bool
+ Hledger.Web.Import: isInfinite :: RealFloat a => a -> Bool
+ Hledger.Web.Import: isJust :: () => Maybe a -> Bool
+ Hledger.Web.Import: isLeapYear :: Integer -> Bool
+ Hledger.Web.Import: isLeft :: () => Either a b -> Bool
+ Hledger.Web.Import: isNaN :: RealFloat a => a -> Bool
+ Hledger.Web.Import: isNegativeZero :: RealFloat a => a -> Bool
+ Hledger.Web.Import: isNothing :: () => Maybe a -> Bool
+ Hledger.Web.Import: isRight :: () => Either a b -> Bool
+ Hledger.Web.Import: isWriteRequest :: Yesod site => Route site -> HandlerFor site Bool
+ Hledger.Web.Import: iso8601DateFormat :: Maybe String -> String
+ Hledger.Web.Import: iterate :: () => a -> a -> a -> [a]
+ Hledger.Web.Import: join :: Monad m => m m a -> m a
+ Hledger.Web.Import: joinPath :: Yesod site => site -> Text -> [Text] -> [(Text, Text)] -> Builder
+ Hledger.Web.Import: jsAttributes :: Yesod site => site -> [(Text, Text)]
+ Hledger.Web.Import: jsLoader :: Yesod site => site -> ScriptLoadPosition site
+ Hledger.Web.Import: js_bootstrap_datepicker_min_js :: StaticRoute
+ Hledger.Web.Import: js_bootstrap_js :: StaticRoute
+ Hledger.Web.Import: js_bootstrap_min_js :: StaticRoute
+ Hledger.Web.Import: js_excanvas_js :: StaticRoute
+ Hledger.Web.Import: js_excanvas_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_cookie_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_canvas_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_canvas_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_categories_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_categories_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_crosshair_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_crosshair_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_errorbars_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_errorbars_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_fillbetween_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_fillbetween_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_image_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_image_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_navigate_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_navigate_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_pie_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_pie_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_resize_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_resize_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_selection_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_selection_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_stack_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_stack_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_symbol_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_symbol_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_threshold_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_threshold_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_time_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_time_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_tooltip_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_flot_tooltip_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_hotkeys_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_min_js :: StaticRoute
+ Hledger.Web.Import: js_jquery_url_js :: StaticRoute
+ Hledger.Web.Import: js_typeahead_bundle_js :: StaticRoute
+ Hledger.Web.Import: js_typeahead_bundle_min_js :: StaticRoute
+ Hledger.Web.Import: jsonEncodingOrRedirect :: (MonadHandler m, ToJSON a) => Route HandlerSite m -> a -> m Encoding
+ Hledger.Web.Import: jsonOrRedirect :: (MonadHandler m, ToJSON a) => Route HandlerSite m -> a -> m Value
+ Hledger.Web.Import: jsonToRepJson :: (Monad m, ToJSON a) => a -> m Value
+ Hledger.Web.Import: julius :: QuasiQuoter
+ Hledger.Web.Import: keyAndEntityFields :: EntityDef -> [FieldDef]
+ Hledger.Web.Import: keyFromValues :: PersistEntity record => [PersistValue] -> Either Text Key record
+ Hledger.Web.Import: keyToValues :: PersistEntity record => Key record -> [PersistValue]
+ Hledger.Web.Import: keyValueEntityFromJSON :: (PersistEntity record, FromJSON record, FromJSON Key record) => Value -> Parser Entity record
+ Hledger.Web.Import: keyValueEntityToJSON :: (PersistEntity record, ToJSON record, ToJSON Key record) => Entity record -> Value
+ Hledger.Web.Import: languages :: MonadHandler m => m [Text]
+ Hledger.Web.Import: laxSameSiteSessions :: IO Maybe SessionBackend -> IO Maybe SessionBackend
+ Hledger.Web.Import: lcm :: Integral a => a -> a -> a
+ Hledger.Web.Import: lefts :: () => [Either a b] -> [a]
+ Hledger.Web.Import: length :: Foldable t => t a -> Int
+ Hledger.Web.Import: lensPTH :: () => s -> a -> s -> b -> t -> Lens s t a b
+ Hledger.Web.Import: lex :: ReadS String
+ Hledger.Web.Import: lift :: (MonadTrans t, Monad m) => m a -> t m a
+ Hledger.Web.Import: liftHandler :: MonadHandler m => HandlerFor HandlerSite m a -> m a
+ Hledger.Web.Import: liftIO :: MonadIO m => IO a -> m a
+ Hledger.Web.Import: liftM :: Monad m => a1 -> r -> m a1 -> m r
+ Hledger.Web.Import: liftM2 :: Monad m => a1 -> a2 -> r -> m a1 -> m a2 -> m r
+ Hledger.Web.Import: liftM3 :: Monad m => a1 -> a2 -> a3 -> r -> m a1 -> m a2 -> m a3 -> m r
+ Hledger.Web.Import: liftM4 :: Monad m => a1 -> a2 -> a3 -> a4 -> r -> m a1 -> m a2 -> m a3 -> m a4 -> m r
+ Hledger.Web.Import: liftM5 :: Monad m => a1 -> a2 -> a3 -> a4 -> a5 -> r -> m a1 -> m a2 -> m a3 -> m a4 -> m a5 -> m r
+ Hledger.Web.Import: liftPersist :: (MonadIO m, MonadReader backend m, HasPersistBackend backend) => ReaderT BaseBackend backend IO b -> m b
+ Hledger.Web.Import: liftResourceT :: MonadResource m => ResourceT IO a -> m a
+ Hledger.Web.Import: liftSubHandler :: MonadHandler m => SubHandlerFor SubHandlerSite m HandlerSite m a -> m a
+ Hledger.Web.Import: liftWidget :: MonadWidget m => WidgetFor HandlerSite m a -> m a
+ Hledger.Web.Import: limitOffsetOrder :: PersistEntity val => [SelectOpt val] -> (Int, Int, [SelectOpt val])
+ Hledger.Web.Import: lines :: String -> [String]
+ Hledger.Web.Import: listToJSON :: [PersistValue] -> Text
+ Hledger.Web.Import: listToMaybe :: () => [a] -> Maybe a
+ Hledger.Web.Import: liteApp :: Writer LiteApp () -> LiteApp
+ Hledger.Web.Import: loadClientSession :: Key -> IO ClientSessionDateCache -> ByteString -> Request -> IO (SessionMap, SaveSession)
+ Hledger.Web.Import: loadConfig :: PersistConfig c => Value -> Parser c
+ Hledger.Web.Import: localTimeToUT1 :: Rational -> LocalTime -> UniversalTime
+ Hledger.Web.Import: localTimeToUTC :: TimeZone -> LocalTime -> UTCTime
+ Hledger.Web.Import: localToUTCTimeOfDay :: TimeZone -> TimeOfDay -> (Integer, TimeOfDay)
+ Hledger.Web.Import: log :: Floating a => a -> a
+ Hledger.Web.Import: logBase :: Floating a => a -> a -> a
+ Hledger.Web.Import: logDebug :: Q Exp
+ Hledger.Web.Import: logDebugS :: Q Exp
+ Hledger.Web.Import: logError :: Q Exp
+ Hledger.Web.Import: logErrorS :: Q Exp
+ Hledger.Web.Import: logInfo :: Q Exp
+ Hledger.Web.Import: logInfoS :: Q Exp
+ Hledger.Web.Import: logOther :: Text -> Q Exp
+ Hledger.Web.Import: logOtherS :: Q Exp
+ Hledger.Web.Import: logWarn :: Q Exp
+ Hledger.Web.Import: logWarnS :: Q Exp
+ Hledger.Web.Import: lookup :: Eq a => a -> [(a, b)] -> Maybe b
+ Hledger.Web.Import: lookupBasicAuth :: MonadHandler m => m Maybe (Text, Text)
+ Hledger.Web.Import: lookupBearerAuth :: MonadHandler m => m Maybe Text
+ Hledger.Web.Import: lookupCookie :: MonadHandler m => Text -> m Maybe Text
+ Hledger.Web.Import: lookupCookies :: MonadHandler m => Text -> m [Text]
+ Hledger.Web.Import: lookupFile :: MonadHandler m => Text -> m Maybe FileInfo
+ Hledger.Web.Import: lookupFiles :: MonadHandler m => Text -> m [FileInfo]
+ Hledger.Web.Import: lookupGetParam :: MonadHandler m => Text -> m Maybe Text
+ Hledger.Web.Import: lookupGetParams :: MonadHandler m => Text -> m [Text]
+ Hledger.Web.Import: lookupHeader :: MonadHandler m => CI ByteString -> m Maybe ByteString
+ Hledger.Web.Import: lookupHeaders :: MonadHandler m => CI ByteString -> m [ByteString]
+ Hledger.Web.Import: lookupPostParam :: (MonadResource m, MonadHandler m) => Text -> m Maybe Text
+ Hledger.Web.Import: lookupPostParams :: (MonadResource m, MonadHandler m) => Text -> m [Text]
+ Hledger.Web.Import: lookupSession :: MonadHandler m => Text -> m Maybe Text
+ Hledger.Web.Import: lookupSessionBS :: MonadHandler m => Text -> m Maybe ByteString
+ Hledger.Web.Import: lucius :: QuasiQuoter
+ Hledger.Web.Import: mFormToWForm :: (MonadHandler m, HandlerSite m ~ site) => MForm m (a, FieldView site) -> WForm m a
+ Hledger.Web.Import: makeLogger :: Yesod site => site -> IO Logger
+ Hledger.Web.Import: makeSessionBackend :: Yesod site => site -> IO Maybe SessionBackend
+ Hledger.Web.Import: makeTimeOfDayValid :: Int -> Int -> Pico -> Maybe TimeOfDay
+ Hledger.Web.Import: manualurl :: Text
+ Hledger.Web.Import: map :: () => a -> b -> [a] -> [b]
+ Hledger.Web.Import: mapAccumL :: Traversable t => a -> b -> (a, c) -> a -> t b -> (a, t c)
+ Hledger.Web.Import: mapAccumR :: Traversable t => a -> b -> (a, c) -> a -> t b -> (a, t c)
+ Hledger.Web.Import: mapAndUnzipM :: Applicative m => a -> m (b, c) -> [a] -> m ([b], [c])
+ Hledger.Web.Import: mapM :: (Traversable t, Monad m) => a -> m b -> t a -> m t b
+ Hledger.Web.Import: mapM_ :: (Foldable t, Monad m) => a -> m b -> t a -> m ()
+ Hledger.Web.Import: mapMaybe :: () => a -> Maybe b -> [a] -> [b]
+ Hledger.Web.Import: mapToJSON :: [(Text, PersistValue)] -> Text
+ Hledger.Web.Import: mappend :: Monoid a => a -> a -> a
+ Hledger.Web.Import: max :: Ord a => a -> a -> a
+ Hledger.Web.Import: maxBound :: Bounded a => a
+ Hledger.Web.Import: maximum :: (Foldable t, Ord a) => t a -> a
+ Hledger.Web.Import: maximumBy :: Foldable t => a -> a -> Ordering -> t a -> a
+ Hledger.Web.Import: maximumContentLength :: Yesod site => site -> Maybe Route site -> Maybe Word64
+ Hledger.Web.Import: maybe :: () => b -> a -> b -> Maybe a -> b
+ Hledger.Web.Import: maybeAuthorized :: Yesod site => Route site -> Bool -> HandlerT site IO Maybe Route site
+ Hledger.Web.Import: maybeToList :: () => Maybe a -> [a]
+ Hledger.Web.Import: mconcat :: Monoid a => [a] -> a
+ Hledger.Web.Import: mempty :: Monoid a => a
+ Hledger.Web.Import: messageLoggerSource :: Yesod site => site -> Logger -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
+ Hledger.Web.Import: mfilter :: MonadPlus m => a -> Bool -> m a -> m a
+ Hledger.Web.Import: midday :: TimeOfDay
+ Hledger.Web.Import: midnight :: TimeOfDay
+ Hledger.Web.Import: min :: Ord a => a -> a -> a
+ Hledger.Web.Import: minBound :: Bounded a => a
+ Hledger.Web.Import: minimum :: (Foldable t, Ord a) => t a -> a
+ Hledger.Web.Import: minimumBy :: Foldable t => a -> a -> Ordering -> t a -> a
+ Hledger.Web.Import: minutesToTimeZone :: Int -> TimeZone
+ Hledger.Web.Import: mkDefaultMiddlewares :: Logger -> IO Middleware
+ Hledger.Web.Import: mkDeleteCascade :: MkPersistSettings -> [EntityDef] -> Q [Dec]
+ Hledger.Web.Import: mkMessage :: String -> FilePath -> Lang -> Q [Dec]
+ Hledger.Web.Import: mkMessageFor :: String -> String -> FilePath -> Lang -> Q [Dec]
+ Hledger.Web.Import: mkMessageVariant :: String -> String -> FilePath -> Lang -> Q [Dec]
+ Hledger.Web.Import: mkMigrate :: String -> [EntityDef] -> Q [Dec]
+ Hledger.Web.Import: mkOptionList :: () => [Option a] -> OptionList a
+ Hledger.Web.Import: mkPersist :: MkPersistSettings -> [EntityDef] -> Q [Dec]
+ Hledger.Web.Import: mkPersistSettings :: Type -> MkPersistSettings
+ Hledger.Web.Import: mkSave :: String -> [EntityDef] -> Q [Dec]
+ Hledger.Web.Import: mkYesod :: String -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: mkYesodData :: String -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: mkYesodDispatch :: String -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: mkYesodSubData :: String -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: mkYesodSubDispatch :: () => [ResourceTree a] -> Q Exp
+ Hledger.Web.Import: mkYesodWith :: [[String]] -> String -> [String] -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: mod :: Integral a => a -> a -> a
+ Hledger.Web.Import: mopt :: (site ~ HandlerSite m, MonadHandler m) => Field m a -> FieldSettings site -> Maybe Maybe a -> MForm m (FormResult Maybe a, FieldView site)
+ Hledger.Web.Import: mplus :: MonadPlus m => m a -> m a -> m a
+ Hledger.Web.Import: mreq :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m) => Field m a -> FieldSettings site -> Maybe a -> MForm m (FormResult a, FieldView site)
+ Hledger.Web.Import: msum :: (Foldable t, MonadPlus m) => t m a -> m a
+ Hledger.Web.Import: multiEmailField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m [Text]
+ Hledger.Web.Import: multiSelectField :: Eq a => HandlerFor site OptionList a -> Field HandlerFor site [a]
+ Hledger.Web.Import: multiSelectFieldList :: (Eq a, RenderMessage site msg) => [(msg, a)] -> Field HandlerFor site [a]
+ Hledger.Web.Import: mzero :: MonadPlus m => m a
+ Hledger.Web.Import: negate :: Num a => a -> a
+ Hledger.Web.Import: neverExpires :: MonadHandler m => m ()
+ Hledger.Web.Import: newFormIdent :: Monad m => MForm m Text
+ Hledger.Web.Import: newIdent :: MonadHandler m => m Text
+ Hledger.Web.Import: newtype AForm (m :: * -> *) a
+ Hledger.Web.Import: newtype CssBuilder
+ Hledger.Web.Import: newtype DBName
+ Hledger.Web.Import: newtype DBRunner site
+ Hledger.Web.Import: newtype Day
+ Hledger.Web.Import: newtype DontFullyEvaluate a
+ Hledger.Web.Import: newtype FormInput (m :: * -> *) a
+ Hledger.Web.Import: newtype HaskellName
+ Hledger.Web.Import: newtype LiteApp
+ Hledger.Web.Import: newtype RepJson
+ Hledger.Web.Import: newtype RepPlain
+ Hledger.Web.Import: newtype RepXml
+ Hledger.Web.Import: newtype SessionBackend
+ Hledger.Web.Import: newtype Textarea
+ Hledger.Web.Import: newtype UniversalTime
+ Hledger.Web.Import: newtype WaiSubsite
+ Hledger.Web.Import: newtype WaiSubsiteWithAuth
+ Hledger.Web.Import: nominalDay :: NominalDiffTime
+ Hledger.Web.Import: not :: Bool -> Bool
+ Hledger.Web.Import: notAuthenticated :: MonadHandler m => m a
+ Hledger.Web.Import: notElem :: (Foldable t, Eq a) => a -> t a -> Bool
+ Hledger.Web.Import: notFound :: MonadHandler m => m a
+ Hledger.Web.Import: notModified :: MonadHandler m => m a
+ Hledger.Web.Import: null :: Foldable t => t a -> Bool
+ Hledger.Web.Import: object :: [Pair] -> Value
+ Hledger.Web.Import: odd :: Integral a => a -> Bool
+ Hledger.Web.Import: onMethod :: Method -> Writer LiteApp () -> Writer LiteApp ()
+ Hledger.Web.Import: onStatic :: Text -> Writer LiteApp () -> Writer LiteApp ()
+ Hledger.Web.Import: onlyUnique :: (MonadIO m, PersistUniqueWrite backend, PersistRecordBackend record backend) => record -> ReaderT backend m Unique record
+ Hledger.Web.Import: optionsEnum :: (MonadHandler m, Show a, Enum a, Bounded a) => m OptionList a
+ Hledger.Web.Import: optionsPairs :: (MonadHandler m, RenderMessage HandlerSite m msg) => [(msg, a)] -> m OptionList a
+ Hledger.Web.Import: optionsPersist :: (YesodPersist site, PersistQueryRead backend, PathPiece Key a, RenderMessage site msg, YesodPersistBackend site ~ backend, PersistRecordBackend a backend) => [Filter a] -> [SelectOpt a] -> a -> msg -> HandlerFor site OptionList Entity a
+ Hledger.Web.Import: optionsPersistKey :: (YesodPersist site, PersistQueryRead backend, PathPiece Key a, RenderMessage site msg, backend ~ YesodPersistBackend site, PersistRecordBackend a backend) => [Filter a] -> [SelectOpt a] -> a -> msg -> HandlerFor site OptionList Key a
+ Hledger.Web.Import: or :: Foldable t => t Bool -> Bool
+ Hledger.Web.Import: otherwise :: Bool
+ Hledger.Web.Import: packPTH :: String -> Text
+ Hledger.Web.Import: parseCheckJsonBody :: (MonadHandler m, FromJSON a) => m Result a
+ Hledger.Web.Import: parseDate :: String -> Either FormMessage Day
+ Hledger.Web.Import: parseExtra :: DefaultEnv -> Object -> Parser Extra
+ Hledger.Web.Import: parseHelper :: (Monad m, RenderMessage site FormMessage) => Text -> Either FormMessage a -> [Text] -> [FileInfo] -> m Either SomeMessage site Maybe a
+ Hledger.Web.Import: parseHelperGen :: (Monad m, RenderMessage site msg) => Text -> Either msg a -> [Text] -> [FileInfo] -> m Either SomeMessage site Maybe a
+ Hledger.Web.Import: parseJSON :: FromJSON a => Value -> Parser a
+ Hledger.Web.Import: parseJSONList :: FromJSON a => Value -> Parser [a]
+ Hledger.Web.Import: parseJsonBody :: (MonadHandler m, FromJSON a) => m Result a
+ Hledger.Web.Import: parseJsonBody_ :: (MonadHandler m, FromJSON a) => m a
+ Hledger.Web.Import: parseReferences :: PersistSettings -> Text -> Q Exp
+ Hledger.Web.Import: parseRoute :: ParseRoute a => ([Text], [(Text, Text)]) -> Maybe Route a
+ Hledger.Web.Import: parseRoutes :: QuasiQuoter
+ Hledger.Web.Import: parseRoutesFile :: FilePath -> Q Exp
+ Hledger.Web.Import: parseRoutesFileNoCheck :: FilePath -> Q Exp
+ Hledger.Web.Import: parseRoutesNoCheck :: QuasiQuoter
+ Hledger.Web.Import: parseTime :: Text -> Either FormMessage TimeOfDay
+ Hledger.Web.Import: parseTimeM :: (Monad m, ParseTime t) => Bool -> TimeLocale -> String -> String -> m t
+ Hledger.Web.Import: parseTimeOrError :: ParseTime t => Bool -> TimeLocale -> String -> String -> t
+ Hledger.Web.Import: partitionEithers :: () => [Either a b] -> ([a], [b])
+ Hledger.Web.Import: passwordField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Text
+ Hledger.Web.Import: permissionDenied :: MonadHandler m => Text -> m a
+ Hledger.Web.Import: permissionDeniedI :: (RenderMessage HandlerSite m msg, MonadHandler m) => msg -> m a
+ Hledger.Web.Import: persistBackend :: HasPersistBackend backend => backend -> BaseBackend backend
+ Hledger.Web.Import: persistFieldDef :: PersistEntity record => EntityField record typ -> FieldDef
+ Hledger.Web.Import: persistFieldFromEntity :: MkPersistSettings -> EntityDef -> Q [Dec]
+ Hledger.Web.Import: persistFileWith :: PersistSettings -> FilePath -> Q Exp
+ Hledger.Web.Import: persistIdField :: PersistEntity record => EntityField record Key record
+ Hledger.Web.Import: persistLowerCase :: QuasiQuoter
+ Hledger.Web.Import: persistManyFileWith :: PersistSettings -> [FilePath] -> Q Exp
+ Hledger.Web.Import: persistUniqueKeys :: PersistEntity record => record -> [Unique record]
+ Hledger.Web.Import: persistUniqueToFieldNames :: PersistEntity record => Unique record -> [(HaskellName, DBName)]
+ Hledger.Web.Import: persistUniqueToValues :: PersistEntity record => Unique record -> [PersistValue]
+ Hledger.Web.Import: persistUpperCase :: QuasiQuoter
+ Hledger.Web.Import: persistWith :: PersistSettings -> QuasiQuoter
+ Hledger.Web.Import: pi :: Floating a => a
+ Hledger.Web.Import: picosecondsToDiffTime :: Integer -> DiffTime
+ Hledger.Web.Import: preEscapedToMarkup :: ToMarkup a => a -> Markup
+ Hledger.Web.Import: pred :: Enum a => a -> a
+ Hledger.Web.Import: print :: Show a => a -> IO ()
+ Hledger.Web.Import: product :: (Foldable t, Num a) => t a -> a
+ Hledger.Web.Import: production :: Bool
+ Hledger.Web.Import: projectBackend :: BackendCompatible sup sub => sub -> sup
+ Hledger.Web.Import: properFraction :: (RealFrac a, Integral b) => a -> (b, a)
+ Hledger.Web.Import: provideJson :: (Monad m, ToJSON a) => a -> Writer Endo [ProvidedRep m] ()
+ Hledger.Web.Import: provideRep :: (Monad m, HasContentType a) => m a -> Writer Endo [ProvidedRep m] ()
+ Hledger.Web.Import: provideRepType :: (Monad m, ToContent a) => ContentType -> m a -> Writer Endo [ProvidedRep m] ()
+ Hledger.Web.Import: pure :: Applicative f => a -> f a
+ Hledger.Web.Import: putChar :: Char -> IO ()
+ Hledger.Web.Import: putMany :: (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend) => [record] -> ReaderT backend m ()
+ Hledger.Web.Import: putStr :: String -> IO ()
+ Hledger.Web.Import: putStrLn :: String -> IO ()
+ Hledger.Web.Import: quot :: Integral a => a -> a -> a
+ Hledger.Web.Import: quotRem :: Integral a => a -> a -> (a, a)
+ Hledger.Web.Import: radioField :: (Eq a, RenderMessage site FormMessage) => HandlerFor site OptionList a -> Field HandlerFor site a
+ Hledger.Web.Import: radioFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg) => [(msg, a)] -> Field HandlerFor site a
+ Hledger.Web.Import: rawRequestBody :: MonadHandler m => ConduitT i ByteString m ()
+ Hledger.Web.Import: read :: Read a => String -> a
+ Hledger.Web.Import: readIO :: Read a => String -> IO a
+ Hledger.Web.Import: readIntegral :: Num a => String -> Maybe a
+ Hledger.Web.Import: readList :: Read a => ReadS [a]
+ Hledger.Web.Import: readLn :: Read a => IO a
+ Hledger.Web.Import: readPTime :: ParseTime t => Bool -> TimeLocale -> String -> ReadP t
+ Hledger.Web.Import: readParen :: () => Bool -> ReadS a -> ReadS a
+ Hledger.Web.Import: readSTime :: ParseTime t => Bool -> TimeLocale -> String -> ReadS t
+ Hledger.Web.Import: readTime :: ParseTime t => TimeLocale -> String -> String -> t
+ Hledger.Web.Import: reads :: Read a => ReadS a
+ Hledger.Web.Import: readsPrec :: Read a => Int -> ReadS a
+ Hledger.Web.Import: readsTime :: ParseTime t => TimeLocale -> String -> ReadS t
+ Hledger.Web.Import: realToFrac :: (Real a, Fractional b) => a -> b
+ Hledger.Web.Import: recip :: Fractional a => a -> a
+ Hledger.Web.Import: redirect :: (MonadHandler m, RedirectUrl HandlerSite m url) => url -> m a
+ Hledger.Web.Import: redirectToPost :: (MonadHandler m, RedirectUrl HandlerSite m url) => url -> m a
+ Hledger.Web.Import: redirectUltDest :: (RedirectUrl HandlerSite m url, MonadHandler m) => url -> m a
+ Hledger.Web.Import: redirectWith :: (MonadHandler m, RedirectUrl HandlerSite m url) => Status -> url -> m a
+ Hledger.Web.Import: rem :: Integral a => a -> a -> a
+ Hledger.Web.Import: renderBootstrap :: Monad m => FormRender m a
+ Hledger.Web.Import: renderBootstrap2 :: Monad m => FormRender m a
+ Hledger.Web.Import: renderCssUrl :: () => url -> [(Text, Text)] -> Text -> CssUrl url -> Text
+ Hledger.Web.Import: renderDivs :: Monad m => FormRender m a
+ Hledger.Web.Import: renderDivsNoLabels :: Monad m => FormRender m a
+ Hledger.Web.Import: renderJavascriptUrl :: () => url -> [(Text, Text)] -> Text -> JavascriptUrl url -> Text
+ Hledger.Web.Import: renderMessage :: RenderMessage master message => master -> [Lang] -> message -> Text
+ Hledger.Web.Import: renderTable :: Monad m => FormRender m a
+ Hledger.Web.Import: repJson :: ToContent a => a -> RepJson
+ Hledger.Web.Import: repPlain :: ToContent a => a -> RepPlain
+ Hledger.Web.Import: repXml :: ToContent a => a -> RepXml
+ Hledger.Web.Import: repeat :: () => a -> [a]
+ Hledger.Web.Import: replace :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()
+ Hledger.Web.Import: replaceOrAddHeader :: MonadHandler m => Text -> Text -> m ()
+ Hledger.Web.Import: replaceUnique :: (MonadIO m, Eq record, Eq Unique record, PersistRecordBackend record backend, PersistUniqueWrite backend) => Key record -> record -> ReaderT backend m Maybe Unique record
+ Hledger.Web.Import: replicate :: () => Int -> a -> [a]
+ Hledger.Web.Import: replicateM :: Applicative m => Int -> m a -> m [a]
+ Hledger.Web.Import: replicateM_ :: Applicative m => Int -> m a -> m ()
+ Hledger.Web.Import: repsert :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> record -> ReaderT backend m ()
+ Hledger.Web.Import: repsertMany :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => [(Key record, record)] -> ReaderT backend m ()
+ Hledger.Web.Import: requireCheckJsonBody :: (MonadHandler m, FromJSON a) => m a
+ Hledger.Web.Import: requireJsonBody :: (MonadHandler m, FromJSON a) => m a
+ Hledger.Web.Import: resourcesApp :: [ResourceTree String]
+ Hledger.Web.Import: respond :: (Monad m, ToContent a) => ContentType -> a -> m TypedContent
+ Hledger.Web.Import: respondSource :: () => ContentType -> ConduitT () Flush Builder HandlerFor site () -> HandlerFor site TypedContent
+ Hledger.Web.Import: respondSourceDB :: YesodPersistRunner site => ContentType -> ConduitT () Flush Builder YesodDB site () -> HandlerFor site TypedContent
+ Hledger.Web.Import: return :: Monad m => a -> m a
+ Hledger.Web.Import: returnJson :: (Monad m, ToJSON a) => a -> m Value
+ Hledger.Web.Import: returnJsonEncoding :: (Monad m, ToJSON a) => a -> m Encoding
+ Hledger.Web.Import: reverse :: () => [a] -> [a]
+ Hledger.Web.Import: rfc822DateFormat :: String
+ Hledger.Web.Import: rights :: () => [Either a b] -> [b]
+ Hledger.Web.Import: round :: (RealFrac a, Integral b) => a -> b
+ Hledger.Web.Import: routeAttrs :: RouteAttrs a => Route a -> Set Text
+ Hledger.Web.Import: runDB :: YesodPersist site => YesodDB site a -> HandlerFor site a
+ Hledger.Web.Import: runDBSource :: YesodPersistRunner site => ConduitT () a YesodDB site () -> ConduitT () a HandlerFor site ()
+ Hledger.Web.Import: runFakeHandler :: (Yesod site, MonadIO m) => SessionMap -> site -> Logger -> site -> HandlerT site IO a -> m Either ErrorResponse a
+ Hledger.Web.Import: runFormGet :: MonadHandler m => Markup -> MForm m a -> m (a, Enctype)
+ Hledger.Web.Import: runFormPost :: (RenderMessage HandlerSite m FormMessage, MonadResource m, MonadHandler m) => Markup -> MForm m (FormResult a, xml) -> m ((FormResult a, xml), Enctype)
+ Hledger.Web.Import: runFormPostNoToken :: MonadHandler m => Markup -> MForm m a -> m (a, Enctype)
+ Hledger.Web.Import: runInputGet :: MonadHandler m => FormInput m a -> m a
+ Hledger.Web.Import: runInputGetResult :: MonadHandler m => FormInput m a -> m FormResult a
+ Hledger.Web.Import: runInputPost :: MonadHandler m => FormInput m a -> m a
+ Hledger.Web.Import: runInputPostResult :: MonadHandler m => FormInput m a -> m FormResult a
+ Hledger.Web.Import: runPool :: (PersistConfig c, MonadUnliftIO m) => c -> PersistConfigBackend c m a -> PersistConfigPool c -> m a
+ Hledger.Web.Import: runRequestBody :: MonadHandler m => m RequestBodyContents
+ Hledger.Web.Import: scaleFloat :: RealFloat a => Int -> a -> a
+ Hledger.Web.Import: scanl :: () => b -> a -> b -> b -> [a] -> [b]
+ Hledger.Web.Import: scanl1 :: () => a -> a -> a -> [a] -> [a]
+ Hledger.Web.Import: scanr :: () => a -> b -> b -> b -> [a] -> [b]
+ Hledger.Web.Import: scanr1 :: () => a -> a -> a -> [a] -> [a]
+ Hledger.Web.Import: searchField :: (Monad m, RenderMessage HandlerSite m FormMessage) => AutoFocus -> Field m Text
+ Hledger.Web.Import: second :: Bifunctor p => b -> c -> p a b -> p a c
+ Hledger.Web.Import: secondsToDiffTime :: Integer -> DiffTime
+ Hledger.Web.Import: selectField :: (Eq a, RenderMessage site FormMessage) => HandlerFor site OptionList a -> Field HandlerFor site a
+ Hledger.Web.Import: selectFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg) => [(msg, a)] -> Field HandlerFor site a
+ Hledger.Web.Import: selectFirst :: (PersistQueryRead backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> [SelectOpt record] -> ReaderT backend m Maybe Entity record
+ Hledger.Web.Import: selectKeys :: (PersistQueryRead BaseBackend backend, MonadResource m, PersistEntity record, BaseBackend BaseBackend backend ~ PersistEntityBackend record, MonadReader backend m, HasPersistBackend backend) => [Filter record] -> [SelectOpt record] -> ConduitM () Key record m ()
+ Hledger.Web.Import: selectKeysList :: (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend) => [Filter record] -> [SelectOpt record] -> ReaderT backend m [Key record]
+ Hledger.Web.Import: selectKeysRes :: (PersistQueryRead backend, MonadIO m1, MonadIO m2, PersistRecordBackend record backend) => [Filter record] -> [SelectOpt record] -> ReaderT backend m1 Acquire ConduitM () Key record m2 ()
+ Hledger.Web.Import: selectList :: (MonadIO m, PersistQueryRead backend, PersistRecordBackend record backend) => [Filter record] -> [SelectOpt record] -> ReaderT backend m [Entity record]
+ Hledger.Web.Import: selectRep :: MonadHandler m => Writer Endo [ProvidedRep m] () -> m TypedContent
+ Hledger.Web.Import: selectSource :: (PersistQueryRead BaseBackend backend, MonadResource m, PersistEntity record, PersistEntityBackend record ~ BaseBackend BaseBackend backend, MonadReader backend m, HasPersistBackend backend) => [Filter record] -> [SelectOpt record] -> ConduitM () Entity record m ()
+ Hledger.Web.Import: selectSourceRes :: (PersistQueryRead backend, PersistRecordBackend record backend, MonadIO m1, MonadIO m2) => [Filter record] -> [SelectOpt record] -> ReaderT backend m1 Acquire ConduitM () Entity record m2 ()
+ Hledger.Web.Import: sendChunk :: (Monad m, ToFlushBuilder a) => a -> ConduitT i Flush Builder m ()
+ Hledger.Web.Import: sendChunkBS :: Monad m => ByteString -> ConduitT i Flush Builder m ()
+ Hledger.Web.Import: sendChunkHtml :: Monad m => Html -> ConduitT i Flush Builder m ()
+ Hledger.Web.Import: sendChunkLBS :: Monad m => ByteString -> ConduitT i Flush Builder m ()
+ Hledger.Web.Import: sendChunkLazyText :: Monad m => Text -> ConduitT i Flush Builder m ()
+ Hledger.Web.Import: sendChunkText :: Monad m => Text -> ConduitT i Flush Builder m ()
+ Hledger.Web.Import: sendFile :: MonadHandler m => ContentType -> FilePath -> m a
+ Hledger.Web.Import: sendFilePart :: MonadHandler m => ContentType -> FilePath -> Integer -> Integer -> m a
+ Hledger.Web.Import: sendFlush :: Monad m => ConduitT i Flush Builder m ()
+ Hledger.Web.Import: sendRawResponse :: (MonadHandler m, MonadUnliftIO m) => ConduitT () ByteString IO () -> ConduitT ByteString Void IO () -> m () -> m a
+ Hledger.Web.Import: sendRawResponseNoConduit :: (MonadHandler m, MonadUnliftIO m) => IO ByteString -> ByteString -> IO () -> m () -> m a
+ Hledger.Web.Import: sendResponse :: (MonadHandler m, ToTypedContent c) => c -> m a
+ Hledger.Web.Import: sendResponseCreated :: MonadHandler m => Route HandlerSite m -> m a
+ Hledger.Web.Import: sendResponseStatus :: (MonadHandler m, ToTypedContent c) => Status -> c -> m a
+ Hledger.Web.Import: sendStatusJSON :: (MonadHandler m, ToJSON c) => Status -> c -> m a
+ Hledger.Web.Import: sendWaiApplication :: MonadHandler m => Application -> m b
+ Hledger.Web.Import: sendWaiResponse :: MonadHandler m => Response -> m b
+ Hledger.Web.Import: seq :: () => a -> b -> b
+ Hledger.Web.Import: sequence :: (Traversable t, Monad m) => t m a -> m t a
+ Hledger.Web.Import: sequenceA :: (Traversable t, Applicative f) => t f a -> f t a
+ Hledger.Web.Import: sequenceA_ :: (Foldable t, Applicative f) => t f a -> f ()
+ Hledger.Web.Import: sequence_ :: (Foldable t, Monad m) => t m a -> m ()
+ Hledger.Web.Import: setCookie :: MonadHandler m => SetCookie -> m ()
+ Hledger.Web.Import: setCsrfCookie :: MonadHandler m => m ()
+ Hledger.Web.Import: setCsrfCookieWithCookie :: MonadHandler m => SetCookie -> m ()
+ Hledger.Web.Import: setEtag :: MonadHandler m => Text -> m ()
+ Hledger.Web.Import: setHeader :: MonadHandler m => Text -> Text -> m ()
+ Hledger.Web.Import: setLanguage :: MonadHandler m => Text -> m ()
+ Hledger.Web.Import: setMessage :: MonadHandler m => Html -> m ()
+ Hledger.Web.Import: setMessageI :: (MonadHandler m, RenderMessage HandlerSite m msg) => msg -> m ()
+ Hledger.Web.Import: setSession :: MonadHandler m => Text -> Text -> m ()
+ Hledger.Web.Import: setSessionBS :: MonadHandler m => Text -> ByteString -> m ()
+ Hledger.Web.Import: setTitle :: MonadWidget m => Html -> m ()
+ Hledger.Web.Import: setTitleI :: (MonadWidget m, RenderMessage HandlerSite m msg) => msg -> m ()
+ Hledger.Web.Import: setUltDest :: (MonadHandler m, RedirectUrl HandlerSite m url) => url -> m ()
+ Hledger.Web.Import: setUltDestCurrent :: MonadHandler m => m ()
+ Hledger.Web.Import: setUltDestReferer :: MonadHandler m => m ()
+ Hledger.Web.Import: setWeakEtag :: MonadHandler m => Text -> m ()
+ Hledger.Web.Import: shamlet :: QuasiQuoter
+ Hledger.Web.Import: share :: [[EntityDef] -> Q [Dec]] -> [EntityDef] -> Q [Dec]
+ Hledger.Web.Import: shouldLogIO :: Yesod site => site -> LogSource -> LogLevel -> IO Bool
+ Hledger.Web.Import: shouldShowSidebar :: Handler Bool
+ Hledger.Web.Import: show :: Show a => a -> String
+ Hledger.Web.Import: showChar :: Char -> ShowS
+ Hledger.Web.Import: showGregorian :: Day -> String
+ Hledger.Web.Import: showIntegral :: Integral a => a -> String
+ Hledger.Web.Import: showList :: Show a => [a] -> ShowS
+ Hledger.Web.Import: showParen :: Bool -> ShowS -> ShowS
+ Hledger.Web.Import: showString :: String -> ShowS
+ Hledger.Web.Import: shows :: Show a => a -> ShowS
+ Hledger.Web.Import: showsPrec :: Show a => Int -> a -> ShowS
+ Hledger.Web.Import: significand :: RealFloat a => a -> a
+ Hledger.Web.Import: signum :: Num a => a -> a
+ Hledger.Web.Import: simpleContentType :: ContentType -> ContentType
+ Hledger.Web.Import: sin :: Floating a => a -> a
+ Hledger.Web.Import: sinh :: Floating a => a -> a
+ Hledger.Web.Import: snd :: () => (a, b) -> b
+ Hledger.Web.Import: span :: () => a -> Bool -> [a] -> ([a], [a])
+ Hledger.Web.Import: splitAt :: () => Int -> [a] -> ([a], [a])
+ Hledger.Web.Import: sqlOnlySettings :: MkPersistSettings
+ Hledger.Web.Import: sqlSettings :: MkPersistSettings
+ Hledger.Web.Import: sqrt :: Floating a => a -> a
+ Hledger.Web.Import: sslOnlyMiddleware :: () => Int -> HandlerFor site res -> HandlerFor site res
+ Hledger.Web.Import: sslOnlySessions :: IO Maybe SessionBackend -> IO Maybe SessionBackend
+ Hledger.Web.Import: staticDir :: FilePath
+ Hledger.Web.Import: staticRoot :: AppConfig DefaultEnv Extra -> Text
+ Hledger.Web.Import: staticSite :: IO Static
+ Hledger.Web.Import: strictSameSiteSessions :: IO Maybe SessionBackend -> IO Maybe SessionBackend
+ Hledger.Web.Import: subtract :: Num a => a -> a -> a
+ Hledger.Web.Import: succ :: Enum a => a -> a
+ Hledger.Web.Import: sum :: (Foldable t, Num a) => t a -> a
+ Hledger.Web.Import: take :: () => Int -> [a] -> [a]
+ Hledger.Web.Import: takeWhile :: () => a -> Bool -> [a] -> [a]
+ Hledger.Web.Import: tan :: Floating a => a -> a
+ Hledger.Web.Import: tanh :: Floating a => a -> a
+ Hledger.Web.Import: textField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Text
+ Hledger.Web.Import: textareaField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Textarea
+ Hledger.Web.Import: timeField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m TimeOfDay
+ Hledger.Web.Import: timeFieldTypeText :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m TimeOfDay
+ Hledger.Web.Import: timeFieldTypeTime :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m TimeOfDay
+ Hledger.Web.Import: timeOfDayToDayFraction :: TimeOfDay -> Rational
+ Hledger.Web.Import: timeOfDayToTime :: TimeOfDay -> DiffTime
+ Hledger.Web.Import: timeToTimeOfDay :: DiffTime -> TimeOfDay
+ Hledger.Web.Import: timeZoneOffsetString :: TimeZone -> String
+ Hledger.Web.Import: timeZoneOffsetString' :: Maybe Char -> TimeZone -> String
+ Hledger.Web.Import: toBackendKey :: ToBackendKey backend record => Key record -> BackendKey backend
+ Hledger.Web.Import: toContent :: ToContent a => a -> Content
+ Hledger.Web.Import: toEmbedEntityDef :: EntityDef -> EmbedEntityDef
+ Hledger.Web.Import: toEncoding :: ToJSON a => a -> Encoding
+ Hledger.Web.Import: toEncodingList :: ToJSON a => [a] -> Encoding
+ Hledger.Web.Import: toEnum :: Enum a => Int -> a
+ Hledger.Web.Import: toFlushBuilder :: ToFlushBuilder a => a -> Flush Builder
+ Hledger.Web.Import: toGregorian :: Day -> (Integer, Int, Int)
+ Hledger.Web.Import: toHtml :: ToMarkup a => a -> Html
+ Hledger.Web.Import: toInteger :: Integral a => a -> Integer
+ Hledger.Web.Import: toJSON :: ToJSON a => a -> Value
+ Hledger.Web.Import: toJSONList :: ToJSON a => [a] -> Value
+ Hledger.Web.Import: toJsonText :: ToJSON j => j -> Text
+ Hledger.Web.Import: toList :: Foldable t => t a -> [a]
+ Hledger.Web.Import: toMessage :: ToMessage a => a -> Text
+ Hledger.Web.Import: toPathMultiPiece :: PathMultiPiece s => s -> [Text]
+ Hledger.Web.Import: toPathPiece :: PathPiece s => s -> Text
+ Hledger.Web.Import: toPersistFields :: PersistEntity record => record -> [SomePersistField]
+ Hledger.Web.Import: toPersistValue :: PersistField a => a -> PersistValue
+ Hledger.Web.Import: toPersistValueJSON :: ToJSON a => a -> PersistValue
+ Hledger.Web.Import: toRational :: Real a => a -> Rational
+ Hledger.Web.Import: toTextUrl :: (RedirectUrl master a, MonadHandler m, HandlerSite m ~ master) => a -> m Text
+ Hledger.Web.Import: toTypedContent :: ToTypedContent a => a -> TypedContent
+ Hledger.Web.Import: toWaiApp :: YesodDispatch site => site -> IO Application
+ Hledger.Web.Import: toWaiAppPlain :: YesodDispatch site => site -> IO Application
+ Hledger.Web.Import: toWaiAppYre :: YesodDispatch site => YesodRunnerEnv site -> Application
+ Hledger.Web.Import: toWidget :: (ToWidget site a, MonadWidget m, HandlerSite m ~ site) => a -> m ()
+ Hledger.Web.Import: toWidgetBody :: (ToWidgetBody site a, MonadWidget m, HandlerSite m ~ site) => a -> m ()
+ Hledger.Web.Import: toWidgetHead :: (ToWidgetHead site a, MonadWidget m, HandlerSite m ~ site) => a -> m ()
+ Hledger.Web.Import: toWidgetMedia :: (ToWidgetMedia site a, MonadWidget m, HandlerSite m ~ site) => Text -> a -> m ()
+ Hledger.Web.Import: traverse :: (Traversable t, Applicative f) => a -> f b -> t a -> f t b
+ Hledger.Web.Import: traverse_ :: (Foldable t, Applicative f) => a -> f b -> t a -> f ()
+ Hledger.Web.Import: truncate :: (RealFrac a, Integral b) => a -> b
+ Hledger.Web.Import: type AppRoute = Route App
+ Hledger.Web.Import: type Application = Request -> Response -> IO ResponseReceived -> IO ResponseReceived
+ Hledger.Web.Import: type Attr = Text
+ Hledger.Web.Import: type AutoFocus = Bool
+ Hledger.Web.Import: type BottomOfHeadAsync master = [Text] -> Maybe HtmlUrl Route master -> HtmlUrl Route master
+ Hledger.Web.Import: type ContentType = ByteString
+ Hledger.Web.Import: type CssUrl url = url -> [(Text, Text)] -> Text -> Css
+ Hledger.Web.Import: type Env = Map Text [Text]
+ Hledger.Web.Import: type ExtraLine = [Text]
+ Hledger.Web.Import: type FieldViewFunc (m :: * -> *) a = Text -> Text -> [(Text, Text)] -> Either Text a -> Bool -> WidgetFor HandlerSite m ()
+ Hledger.Web.Import: type FileEnv = Map Text [FileInfo]
+ Hledger.Web.Import: type FilePath = String
+ Hledger.Web.Import: type ForeignFieldDef = (HaskellName, DBName)
+ Hledger.Web.Import: type Form x = Html -> MForm (HandlerFor App) (FormResult x, Widget)
+ Hledger.Web.Import: type FormRender (m :: * -> *) a = AForm m a -> Markup -> MForm m (FormResult a, WidgetFor HandlerSite m ())
+ Hledger.Web.Import: type Handler = HandlerFor App
+ Hledger.Web.Import: type HandlerT site (m :: * -> *) = HandlerFor site
+ Hledger.Web.Import: type Html = Markup
+ Hledger.Web.Import: type HtmlUrl url = Render url -> Html
+ Hledger.Web.Import: type IOError = IOException
+ Hledger.Web.Import: type JavascriptUrl url = url -> [(Text, Text)] -> Text -> Javascript
+ Hledger.Web.Import: type Lang = Text
+ Hledger.Web.Import: type LiteHandler = HandlerFor LiteApp
+ Hledger.Web.Import: type LiteWidget = WidgetFor LiteApp
+ Hledger.Web.Import: type MForm (m :: * -> *) a = RWST (Maybe (Env, FileEnv), HandlerSite m, [Lang]) Enctype Ints m a
+ Hledger.Web.Import: type Markup = MarkupM ()
+ Hledger.Web.Import: type NumericPadOption = Maybe Char
+ Hledger.Web.Import: type PersistQuery a = PersistQueryWrite a
+ Hledger.Web.Import: type PersistRecordBackend record backend = (PersistEntity record, PersistEntityBackend record ~ BaseBackend backend)
+ Hledger.Web.Import: type PersistStore a = PersistStoreWrite a
+ Hledger.Web.Import: type PersistUnique a = PersistUniqueWrite a
+ Hledger.Web.Import: type Rational = Ratio Integer
+ Hledger.Web.Import: type ReadS a = String -> [(a, String)]
+ Hledger.Web.Import: type RepHtml = Html
+ Hledger.Web.Import: type RequestBodyContents = ([(Text, Text)], [(Text, FileInfo)])
+ Hledger.Web.Import: type SessionMap = Map Text ByteString
+ Hledger.Web.Import: type ShowS = String -> String
+ Hledger.Web.Import: type String = [Char]
+ Hledger.Web.Import: type Texts = [Text]
+ Hledger.Web.Import: type WForm (m :: * -> *) a = MForm WriterT [FieldView HandlerSite m] m a
+ Hledger.Web.Import: type Widget = WidgetFor App ()
+ Hledger.Web.Import: type WidgetT site (m :: * -> *) = WidgetFor site
+ Hledger.Web.Import: type YesodDB site = ReaderT YesodPersistBackend site HandlerFor site
+ Hledger.Web.Import: type family SubHandlerSite (m :: * -> *) :: *;
+ Hledger.Web.Import: typeAtom :: ContentType
+ Hledger.Web.Import: typeCss :: ContentType
+ Hledger.Web.Import: typeFlv :: ContentType
+ Hledger.Web.Import: typeGif :: ContentType
+ Hledger.Web.Import: typeHtml :: ContentType
+ Hledger.Web.Import: typeJavascript :: ContentType
+ Hledger.Web.Import: typeJpeg :: ContentType
+ Hledger.Web.Import: typeJson :: ContentType
+ Hledger.Web.Import: typeOctet :: ContentType
+ Hledger.Web.Import: typeOgv :: ContentType
+ Hledger.Web.Import: typePlain :: ContentType
+ Hledger.Web.Import: typePng :: ContentType
+ Hledger.Web.Import: typeRss :: ContentType
+ Hledger.Web.Import: typeSvg :: ContentType
+ Hledger.Web.Import: typeXml :: ContentType
+ Hledger.Web.Import: unauthorizedI :: (MonadHandler m, RenderMessage HandlerSite m msg) => msg -> m AuthResult
+ Hledger.Web.Import: uncurry :: () => a -> b -> c -> (a, b) -> c
+ Hledger.Web.Import: undefined :: HasCallStack => a
+ Hledger.Web.Import: unfoldr :: () => b -> Maybe (a, b) -> b -> [a]
+ Hledger.Web.Import: unless :: Applicative f => Bool -> f () -> f ()
+ Hledger.Web.Import: unlines :: [String] -> String
+ Hledger.Web.Import: until :: () => a -> Bool -> a -> a -> a -> a
+ Hledger.Web.Import: unwords :: [String] -> String
+ Hledger.Web.Import: unzip :: () => [(a, b)] -> ([a], [b])
+ Hledger.Web.Import: unzip3 :: () => [(a, b, c)] -> ([a], [b], [c])
+ Hledger.Web.Import: update :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> [Update record] -> ReaderT backend m ()
+ Hledger.Web.Import: updateGet :: (PersistStoreWrite backend, MonadIO m, PersistRecordBackend record backend) => Key record -> [Update record] -> ReaderT backend m record
+ Hledger.Web.Import: updateWhere :: (PersistQueryWrite backend, MonadIO m, PersistRecordBackend record backend) => [Filter record] -> [Update record] -> ReaderT backend m ()
+ Hledger.Web.Import: upsert :: (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend) => record -> [Update record] -> ReaderT backend m Entity record
+ Hledger.Web.Import: upsertBy :: (PersistUniqueWrite backend, MonadIO m, PersistRecordBackend record backend) => Unique record -> record -> [Update record] -> ReaderT backend m Entity record
+ Hledger.Web.Import: urlField :: (Monad m, RenderMessage HandlerSite m FormMessage) => Field m Text
+ Hledger.Web.Import: urlParamRenderOverride :: Yesod site => site -> Route site -> [(Text, Text)] -> Maybe Builder
+ Hledger.Web.Import: userError :: String -> IOError
+ Hledger.Web.Import: ut1ToLocalTime :: Rational -> UniversalTime -> LocalTime
+ Hledger.Web.Import: utc :: TimeZone
+ Hledger.Web.Import: utcToLocalTime :: TimeZone -> UTCTime -> LocalTime
+ Hledger.Web.Import: utcToLocalTimeOfDay :: TimeZone -> TimeOfDay -> (Integer, TimeOfDay)
+ Hledger.Web.Import: utcToLocalZonedTime :: UTCTime -> IO ZonedTime
+ Hledger.Web.Import: utcToZonedTime :: TimeZone -> UTCTime -> ZonedTime
+ Hledger.Web.Import: void :: Functor f => f a -> f ()
+ Hledger.Web.Import: wFormToAForm :: MonadHandler m => WForm m FormResult a -> AForm m a
+ Hledger.Web.Import: wFormToMForm :: (MonadHandler m, HandlerSite m ~ site) => WForm m a -> MForm m (a, [FieldView site])
+ Hledger.Web.Import: waiRequest :: MonadHandler m => m Request
+ Hledger.Web.Import: warp :: YesodDispatch site => Int -> site -> IO ()
+ Hledger.Web.Import: warpDebug :: YesodDispatch site => Int -> site -> IO ()
+ Hledger.Web.Import: warpEnv :: YesodDispatch site => site -> IO ()
+ Hledger.Web.Import: whamlet :: QuasiQuoter
+ Hledger.Web.Import: whamletFile :: FilePath -> Q Exp
+ Hledger.Web.Import: whamletFileWithSettings :: HamletSettings -> FilePath -> Q Exp
+ Hledger.Web.Import: when :: Applicative f => Bool -> f () -> f ()
+ Hledger.Web.Import: widgetFile :: String -> Q Exp
+ Hledger.Web.Import: widgetFileSettings :: WidgetFileSettings
+ Hledger.Web.Import: widgetToPageContent :: Yesod site => WidgetFor site () -> HandlerFor site PageContent Route site
+ Hledger.Web.Import: withDynamic :: PathPiece p => p -> Writer LiteApp () -> Writer LiteApp ()
+ Hledger.Web.Import: withDynamicMulti :: PathMultiPiece ps => ps -> Writer LiteApp () -> Writer LiteApp ()
+ Hledger.Web.Import: withRunInIO :: MonadUnliftIO m => forall a. () => m a -> IO a -> IO b -> m b
+ Hledger.Web.Import: withUrlRenderer :: MonadHandler m => Route HandlerSite m -> [(Text, Text)] -> Text -> output -> m output
+ Hledger.Web.Import: wopt :: (MonadHandler m, HandlerSite m ~ site) => Field m a -> FieldSettings site -> Maybe Maybe a -> WForm m FormResult Maybe a
+ Hledger.Web.Import: words :: String -> [String]
+ Hledger.Web.Import: wreq :: (RenderMessage site FormMessage, HandlerSite m ~ site, MonadHandler m) => Field m a -> FieldSettings site -> Maybe a -> WForm m FormResult a
+ Hledger.Web.Import: xhamlet :: QuasiQuoter
+ Hledger.Web.Import: yesodDispatch :: YesodDispatch site => YesodRunnerEnv site -> Application
+ Hledger.Web.Import: yesodMiddleware :: (Yesod site, ToTypedContent res) => HandlerFor site res -> HandlerFor site res
+ Hledger.Web.Import: yesodRender :: Yesod y => y -> ResolvedApproot -> Route y -> [(Text, Text)] -> Text
+ Hledger.Web.Import: yesodRunner :: (ToTypedContent res, Yesod site) => HandlerFor site res -> YesodRunnerEnv site -> Maybe Route site -> Application
+ Hledger.Web.Import: yesodSubDispatch :: YesodSubDispatch sub master => YesodSubRunnerEnv sub master -> Application
+ Hledger.Web.Import: yesodVersion :: String
+ Hledger.Web.Import: yesodWithInternalState :: Yesod site => site -> Maybe Route site -> InternalState -> IO a -> IO a
+ Hledger.Web.Import: zip :: () => [a] -> [b] -> [(a, b)]
+ Hledger.Web.Import: zip3 :: () => [a] -> [b] -> [c] -> [(a, b, c)]
+ Hledger.Web.Import: zipWith :: () => a -> b -> c -> [a] -> [b] -> [c]
+ Hledger.Web.Import: zipWith3 :: () => a -> b -> c -> d -> [a] -> [b] -> [c] -> [d]
+ Hledger.Web.Import: zipWithM :: Applicative m => a -> b -> m c -> [a] -> [b] -> m [c]
+ Hledger.Web.Import: zipWithM_ :: Applicative m => a -> b -> m c -> [a] -> [b] -> m ()
+ Hledger.Web.Import: zonedTimeToUTC :: ZonedTime -> UTCTime
+ Hledger.Web.Import: }
+ Hledger.Web.Main: hledgerWebDev :: IO (Int, Application)
+ Hledger.Web.Main: withJournalDoWeb :: WebOpts -> (WebOpts -> Journal -> IO a) -> IO a
+ Hledger.Web.Settings: Extra :: Text -> Maybe Text -> Maybe Text -> Extra
+ Hledger.Web.Settings: [extraAnalytics] :: Extra -> Maybe Text
+ Hledger.Web.Settings: [extraCopyright] :: Extra -> Text
+ Hledger.Web.Settings: [extraStaticRoot] :: Extra -> Maybe Text
+ Hledger.Web.Settings: data Extra
+ Hledger.Web.Settings: defbaseurl :: String -> Int -> String
+ Hledger.Web.Settings: defhost :: String
+ Hledger.Web.Settings: defport :: Int
+ Hledger.Web.Settings: development :: Bool
+ Hledger.Web.Settings: hledgerorgurl :: Text
+ Hledger.Web.Settings: instance GHC.Show.Show Hledger.Web.Settings.Extra
+ Hledger.Web.Settings: manualurl :: Text
+ Hledger.Web.Settings: parseExtra :: DefaultEnv -> Object -> Parser Extra
+ Hledger.Web.Settings: production :: Bool
+ Hledger.Web.Settings: staticDir :: FilePath
+ Hledger.Web.Settings: staticRoot :: AppConfig DefaultEnv Extra -> Text
+ Hledger.Web.Settings: widgetFile :: String -> Q Exp
+ Hledger.Web.Settings: widgetFileSettings :: WidgetFileSettings
+ Hledger.Web.Settings.StaticFiles: css_bootstrap_css :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: css_bootstrap_css_map :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: css_bootstrap_datepicker_standalone_min_css :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: css_bootstrap_min_css :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: css_bootstrap_theme_css :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: css_bootstrap_theme_css_map :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: css_bootstrap_theme_min_css :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: fonts_glyphicons_halflings_regular_eot :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: fonts_glyphicons_halflings_regular_svg :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: fonts_glyphicons_halflings_regular_ttf :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: fonts_glyphicons_halflings_regular_woff :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: hledger_css :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: hledger_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_bootstrap_datepicker_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_bootstrap_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_bootstrap_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_excanvas_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_excanvas_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_cookie_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_canvas_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_canvas_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_categories_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_categories_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_crosshair_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_crosshair_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_errorbars_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_errorbars_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_fillbetween_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_fillbetween_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_image_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_image_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_navigate_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_navigate_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_pie_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_pie_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_resize_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_resize_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_selection_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_selection_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_stack_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_stack_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_symbol_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_symbol_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_threshold_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_threshold_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_time_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_time_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_tooltip_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_flot_tooltip_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_hotkeys_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_jquery_url_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_typeahead_bundle_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: js_typeahead_bundle_min_js :: StaticRoute
+ Hledger.Web.Settings.StaticFiles: staticSite :: IO Static
+ Hledger.Web.WebOptions: CapAdd :: Capability
+ Hledger.Web.WebOptions: CapManage :: Capability
+ Hledger.Web.WebOptions: CapView :: Capability
+ Hledger.Web.WebOptions: [capabilitiesHeader_] :: WebOpts -> Maybe (CI ByteString)
+ Hledger.Web.WebOptions: [capabilities_] :: WebOpts -> [Capability]
+ Hledger.Web.WebOptions: capabilityFromBS :: ByteString -> Either ByteString Capability
+ Hledger.Web.WebOptions: capabilityFromText :: Text -> Either Text Capability
+ Hledger.Web.WebOptions: data Capability
+ Hledger.Web.WebOptions: instance Data.Default.Class.Default Hledger.Web.WebOptions.WebOpts
+ Hledger.Web.WebOptions: instance GHC.Classes.Eq Hledger.Web.WebOptions.Capability
+ Hledger.Web.WebOptions: instance GHC.Classes.Ord Hledger.Web.WebOptions.Capability
+ Hledger.Web.WebOptions: instance GHC.Enum.Bounded Hledger.Web.WebOptions.Capability
+ Hledger.Web.WebOptions: instance GHC.Enum.Enum Hledger.Web.WebOptions.Capability
+ Hledger.Web.WebOptions: instance GHC.Show.Show Hledger.Web.WebOptions.Capability
+ Hledger.Web.Widget.AddForm: addForm :: (site ~ HandlerSite m, RenderMessage site FormMessage, MonadHandler m) => Journal -> Day -> Markup -> MForm m (FormResult Transaction, WidgetFor site ())
+ Hledger.Web.Widget.AddForm: addModal :: (MonadWidget m, r ~ Route (HandlerSite m), m ~ WidgetFor (HandlerSite m), RenderMessage (HandlerSite m) FormMessage) => r -> Journal -> Day -> m ()
+ Hledger.Web.Widget.Common: accountOnlyQuery :: AccountName -> Text
+ Hledger.Web.Widget.Common: accountQuery :: AccountName -> Text
+ Hledger.Web.Widget.Common: balanceReportAsHtml :: Eq r => (r, r) -> r -> Bool -> Journal -> [QueryOpt] -> BalanceReport -> HtmlUrl r
+ Hledger.Web.Widget.Common: fromFormSuccess :: Applicative m => m a -> FormResult a -> m a
+ Hledger.Web.Widget.Common: helplink :: Text -> Text -> HtmlUrl r
+ Hledger.Web.Widget.Common: journalFile404 :: FilePath -> Journal -> HandlerFor m (FilePath, Text)
+ Hledger.Web.Widget.Common: mixedAmountAsHtml :: MixedAmount -> HtmlUrl a
+ Hledger.Web.Widget.Common: writeValidJournal :: MonadHandler m => FilePath -> Text -> m (Either String ())
- Hledger.Web.WebOptions: WebOpts :: Bool -> String -> Int -> String -> Maybe String -> CliOpts -> WebOpts
+ Hledger.Web.WebOptions: WebOpts :: Bool -> String -> Int -> String -> Maybe String -> [Capability] -> Maybe (CI ByteString) -> CliOpts -> WebOpts
- Hledger.Web.WebOptions: webflags :: [Flag [([Char], [Char])]]
+ Hledger.Web.WebOptions: webflags :: [Flag [(String, String)]]
- Hledger.Web.WebOptions: webmode :: Mode [([Char], [Char])]
+ Hledger.Web.WebOptions: webmode :: Mode [(String, String)]
Files
- Application.hs +0/−88
- CHANGES +15/−0
- Foundation.hs +0/−397
- Handler/AddForm.hs +0/−124
- Handler/Common.hs +0/−251
- Handler/JournalR.hs +0/−88
- Handler/RegisterR.hs +0/−181
- Handler/RootR.hs +0/−8
- Handler/SidebarR.hs +0/−15
- Handler/Utils.hs +0/−20
- Hledger/Web.hs +6/−6
- Hledger/Web/Application.hs +53/−0
- Hledger/Web/Foundation.hs +232/−0
- Hledger/Web/Handler/AddR.hs +40/−0
- Hledger/Web/Handler/Common.hs +38/−0
- Hledger/Web/Handler/EditR.hs +47/−0
- Hledger/Web/Handler/JournalR.hs +31/−0
- Hledger/Web/Handler/RegisterR.hs +60/−0
- Hledger/Web/Handler/UploadR.hs +63/−0
- Hledger/Web/Import.hs +31/−0
- Hledger/Web/Main.hs +44/−43
- Hledger/Web/Settings.hs +100/−0
- Hledger/Web/Settings/StaticFiles.hs +31/−0
- Hledger/Web/WebOptions.hs +133/−74
- Hledger/Web/Widget/AddForm.hs +144/−0
- Hledger/Web/Widget/Common.hs +89/−0
- Import.hs +0/−22
- Settings.hs +0/−92
- Settings/Development.hs +0/−15
- Settings/StaticFiles.hs +0/−33
- config/routes +8/−5
- hledger-web.1 +1/−1
- hledger-web.cabal +41/−128
- hledger-web.info +4/−4
- hledger-web.txt +1/−1
- messages/en.msg +0/−1
- static/hledger.css +14/−85
- static/hledger.js +44/−107
- templates/add-form.hamlet +71/−0
- templates/balance-report.hamlet +25/−0
- templates/chart.hamlet +59/−0
- templates/default-layout-wrapper.hamlet +1/−59
- templates/default-layout.hamlet +81/−4
- templates/edit-form.hamlet +17/−0
- templates/journal.hamlet +39/−0
- templates/manage.hamlet +22/−0
- templates/register.hamlet +37/−0
- templates/upload-form.hamlet +14/−0
- tests/HomeTest.hs +0/−25
- tests/TestImport.hs +0/−12
- tests/main.hs +0/−24
− Application.hs
@@ -1,88 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE CPP, OverloadedStrings, TemplateHaskell #-}-module Application- ( makeApplication- , getApplicationDev- , makeFoundation- ) where--import Data.Default-import Data.IORef-import Import-import Yesod.Default.Config-import Yesod.Default.Main-import Yesod.Default.Handlers-import Network.Wai.Middleware.RequestLogger (logStdoutDev, logStdout)-import Network.HTTP.Conduit (newManager)-import Prelude (head)---- adapt to http-conduit 1.x or 2.x when cabal macros are available, otherwise assume 2.x-#ifdef MIN_VERSION_http_conduit-#if MIN_VERSION_http_conduit(2,0,0)-#define http_conduit_2-#endif-#else-#define http_conduit_2-#endif-#ifdef http_conduit_2-import Network.HTTP.Client (defaultManagerSettings)-#else-import Network.HTTP.Conduit (def)-#endif---- Import all relevant handler modules here.--- Don't forget to add new modules to your cabal file!-import Handler.RootR-import Handler.JournalR-import Handler.RegisterR-import Handler.SidebarR--import Hledger.Web.WebOptions (WebOpts(..), defwebopts)-import Hledger.Data (Journal, nulljournal)-import Hledger.Read (readJournalFile)-import Hledger.Utils (error')-import Hledger.Cli.CliOptions (defcliopts, journalFilePathFromOpts)---- This line actually creates our YesodDispatch instance. It is the second half--- of the call to mkYesodData which occurs in Foundation.hs. Please see the--- comments there for more details.-mkYesodDispatch "App" resourcesApp---- This function allocates resources (such as a database connection pool),--- performs initialization and creates a WAI application. This is also the--- place to put your migrate statements to have automatic database--- migrations handled by Yesod.-makeApplication :: WebOpts -> Journal -> AppConfig DefaultEnv Extra -> IO Application-makeApplication opts j conf = do- foundation <- makeFoundation conf opts- writeIORef (appJournal foundation) j- app <- toWaiAppPlain foundation- return $ logWare app- where- logWare | development = logStdoutDev- | serve_ opts = logStdout- | otherwise = id--makeFoundation :: AppConfig DefaultEnv Extra -> WebOpts -> IO App-makeFoundation conf opts = do- manager <- newManager-#ifdef http_conduit_2- defaultManagerSettings-#else- def-#endif- s <- staticSite- jref <- newIORef nulljournal- return $ App conf s manager opts jref---- for yesod devel--- uses the journal specified by the LEDGER_FILE env var, or ~/.hledger.journal-getApplicationDev :: IO (Int, Application)-getApplicationDev = do- f <- head `fmap` journalFilePathFromOpts defcliopts -- XXX head should be safe for now- j <- either error' id `fmap` readJournalFile def f- defaultDevelApp loader (makeApplication defwebopts j)- where- loader = Yesod.Default.Config.loadConfig (configSettings Development)- { csParseExtra = parseExtra- }
CHANGES view
@@ -1,6 +1,21 @@ User-visible changes in hledger-web. See also hledger, hledger-lib. +# 1.10 (2018/6/30)++* multiple -f options, and --auto, work again++* view, add, edit permissions can be set at CLI or by Sandstorm HTTP header++* the edit form has been revived, for whole-journal editing++* the journal can now be uploaded and downloaded++* the e key toggles empty accounts in the sidebar++* use hledger-lib 1.10++ # 1.9.2 (2018/4/30) * use hledger-lib 1.9.1
− Foundation.hs
@@ -1,397 +0,0 @@-{-# LANGUAGE CPP, MultiParamTypeClasses, OverloadedStrings, RecordWildCards, QuasiQuotes, TemplateHaskell, TypeFamilies, TypeSynonymInstances, FlexibleInstances #-}-{---Define the web application's foundation, in the usual Yesod style.-See a default Yesod app's comments for more details of each part.---}-module Foundation where--import Prelude-#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$>))-#endif-import Data.IORef-import Yesod-import Yesod.Static-import Yesod.Default.Config-#ifndef DEVELOPMENT-import Yesod.Default.Util (addStaticContentExternal)-#endif-import Network.HTTP.Conduit (Manager)--- import qualified Settings-import Settings.StaticFiles-import Settings (staticRoot, widgetFile, Extra (..))-#ifndef DEVELOPMENT-import Settings (staticDir)-import Text.Jasmine (minifym)-#endif-import Text.Blaze.Html.Renderer.String (renderHtml)-import Text.Hamlet (hamletFile)--import Hledger.Web.WebOptions-import Hledger.Data.Types--- import Hledger.Web.Settings--- import Hledger.Web.Settings.StaticFiles---- for addform-import Data.List-import Data.Maybe-import Data.Text as Text (Text,pack,unpack)-import Data.Time.Calendar-#if BLAZE_HTML_0_4-import Text.Blaze (preEscapedString, Markup)-#else-import Text.Blaze (Markup)-import Text.Blaze.Internal (preEscapedString)-#endif-import Text.JSON-import Hledger.Data.Journal-import Hledger.Query-import Hledger hiding (is)-import Hledger.Cli hiding (version)----- | The site argument for your application. This can be a good place to--- keep settings and values requiring initialization before your application--- starts running, such as database connections. Every handler will have--- access to the data present here.-data App = App- { settings :: AppConfig DefaultEnv Extra- , getStatic :: Static -- ^ Settings for static file serving.- , httpManager :: Manager- --- , appOpts :: WebOpts- , appJournal :: IORef Journal- }---- Set up i18n messages. See the message folder.-mkMessage "App" "messages" "en"---- This is where we define all of the routes in our application. For a full--- explanation of the syntax, please see:--- http://www.yesodweb.com/book/handler------ This function does three things:------ * Creates the route datatype AppRoute. Every valid URL in your--- application can be represented as a value of this type.--- * Creates the associated type:--- type instance Route App = AppRoute--- * Creates the value resourcesApp which contains information on the--- resources declared below. This is used in Handler.hs by the call to--- mkYesodDispatch------ What this function does *not* do is create a YesodSite instance for--- App. Creating that instance requires all of the handler functions--- for our application to be in scope. However, the handler functions--- usually require access to the AppRoute datatype. Therefore, we--- split these actions into two functions and place them in separate files.-mkYesodData "App" $(parseRoutesFile "config/routes")---- | A convenience alias.-type AppRoute = Route App--#if MIN_VERSION_yesod(1,6,0)-type Form x = Html -> MForm (HandlerFor App) (FormResult x, Widget)-#else-type Form x = Html -> MForm (HandlerT App IO) (FormResult x, Widget)-#endif---- Please see the documentation for the Yesod typeclass. There are a number--- of settings which can be configured by overriding methods here.-instance Yesod App where- approot = ApprootMaster $ appRoot . settings---- -- Store session data on the client in encrypted cookies,--- -- default session idle timeout is 120 minutes--- makeSessionBackend _ = fmap Just $ defaultClientSessionBackend--- (120 * 60)--- ".hledger-web_client_session_key.aes"- -- don't use session data- makeSessionBackend _ = return Nothing-- defaultLayout widget = do- master <- getYesod- lastmsg <- getMessage- vd@VD{..} <- getViewData-- -- We break up the default layout into two components:- -- default-layout is the contents of the body tag, and- -- default-layout-wrapper is the entire page. Since the final- -- value passed to hamletToRepHtml cannot be a widget, this allows- -- you to use normal widget features in default-layout.-- -- pc <- widgetToPageContent $ do- -- $(widgetFile "normalize")- -- addStylesheet $ StaticR css_bootstrap_css- -- $(widgetFile "default-layout")- -- hamletToRepHtml $(hamletFile "templates/default-layout-wrapper.hamlet")-- pc <- widgetToPageContent $ do- addStylesheet $ StaticR css_bootstrap_min_css- addStylesheet $ StaticR css_bootstrap_datepicker_standalone_min_css- -- load these things early, in HEAD:- toWidgetHead [hamlet|- <script type="text/javascript" src="@{StaticR js_jquery_min_js}">- <script type="text/javascript" src="@{StaticR js_typeahead_bundle_min_js}">- |]- addScript $ StaticR js_bootstrap_min_js- -- addScript $ StaticR js_typeahead_bundle_min_js- addScript $ StaticR js_bootstrap_datepicker_min_js- addScript $ StaticR js_jquery_url_js- addScript $ StaticR js_jquery_cookie_js- addScript $ StaticR js_jquery_hotkeys_js- addScript $ StaticR js_jquery_flot_min_js- addScript $ StaticR js_jquery_flot_time_min_js- addScript $ StaticR js_jquery_flot_tooltip_min_js- toWidget [hamlet| \<!--[if lte IE 8]> <script type="text/javascript" src="@{StaticR js_excanvas_min_js}"></script> <![endif]--> |]- addStylesheet $ StaticR hledger_css- addScript $ StaticR hledger_js- $(widgetFile "default-layout")-- staticRootUrl <- (staticRoot . settings) <$> getYesod- withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")-- -- TODO outdated, still needed ?- -- This is done to provide an optimization for serving static files from- -- a separate domain. Please see the staticRoot setting in Settings.hs- -- urlRenderOverride y (StaticR s) =- -- Just $ uncurry (joinPath y (Settings.staticRoot $ settings y)) $ renderRoute s- urlParamRenderOverride _ _ _ = Nothing--#ifndef DEVELOPMENT- -- This function creates static content files in the static folder- -- and names them based on a hash of their content. This allows- -- expiration dates to be set far in the future without worry of- -- users receiving stale content.- addStaticContent = addStaticContentExternal minifym base64md5 Settings.staticDir (StaticR . flip StaticRoute [])-#endif-- -- Place Javascript at bottom of the body tag so the rest of the page loads first- jsLoader _ = BottomOfBody---- This instance is required to use forms. You can modify renderMessage to--- achieve customized and internationalized form validation messages.-instance RenderMessage App FormMessage where- renderMessage _ _ = defaultFormMessage---- | Get the 'Extra' value, used to hold data from the settings.yml file.-getExtra :: Handler Extra-getExtra = fmap (appExtra . settings) getYesod---- Note: previous versions of the scaffolding included a deliver function to--- send emails. Unfortunately, there are too many different options for us to--- give a reasonable default. Instead, the information is available on the--- wiki:------ https://github.com/yesodweb/yesod/wiki/Sending-email---------------------------------------------------------------------------- template and handler utilities---- view data, used by the add form and handlers---- | A bundle of data useful for hledger-web request handlers and templates.-data ViewData = VD {- opts :: WebOpts -- ^ the command-line options at startup- ,here :: AppRoute -- ^ the current route- ,msg :: Maybe Html -- ^ the current UI message if any, possibly from the current request- ,today :: Day -- ^ today's date (for queries containing relative dates)- ,j :: Journal -- ^ the up-to-date parsed unfiltered journal- ,q :: String -- ^ the current q parameter, the main query expression- ,m :: Query -- ^ a query parsed from the q parameter- ,qopts :: [QueryOpt] -- ^ query options parsed from the q parameter- ,am :: Query -- ^ a query parsed from the accounts sidebar query expr ("a" parameter)- ,aopts :: [QueryOpt] -- ^ query options parsed from the accounts sidebar query expr- ,showpostings :: Bool -- ^ current p parameter, 1 or 0 shows/hides all postings where applicable- ,showsidebar :: Bool -- ^ current showsidebar cookie value- } deriving (Show)--instance Show Text.Blaze.Markup where show _ = "<blaze markup>"---- | Make a default ViewData, using day 0 as today's date.-nullviewdata :: ViewData-nullviewdata = viewdataWithDateAndParams nulldate "" "" ""---- | Make a ViewData using the given date and request parameters, and defaults elsewhere.-viewdataWithDateAndParams :: Day -> String -> String -> String -> ViewData-viewdataWithDateAndParams d q a p =- let (querymatcher,queryopts) = parseQuery d (pack q)- (acctsmatcher,acctsopts) = parseQuery d (pack a)- in VD {- opts = defwebopts- ,j = nulljournal- ,here = RootR- ,msg = Nothing- ,today = d- ,q = q- ,m = querymatcher- ,qopts = queryopts- ,am = acctsmatcher- ,aopts = acctsopts- ,showpostings = p == "1"- ,showsidebar = True- }---- | Gather data used by handlers and templates in the current request.-getViewData :: Handler ViewData-getViewData = do- mhere <- getCurrentRoute- case mhere of- Nothing -> return nullviewdata- Just here -> do- app <- getYesod- let opts@WebOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} = appOpts app- today <- liftIO getCurrentDay- (j, merr) <- getCurrentJournal app copts{reportopts_=ropts{no_elide_=True}} today- lastmsg <- getLastMessage- let msg = maybe lastmsg (Just . toHtml) merr- q <- getParameterOrNull "q"- a <- getParameterOrNull "a"- p <- getParameterOrNull "p"- -- sidebar visibility: show it, unless there is a showsidebar cookie- -- set to "0", or a ?sidebar=0 query parameter.- msidebarparam <- lookupGetParam "sidebar"- msidebarcookie <- reqCookies <$> getRequest >>= return . lookup "showsidebar"- let showsidebar = maybe (msidebarcookie /= Just "0") (/="0") msidebarparam-- return (viewdataWithDateAndParams today q a p){- opts=opts- ,msg=msg- ,here=here- ,today=today- ,j=j- ,showsidebar=showsidebar- }- where- -- | Update our copy of the journal if the file changed. If there is an- -- error while reloading, keep the old one and return the error, and set a- -- ui message.- getCurrentJournal :: App -> CliOpts -> Day -> Handler (Journal, Maybe String)- getCurrentJournal app opts d = do- -- XXX put this inside atomicModifyIORef' for thread safety- j <- liftIO $ readIORef $ appJournal app- (ej, changed) <- liftIO $ journalReloadIfChanged opts d j- -- re-apply any initial filter specified at startup- let initq = queryFromOpts d $ reportopts_ opts- ej' = filterJournalTransactions initq <$> ej- if not changed- then return (j,Nothing)- else case ej' of- Right j' -> do liftIO $ writeIORef (appJournal app) j'- return (j',Nothing)- Left e -> do setMessage $ "error while reading" {- ++ ": " ++ e-}- return (j, Just e)-- -- | Get the named request parameter, or the empty string if not present.- getParameterOrNull :: String -> Handler String- getParameterOrNull p = unpack `fmap` fromMaybe "" <$> lookupGetParam (pack p)---- | Get the message that was set by the last request, in a--- referentially transparent manner (allowing multiple reads).-getLastMessage :: Handler (Maybe Html)-getLastMessage = cached getMessage---- add form dialog, part of the default template---- | Add transaction form.-addform :: Text -> ViewData -> HtmlUrl AppRoute-addform _ vd@VD{..} = [hamlet|--<script>- jQuery(document).ready(function() {-- /* set up typeahead fields */-- descriptionsSuggester = new Bloodhound({- local:#{listToJsonValueObjArrayStr descriptions},- limit:100,- datumTokenizer: function(d) { return [d.value]; },- queryTokenizer: function(q) { return [q]; }- });- descriptionsSuggester.initialize();-- accountsSuggester = new Bloodhound({- local:#{listToJsonValueObjArrayStr accts},- limit:100,- datumTokenizer: function(d) { return [d.value]; },- queryTokenizer: function(q) { return [q]; }- /*- datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),- datumTokenizer: Bloodhound.tokenizers.whitespace(d.value)- queryTokenizer: Bloodhound.tokenizers.whitespace- */- });- accountsSuggester.initialize();-- enableTypeahead(jQuery('input#description'), descriptionsSuggester);- enableTypeahead(jQuery('input#account1, input#account2, input#account3, input#account4'), accountsSuggester);-- });--<form#addform method=POST .form>- <div .form-group>- <div .row>- <div .col-md-3 .col-xs-6 .col-sm-6>- <div #dateWrap .input-group .date>- <input #date required lang=en name=date .form-control .input-lg placeholder="Date" >- <div .input-group-addon>- <span .glyphicon .glyphicon-th>- <div .col-md-9 .col-xs-6 .col-sm-6>- <input #description required .typeahead .form-control .input-lg type=text size=40 name=description placeholder="Description">- <div .account-postings>- $forall n <- postingnums- ^{postingfields vd n}- <div .col-md-8 .col-xs-8 .col-sm-8>- <div .col-md-4 .col-xs-4 .col-sm-4>- <button type=submit .btn .btn-default .btn-lg name=submit>add- $if length filepaths > 1- <br>- <span class="input-lg">to:- ^{journalselect filepaths}- <span style="padding-left:2em;">- <span .small>- Enter a value in the last field for- <a href="#" onclick="addformAddPosting(); return false;">more- (or ctrl +, ctrl -)-|]- where- descriptions = sort $ nub $ map tdescription $ jtxns j- accts = journalAccountNamesDeclaredOrImplied j- escapeJSSpecialChars = regexReplaceCI "</script>" "<\\/script>" -- #236- listToJsonValueObjArrayStr as = preEscapedString $ escapeJSSpecialChars $ encode $ JSArray $ map (\a -> JSObject $ toJSObject [("value", showJSON a)]) as- numpostings = 4- postingnums = [1..numpostings]- filepaths = map fst $ jfiles j- postingfields :: ViewData -> Int -> HtmlUrl AppRoute- postingfields _ n = [hamlet|-<div .form-group .row .account-group ##{grpvar}>- <div .col-md-8 .col-xs-8 .col-sm-8>- <input ##{acctvar} .account-input .typeahead .form-control .input-lg type=text name=#{acctvar} placeholder="#{acctph}">- <div .col-md-4 .col-xs-4 .col-sm-4>- <input ##{amtvar} .amount-input .form-control .input-lg type=text name=#{amtvar} placeholder="#{amtph}">-|]- where- acctvar = "account" ++ show n- acctph = "Account " ++ show n- amtvar = "amount" ++ show n- amtph = "Amount " ++ show n- grpvar = "grp" ++ show n--journalselect :: [FilePath] -> HtmlUrl AppRoute-journalselect journalfilepaths = [hamlet|-<select id=journalselect name=journal onchange="/*journalSelect(event)*/" class="form-control input-lg" style="width:auto; display:inline-block;">- $forall p <- journalfilepaths- <option value=#{p}>#{p}-|]--journalradio :: [FilePath] -> HtmlUrl AppRoute-journalradio journalfilepaths = [hamlet|- $forall p <- journalfilepaths- <div style="white-space:nowrap;">- <span class="input-lg" style="position:relative; top:-8px; left:8px;">#{p}- <input name=journal type=radio value=#{p} class="form-control" style="width:auto; display:inline;">-|]-
− Handler/AddForm.hs
@@ -1,124 +0,0 @@-{-# LANGUAGE CPP, FlexibleContexts, OverloadedStrings, QuasiQuotes, RecordWildCards, TypeFamilies #-}--- | Add form data & handler. (The layout and js are defined in--- Foundation so that the add form can be in the default layout for--- all views.)--module Handler.AddForm where--import Import--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative-#endif-import Control.Monad.State.Strict (evalStateT)-import Data.Either (lefts,rights)-import Data.List (sort)-import qualified Data.List as L (head) -- qualified keeps dev & prod builds warning-free-import Data.Text (append, pack, unpack)-import qualified Data.Text as T-import Data.Time.Calendar-import Text.Megaparsec.Compat (digitChar, eof, some, string, runParser, ParseError, MPErr)--import Hledger.Utils-import Hledger.Data-import Hledger.Read-import Hledger.Cli.Commands.Add (appendToJournalFileOrStdout)----- Part of the data required from the add form.--- Don't know how to handle the variable posting fields with yesod-form yet.-data AddForm = AddForm- { addFormDate :: Day- , addFormDescription :: Maybe Text -- String- -- , addFormPostings :: [(AccountName, String)]- , addFormJournalFile :: Maybe Text -- FilePath- }- deriving Show--postAddForm :: Handler Html-postAddForm = do- let showErrors errs = do- -- error $ show errs -- XXX uncomment to prevent redirect for debugging- setMessage [shamlet|- Errors:<br>- $forall e<-errs- \#{e}<br>- |]- -- 1. process the fixed fields with yesod-form-- VD{..} <- getViewData- let- validateJournalFile :: Text -> Either FormMessage Text- validateJournalFile f- | unpack f `elem` journalFilePaths j = Right f- | otherwise = Left $ MsgInvalidEntry $ pack "the selected journal file \"" `append` f `append` "\"is unknown"-- validateDate :: Text -> Handler (Either FormMessage Day)- validateDate s = return $- case fixSmartDateStrEither' today $ T.pack $ strip $ unpack s of- Right d -> Right d- Left _ -> Left $ MsgInvalidEntry $ pack "could not parse date \"" `append` s `append` pack "\":" -- ++ show e)-- formresult <- runInputPostResult $ AddForm- <$> ireq (checkMMap validateDate (pack . show) textField) "date"- <*> iopt textField "description"- <*> iopt (check validateJournalFile textField) "journal"- - ok <- case formresult of- FormMissing -> showErrors ["there is no form data"::String] >> return False- FormFailure errs -> showErrors errs >> return False- FormSuccess dat -> do- let AddForm{- addFormDate =date- ,addFormDescription=mdesc- ,addFormJournalFile=mjournalfile- } = dat- desc = maybe "" unpack mdesc- journalfile = maybe (journalFilePath j) unpack mjournalfile-- -- 2. the fixed fields look good; now process the posting fields adhocly,- -- getting either errors or a balanced transaction-- (params,_) <- runRequestBody- let numberedParams s =- reverse $ dropWhile (T.null . snd) $ reverse $ sort- [ (n,v) | (k,v) <- params- , let en = parsewith (paramnamep s) k :: Either (ParseError Char MPErr) Int- , isRight en- , let Right n = en- ]- where paramnamep s = do {string s; n <- some digitChar; eof; return (read n :: Int)}- acctparams = numberedParams "account"- amtparams = numberedParams "amount"- num = length acctparams- paramErrs | num == 0 = ["at least one posting must be entered"]- | map fst acctparams == [1..num] &&- map fst amtparams `elem` [[1..num], [1..num-1]] = []- | otherwise = ["the posting parameters are malformed"]- eaccts = map (runParser (accountnamep <* eof) "" . textstrip . snd) acctparams- eamts = map (runParser (evalStateT (amountp <* eof) mempty) "" . textstrip . snd) amtparams- (accts, acctErrs) = (rights eaccts, map show $ lefts eaccts)- (amts', amtErrs) = (rights eamts, map show $ lefts eamts)- amts | length amts' == num = amts'- | otherwise = amts' ++ [missingamt]- errs = if not (null paramErrs) then paramErrs else (acctErrs ++ amtErrs)- etxn | not $ null errs = Left errs- | otherwise = either (\e -> Left [L.head $ lines e]) Right- (balanceTransaction Nothing $ nulltransaction {- tdate=date- ,tdescription=T.pack desc- ,tpostings=[nullposting{paccount=acct, pamount=Mixed [amt]} | (acct,amt) <- zip accts amts]- })- case etxn of- Left errs -> showErrors errs >> return False- Right t -> do- -- 3. all fields look good and form a balanced transaction; append it to the file- liftIO $ do ensureJournalFileExists journalfile- appendToJournalFileOrStdout journalfile $- showTransaction $- txnTieKnot -- XXX move into balanceTransaction- t- setMessage [shamlet|<span>Transaction added.|]- return True-- if ok then redirect JournalR else redirect (JournalR, [("add","1")])
− Handler/Common.hs
@@ -1,251 +0,0 @@-{-# LANGUAGE CPP, OverloadedStrings, QuasiQuotes, RecordWildCards #-}--- | Common page components and rendering helpers.--- For global page layout, see Application.hs.--module Handler.Common where--import Import---- import Data.Text (Text)-import qualified Data.Text as T-import Data.Time.Calendar-import System.FilePath (takeFileName)-#if BLAZE_HTML_0_4-import Text.Blaze (preEscapedString)-#else-import Text.Blaze.Internal (preEscapedString)-#endif-import Text.Printf--import Hledger.Utils-import Hledger.Data-import Hledger.Query-import Hledger.Reports-import Hledger.Cli.CliOptions-import Hledger.Web.WebOptions------------------------------------------------------------------------------------ Common page layout---- | Standard hledger-web page layout.-#if MIN_VERSION_yesod(1,6,0)-hledgerLayout :: ViewData -> String -> HtmlUrl AppRoute -> HandlerFor App Html-#else-hledgerLayout :: ViewData -> String -> HtmlUrl AppRoute -> HandlerT App IO Html-#endif-hledgerLayout vd title content = do- defaultLayout $ do- setTitle $ toHtml $ title ++ " - hledger-web"- toWidget [hamlet|- ^{topbar vd}- ^{sidebar vd}- <div #main-content .col-xs-12 .#{showmd} .#{showsm}>- ^{searchform vd}- ^{content}- |]- where- showmd = if showsidebar vd then "col-md-8" else "col-md-12" :: String- showsm = if showsidebar vd then "col-sm-8" else "col-sm-12" :: String---- | Global toolbar/heading area.-topbar :: ViewData -> HtmlUrl AppRoute-topbar VD{..} = [hamlet|-<div#spacer .#{showsm} .#{showmd} .col-xs-2>- <h1>- <button .visible-xs .btn .btn-default type="button" data-toggle="offcanvas">- <span .glyphicon .glyphicon-align-left .tgl-icon>-<div#topbar .col-md-8 .col-sm-8 .col-xs-10>- <h1>#{title}--|]- where- title = takeFileName $ journalFilePath j- showmd = if showsidebar then "col-md-4" else "col-any-0" :: String- showsm = if showsidebar then "col-sm-4" else "" :: String---- | The sidebar used on most views.-sidebar :: ViewData -> HtmlUrl AppRoute-sidebar vd@VD{..} =- [hamlet|- <div #sidebar-menu .#{showmd} .#{showsm} .sidebar-offcanvas>- <table .main-menu .table>- <tr .#{journalcurrent}>- <td .top .acct>- <a href=@{JournalR} .#{journalcurrent} title="Show general journal entries, most recent first">Journal- <td .top>- ^{accounts}-|]- where- journalcurrent = if here == JournalR then "inacct" else "" :: String- ropts = reportopts_ $ cliopts_ opts- -- flip the default for items with zero amounts, show them by default- ropts' = ropts{empty_=not $ empty_ ropts}- accounts = balanceReportAsHtml opts vd $ balanceReport ropts' am j- showmd = if showsidebar then "col-md-4" else "col-any-0" :: String- showsm = if showsidebar then "col-sm-4" else "" :: String---- -- | Navigation link, preserving parameters and possibly highlighted.--- navlink :: ViewData -> String -> AppRoute -> String -> HtmlUrl AppRoute--- navlink VD{..} s dest title = [hamlet|--- <a##{s}link.#{style} href=@?{u'} title="#{title}">#{s}--- |]--- where u' = (dest, if null q then [] else [("q", pack q)])--- style | dest == here = "navlinkcurrent"--- | otherwise = "navlink" :: Text---- -- | Links to the various journal editing forms.--- editlinks :: HtmlUrl AppRoute--- editlinks = [hamlet|--- <a#editformlink href="#" onclick="return editformToggle(event)" title="Toggle journal edit form">edit--- \ | #--- <a#addformlink href="#" onclick="return addformToggle(event)" title="Toggle transaction add form">add--- <a#importformlink href="#" onclick="return importformToggle(event)" style="display:none;">import transactions--- |]---- | Search form for entering custom queries to filter journal data.-searchform :: ViewData -> HtmlUrl AppRoute-searchform VD{..} = [hamlet|-<div#searchformdiv .row>- <form#searchform .form-inline method=GET>- <div .form-group .col-md-12 .col-sm-12 .col-xs-12>- <div #searchbar .input-group>- <input .form-control name=q value=#{q} title="Enter hledger search patterns to filter the data below" placeholder="Search">- <div .input-group-btn>- $if filtering- <a href=@{here} .btn .btn-default title="Clear search terms">- <span .glyphicon .glyphicon-remove-circle>- <button .btn .btn-default type=submit title="Apply search terms">- <span .glyphicon .glyphicon-search>- <button .btn .btn-default type=button data-toggle="modal" data-target="#helpmodal" title="Show search and general help">?-|]- where- filtering = not $ null q---- -- | Edit journal form.--- editform :: ViewData -> HtmlUrl AppRoute--- editform VD{..} = [hamlet|--- <form#editform method=POST style=display:none;>--- <h2#contenttitle>#{title}>--- <table.form>--- $if manyfiles--- <tr>--- <td colspan=2>--- Editing ^{journalselect $ files j}--- <tr>--- <td colspan=2>--- <!-- XXX textarea ids are unquoted journal file paths here, not valid html -->--- $forall f <- files j--- <textarea id=#{fst f}_textarea name=text rows=25 cols=80 style=display:none; disabled=disabled>--- \#{snd f}--- <tr#addbuttonrow>--- <td>--- <span.help>^{formathelp}--- <td>--- <span.help>--- Are you sure ? This will overwrite the journal. #--- <input type=hidden name=action value=edit>--- <input type=submit name=submit value="save journal">--- \ or #--- <a href="#" onclick="return editformToggle(event)">cancel--- |]--- where--- title = "Edit journal" :: String--- manyfiles = length (files j) > 1--- formathelp = helplink "file-format" "file format help"---- -- | Import journal form.--- importform :: HtmlUrl AppRoute--- importform = [hamlet|--- <form#importform method=POST style=display:none;>--- <table.form>--- <tr>--- <td>--- <input type=file name=file>--- <input type=hidden name=action value=import>--- <input type=submit name=submit value="import from file">--- \ or #--- <a href="#" onclick="return importformToggle(event)">cancel--- |]---- | Link to a topic in the manual.-helplink :: String -> String -> HtmlUrl AppRoute-helplink topic label = [hamlet|-<a href=#{u} target=hledgerhelp>#{label}-|]- where u = manualurl ++ if null topic then "" else '#':topic--nulltemplate :: HtmlUrl AppRoute-nulltemplate = [hamlet||]---------------------------------------------------------------------------- hledger report renderers---- | Render a "BalanceReport" as html.-balanceReportAsHtml :: WebOpts -> ViewData -> BalanceReport -> HtmlUrl AppRoute-balanceReportAsHtml _ vd@VD{..} (items',total) =- [hamlet|- $forall i <- items- ^{itemAsHtml vd i}- <tr .total>- <td>- <td>- #{mixedAmountAsHtml total}-|]- where- l = ledgerFromJournal Any j- inacctmatcher = inAccountQuery qopts- items = items' -- maybe items' (\m -> filter (matchesAccount m . \(a,_,_,_)->a) items') showacctmatcher- itemAsHtml :: ViewData -> BalanceReportItem -> HtmlUrl AppRoute- itemAsHtml _ (acct, adisplay, aindent, abal) = [hamlet|-<tr .#{inacctclass}>- <td .acct>- <div .ff-wrapper>- \#{indent}- <a href="@?{acctquery}" .#{inacctclass} title="Show transactions affecting this account and subaccounts">#{adisplay}- $if hassubs- <a href="@?{acctonlyquery}" .only .hidden-sm .hidden-xs title="Show transactions affecting this account but not subaccounts">only- <td>- #{mixedAmountAsHtml abal}-|]- where- hassubs = not $ maybe False (null.asubs) $ ledgerAccount l acct- inacctclass = case inacctmatcher of- Just m' -> if m' `matchesAccount` acct then "inacct" else ""- Nothing -> "" :: String- indent = preEscapedString $ concat $ replicate (2 * (1+aindent)) " "- acctquery = (RegisterR, [("q", T.pack $ accountQuery acct)])- acctonlyquery = (RegisterR, [("q", T.pack $ accountOnlyQuery acct)])--accountQuery :: AccountName -> String-accountQuery a = "inacct:" ++ T.unpack (quoteIfSpaced a) -- (accountNameToAccountRegex a)--accountOnlyQuery :: AccountName -> String-accountOnlyQuery a = "inacctonly:" ++ T.unpack (quoteIfSpaced a ) -- (accountNameToAccountRegex a)--accountUrl :: AppRoute -> AccountName -> (AppRoute, [(Text, Text)])-accountUrl r a = (r, [("q", T.pack $ accountQuery a)])---- stringIfLongerThan :: Int -> String -> String--- stringIfLongerThan n s = if length s > n then s else ""--numberTransactionsReportItems :: [TransactionsReportItem] -> [(Int,Bool,Bool,Bool,TransactionsReportItem)]-numberTransactionsReportItems [] = []-numberTransactionsReportItems items = number 0 nulldate items- where- number :: Int -> Day -> [TransactionsReportItem] -> [(Int,Bool,Bool,Bool,TransactionsReportItem)]- number _ _ [] = []- number n prevd (i@(Transaction{tdate=d},_,_,_,_,_):rest) = (n+1,newday,newmonth,newyear,i): number (n+1) d rest- where- newday = d/=prevd- newmonth = dm/=prevdm || dy/=prevdy- newyear = dy/=prevdy- (dy,dm,_) = toGregorian d- (prevdy,prevdm,_) = toGregorian prevd--mixedAmountAsHtml :: MixedAmount -> Html-mixedAmountAsHtml b = preEscapedString $ unlines $ map addclass $ lines $ showMixedAmountWithoutPrice b- where addclass = printf "<span class=\"%s\">%s</span><br/>" (c :: String)- c = case isNegativeMixedAmount b of Just True -> "negative amount"- _ -> "positive amount"-
− Handler/JournalR.hs
@@ -1,88 +0,0 @@-{-# LANGUAGE OverloadedStrings, QuasiQuotes, RecordWildCards #-}--- | /journal handlers.--module Handler.JournalR where---- import Data.Text (Text)-import qualified Data.Text as T-import Import--import Handler.AddForm-import Handler.Common--import Hledger.Data-import Hledger.Query-import Hledger.Reports-import Hledger.Utils-import Hledger.Cli.CliOptions-import Hledger.Web.WebOptions---- | The formatted journal view, with sidebar.-getJournalR :: Handler Html-getJournalR = do- vd@VD{..} <- getViewData- let -- XXX like registerReportAsHtml- inacct = inAccount qopts- -- injournal = isNothing inacct- filtering = m /= Any- -- showlastcolumn = if injournal && not filtering then False else True- title = case inacct of- Nothing -> "General Journal"++s2- Just (a,inclsubs) -> "Transactions in "++T.unpack a++s1++s2- where s1 = if inclsubs then "" else " (excluding subaccounts)"- where- s2 = if filtering then ", filtered" else ""- maincontent = journalTransactionsReportAsHtml opts vd $ journalTransactionsReport (reportopts_ $ cliopts_ opts) j m- hledgerLayout vd "journal" [hamlet|- <div .row>- <h2 #contenttitle>#{title}- <!-- p>Journal entries record movements of commodities between accounts. -->- <a #addformlink role="button" style="cursor:pointer; margin-top:1em;" data-toggle="modal" data-target="#addmodal" title="Add a new transaction to the journal" href="#">Add a transaction- <div .table-responsive>- ^{maincontent}- |]--postJournalR :: Handler Html-postJournalR = postAddForm---- | Render a "TransactionsReport" as html for the formatted journal view.-journalTransactionsReportAsHtml :: WebOpts -> ViewData -> TransactionsReport -> HtmlUrl AppRoute-journalTransactionsReportAsHtml _ vd (_,items) = [hamlet|-<table .transactionsreport .table .table-condensed>- <thead>- <th .date style="text-align:left;">- Date- <th .description style="text-align:left;">Description- <th .account style="text-align:left;">Account- <th .amount style="text-align:right;">Amount- $forall i <- numberTransactionsReportItems items- ^{itemAsHtml vd i}- |]- where--- .#{datetransition}- itemAsHtml :: ViewData -> (Int, Bool, Bool, Bool, TransactionsReportItem) -> HtmlUrl AppRoute- itemAsHtml VD{..} (_, _, _, _, (torig, _, split, _, amt, _)) = [hamlet|-<tr .title #transaction-#{tindex torig}>- <td .date nowrap>#{date}- <td .description colspan=2>#{textElideRight 60 desc}- <td .amount style="text-align:right;">- $if showamt- \#{mixedAmountAsHtml amt}-$forall p' <- tpostings torig- <tr .item .posting title="#{show torig}">- <td .nonhead>- <td .nonhead>- <td .nonhead>- - <a href="@?{acctlink (paccount p')}##{tindex torig}" title="#{paccount p'}">#{elideAccountName 40 $ paccount p'}- <td .amount .nonhead style="text-align:right;">#{mixedAmountAsHtml $ pamount p'}-|]- where- acctlink a = (RegisterR, [("q", T.pack $ accountQuery a)])- -- datetransition | newm = "newmonth"- -- | newd = "newday"- -- | otherwise = "" :: String- (date, desc) = (show $ tdate torig, tdescription torig)- -- acctquery = (here, [("q", T.pack $ accountQuery acct)])- showamt = not split || not (isZeroMixedAmount amt)-
− Handler/RegisterR.hs
@@ -1,181 +0,0 @@-{-# LANGUAGE OverloadedStrings, QuasiQuotes, RecordWildCards #-}--- | /register handlers.--module Handler.RegisterR where--import Import--import Data.List-import Data.Maybe--- import Data.Text (Text)-import qualified Data.Text as T-import Safe--import Handler.AddForm-import Handler.Common-import Handler.Utils--import Hledger.Data-import Hledger.Query-import Hledger.Reports-import Hledger.Utils-import Hledger.Cli.CliOptions-import Hledger.Web.WebOptions---- | The main journal/account register view, with accounts sidebar.-getRegisterR :: Handler Html-getRegisterR = do- vd@VD{..} <- getViewData- -- staticRootUrl <- (staticRoot . settings) <$> getYesod- let -- injournal = isNothing inacct- filtering = m /= Any- -- title = "Transactions in "++a++s1++s2- title = T.unpack a++s1++s2- where- (a,inclsubs) = fromMaybe ("all accounts",True) $ inAccount qopts- s1 = if inclsubs then "" else " (excluding subaccounts)"- s2 = if filtering then ", filtered" else ""- maincontent = registerReportHtml opts vd $ accountTransactionsReport (reportopts_ $ cliopts_ opts) j m $ fromMaybe Any $ inAccountQuery qopts- hledgerLayout vd "register" [hamlet|- <h2 #contenttitle>#{title}- <!-- p>Transactions affecting this account, with running balance. -->- ^{maincontent}- |]--postRegisterR :: Handler Html-postRegisterR = postAddForm---- Generate html for an account register, including a balance chart and transaction list.-registerReportHtml :: WebOpts -> ViewData -> TransactionsReport -> HtmlUrl AppRoute-registerReportHtml opts vd r = [hamlet|- <div .hidden-xs>- ^{registerChartHtml $ transactionsReportByCommodity r}- ^{registerItemsHtml opts vd r}-|]---- Generate html for a transaction list from an "TransactionsReport".-registerItemsHtml :: WebOpts -> ViewData -> TransactionsReport -> HtmlUrl AppRoute-registerItemsHtml _ vd (balancelabel,items) = [hamlet|-<div .table-responsive>- <table.registerreport .table .table-striped .table-condensed>- <thead>- <tr>- <th style="text-align:left;">- Date- <span .glyphicon .glyphicon-chevron-up>- <th style="text-align:left;">Description- <th style="text-align:left;">To/From Account(s)- <th style="text-align:right; white-space:normal;">Amount Out/In- <th style="text-align:right; white-space:normal;">#{balancelabel'}- $forall i <- numberTransactionsReportItems items- ^{itemAsHtml vd i}- |]- where- insomeacct = isJust $ inAccount $ qopts vd- balancelabel' = if insomeacct then balancelabel else "Total"-- -- filtering = m /= Any- itemAsHtml :: ViewData -> (Int, Bool, Bool, Bool, TransactionsReportItem) -> HtmlUrl AppRoute- itemAsHtml VD{..} (n, newd, newm, _, (torig, tacct, split, acct, amt, bal)) = [hamlet|--<tr ##{tindex torig} .item.#{evenodd}.#{firstposting}.#{datetransition} title="#{show torig}" style="vertical-align:top;">- <td .date>- <a href="@{JournalR}#transaction-#{tindex torig}">#{date}- <td .description title="#{show torig}">#{textElideRight 30 desc}- <td .account>#{elideRight 40 acct}- <td .amount style="text-align:right; white-space:nowrap;">- $if showamt- \#{mixedAmountAsHtml amt}- <td .balance style="text-align:right;">#{mixedAmountAsHtml bal}-|]-- where- evenodd = if even n then "even" else "odd" :: String- datetransition | newm = "newmonth"- | newd = "newday"- | otherwise = "" :: String- (firstposting, date, desc) = (False, show $ tdate tacct, tdescription tacct)- -- acctquery = (here, [("q", pack $ accountQuery acct)])- showamt = not split || not (isZeroMixedAmount amt)---- | Generate javascript/html for a register balance line chart based on--- the provided "TransactionsReportItem"s.- -- registerChartHtml :: forall t (t1 :: * -> *) t2 t3 t4 t5.- -- Data.Foldable.Foldable t1 =>- -- t1 (Transaction, t2, t3, t4, t5, MixedAmount)- -- -> t -> Text.Blaze.Internal.HtmlM ()-registerChartHtml :: [(CommoditySymbol, (String, [TransactionsReportItem]))] -> HtmlUrl AppRoute-registerChartHtml percommoditytxnreports =- -- have to make sure plot is not called when our container (maincontent)- -- is hidden, eg with add form toggled- [hamlet|-<label #register-chart-label style=""><br>-<div #register-chart style="height:150px; margin-bottom:1em; display:block;">-<script type=text/javascript>- \$(document).ready(function() {- var $chartdiv = $('#register-chart');- if ($chartdiv.is(':visible')) {- \$('#register-chart-label').text('#{charttitle}');- var seriesData = [- $forall (c,(_,items)) <- percommoditytxnreports- /* we render each commodity using two series:- * one with extra data points added to show a stepped balance line */- {- data: [- $forall i <- reverse items- [- #{dayToJsTimestamp $ triDate i},- #{simpleMixedAmountQuantity $ triCommodityBalance c i}- ],- /* [] */- ],- label: '#{shownull $ T.unpack c}',- color: #{colorForCommodity c},- lines: {- show: true,- steps: true,- },- points: {- show: false,- },- clickable: false,- hoverable: false,- },- /* and one with the original data, showing one clickable, hoverable point per transaction */- {- data: [- $forall i <- reverse items- [- #{dayToJsTimestamp $ triDate i},- #{simpleMixedAmountQuantity $ triCommodityBalance c i},- '#{showMixedAmountWithZeroCommodity $ triCommodityAmount c i}',- '#{showMixedAmountWithZeroCommodity $ triCommodityBalance c i}',- '#{concat $ intersperse "\\n" $ lines $ show $ triOrigTransaction i}',- #{tindex $ triOrigTransaction i}- ],- /* [] */- ],- label: '',- color: #{colorForCommodity c},- lines: {- show: false,- },- points: {- show: true,- },- },- ]- var plot = registerChart($chartdiv, seriesData);- \$chartdiv.bind("plotclick", registerChartClick);- };- });-|]- -- [#{dayToJsTimestamp $ ltrace "\ndate" $ triDate i}, #{ltrace "balancequantity" $ simpleMixedAmountQuantity $ triCommodityBalance c i}, '#{ltrace "balance" $ show $ triCommodityBalance c i}, '#{ltrace "amount" $ show $ triCommodityAmount c i}''],- where- charttitle = case maybe "" (fst.snd) $ headMay percommoditytxnreports- of "" -> ""- s -> s++":"- colorForCommodity = fromMaybe 0 . flip lookup commoditiesIndex- commoditiesIndex = zip (map fst percommoditytxnreports) [0..] :: [(CommoditySymbol,Int)]- simpleMixedAmountQuantity = maybe 0 aquantity . headMay . amounts- shownull c = if null c then " " else c
− Handler/RootR.hs
@@ -1,8 +0,0 @@--- | Site root and misc. handlers.--module Handler.RootR where--import Import--getRootR :: Handler Html-getRootR = redirect defaultroute where defaultroute = JournalR
− Handler/SidebarR.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE OverloadedStrings, QuasiQuotes, RecordWildCards #-}--- | /sidebar--module Handler.SidebarR where--import Import--import Handler.Common---- | Render just the accounts sidebar, useful when opening the sidebar.-getSidebarR :: Handler Html-getSidebarR = do- vd <- getViewData- withUrlRenderer [hamlet|^{sidebar vd}|]-
− Handler/Utils.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE CPP #-}--- | Web handler utilities. More of these are in Foundation.hs, where--- they can be used in the default template.--module Handler.Utils where--import Prelude-import Data.Time.Calendar-import Data.Time.Clock-import Data.Time.Format-#if !(MIN_VERSION_time(1,5,0))-import System.Locale (defaultTimeLocale)-#endif--numbered :: [a] -> [(Int,a)]-numbered = zip [1..]--dayToJsTimestamp :: Day -> Integer-dayToJsTimestamp d = read (formatTime defaultTimeLocale "%s" t) * 1000 -- XXX read- where t = UTCTime d (secondsToDiffTime 0)
Hledger/Web.hs view
@@ -2,12 +2,12 @@ Re-export the modules of the hledger-web program. -} -module Hledger.Web (- module Hledger.Web.WebOptions,- module Hledger.Web.Main,- tests_Hledger_Web- )-where+module Hledger.Web+ ( module Hledger.Web.WebOptions+ , module Hledger.Web.Main+ , tests_Hledger_Web+ ) where+ import Test.HUnit import Hledger.Web.WebOptions
+ Hledger/Web/Application.hs view
@@ -0,0 +1,53 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE ViewPatterns #-}++module Hledger.Web.Application+ ( makeApplication+ , makeFoundation+ ) where++import Data.IORef (newIORef, writeIORef)+import Network.Wai.Middleware.RequestLogger (logStdoutDev, logStdout)+import Network.HTTP.Client (defaultManagerSettings)+import Network.HTTP.Conduit (newManager)+import Yesod.Default.Config++import Hledger.Data (Journal, nulljournal)+import Hledger.Web.Handler.AddR (getAddR, postAddR)+import Hledger.Web.Handler.Common+ (getDownloadR, getFaviconR, getManageR, getRobotsR, getRootR)+import Hledger.Web.Handler.EditR (getEditR, postEditR)+import Hledger.Web.Handler.UploadR (getUploadR, postUploadR)+import Hledger.Web.Handler.JournalR (getJournalR)+import Hledger.Web.Handler.RegisterR (getRegisterR)+import Hledger.Web.Import+import Hledger.Web.WebOptions (WebOpts(serve_))++-- This line actually creates our YesodDispatch instance. It is the second half+-- of the call to mkYesodData which occurs in Foundation.hs. Please see the+-- comments there for more details.+mkYesodDispatch "App" resourcesApp++-- This function allocates resources (such as a database connection pool),+-- performs initialization and creates a WAI application. This is also the+-- place to put your migrate statements to have automatic database+-- migrations handled by Yesod.+makeApplication :: WebOpts -> Journal -> AppConfig DefaultEnv Extra -> IO Application+makeApplication opts' j' conf' = do+ foundation <- makeFoundation conf' opts'+ writeIORef (appJournal foundation) j'+ logWare <$> toWaiApp foundation+ where+ logWare | development = logStdoutDev+ | serve_ opts' = logStdout+ | otherwise = id++makeFoundation :: AppConfig DefaultEnv Extra -> WebOpts -> IO App+makeFoundation conf opts' = do+ manager <- newManager defaultManagerSettings+ s <- staticSite+ jref <- newIORef nulljournal+ return $ App conf s manager opts' jref
+ Hledger/Web/Foundation.hs view
@@ -0,0 +1,232 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE ViewPatterns #-}++-- | Define the web application's foundation, in the usual Yesod style.+-- See a default Yesod app's comments for more details of each part.++module Hledger.Web.Foundation where++import Control.Monad (join)+import qualified Data.ByteString.Char8 as BC+import Data.Traversable (for)+import Data.IORef (IORef, readIORef, writeIORef)+import Data.Maybe (fromMaybe)+import Data.Monoid ((<>))+import Data.Text (Text)+import qualified Data.Text as T+import Data.Time.Calendar (Day)+import Network.HTTP.Conduit (Manager)+import Network.Wai (requestHeaders)+import System.FilePath (takeFileName)+import Text.Blaze (Markup)+import Text.Hamlet (hamletFile)+import Yesod+import Yesod.Static+import Yesod.Default.Config++#ifndef DEVELOPMENT+import Hledger.Web.Settings (staticDir)+import Text.Jasmine (minifym)+import Yesod.Default.Util (addStaticContentExternal)+#endif++import Hledger+import Hledger.Cli (CliOpts(..), journalReloadIfChanged)+import Hledger.Web.Settings (Extra(..), widgetFile)+import Hledger.Web.Settings.StaticFiles+import Hledger.Web.WebOptions+import Hledger.Web.Widget.Common (balanceReportAsHtml)++-- | The site argument for your application. This can be a good place to+-- keep settings and values requiring initialization before your application+-- starts running, such as database connections. Every handler will have+-- access to the data present here.+data App = App+ { settings :: AppConfig DefaultEnv Extra+ , getStatic :: Static -- ^ Settings for static file serving.+ , httpManager :: Manager+ --+ , appOpts :: WebOpts+ , appJournal :: IORef Journal+ }+++-- This is where we define all of the routes in our application. For a full+-- explanation of the syntax, please see:+-- http://www.yesodweb.com/book/handler+--+-- This function does three things:+--+-- * Creates the route datatype AppRoute. Every valid URL in your+-- application can be represented as a value of this type.+-- * Creates the associated type:+-- type instance Route App = AppRoute+-- * Creates the value resourcesApp which contains information on the+-- resources declared below. This is used in Handler.hs by the call to+-- mkYesodDispatch+--+-- What this function does *not* do is create a YesodSite instance for+-- App. Creating that instance requires all of the handler functions+-- for our application to be in scope. However, the handler functions+-- usually require access to the AppRoute datatype. Therefore, we+-- split these actions into two functions and place them in separate files.+mkYesodData "App" $(parseRoutesFile "config/routes")++-- | A convenience alias.+type AppRoute = Route App++#if MIN_VERSION_yesod(1,6,0)+type Form x = Html -> MForm (HandlerFor App) (FormResult x, Widget)+#else+type Form x = Html -> MForm (HandlerT App IO) (FormResult x, Widget)+#endif++-- Please see the documentation for the Yesod typeclass. There are a number+-- of settings which can be configured by overriding methods here.+instance Yesod App where+ approot = ApprootMaster $ appRoot . settings++ makeSessionBackend _ = Just <$> defaultClientSessionBackend 120 ".hledger-web_client_session_key.aes"++ defaultLayout widget = do+ master <- getYesod+ here <- fromMaybe RootR <$> getCurrentRoute+ VD {caps, j, m, opts, q, qopts} <- getViewData+ msg <- getMessage+ showSidebar <- shouldShowSidebar+ hideEmptyAccts <- (== Just "1") . lookup "hideemptyaccts" . reqCookies <$> getRequest++ let ropts = reportopts_ (cliopts_ opts)+ -- flip the default for items with zero amounts, show them by default+ ropts' = ropts { empty_ = not (empty_ ropts) }+ accounts =+ balanceReportAsHtml (JournalR, RegisterR) here hideEmptyAccts j qopts $+ balanceReport ropts' m j++ topShowmd = if showSidebar then "col-md-4" else "col-any-0" :: Text+ topShowsm = if showSidebar then "col-sm-4" else "" :: Text+ sideShowmd = if showSidebar then "col-md-4" else "col-any-0" :: Text+ sideShowsm = if showSidebar then "col-sm-4" else "" :: Text+ mainShowmd = if showSidebar then "col-md-8" else "col-md-12" :: Text+ mainShowsm = if showSidebar then "col-sm-8" else "col-sm-12" :: Text++ -- We break up the default layout into two components:+ -- default-layout is the contents of the body tag, and+ -- default-layout-wrapper is the entire page. Since the final+ -- value passed to hamletToRepHtml cannot be a widget, this allows+ -- you to use normal widget features in default-layout.+ pc <- widgetToPageContent $ do+ addStylesheet $ StaticR css_bootstrap_min_css+ addStylesheet $ StaticR css_bootstrap_datepicker_standalone_min_css+ -- load these things early, in HEAD:+ toWidgetHead [hamlet|+ <script type="text/javascript" src="@{StaticR js_jquery_min_js}">+ <script type="text/javascript" src="@{StaticR js_typeahead_bundle_min_js}">+ |]+ addScript $ StaticR js_bootstrap_min_js+ addScript $ StaticR js_bootstrap_datepicker_min_js+ addScript $ StaticR js_jquery_url_js+ addScript $ StaticR js_jquery_cookie_js+ addScript $ StaticR js_jquery_hotkeys_js+ addScript $ StaticR js_jquery_flot_min_js+ addScript $ StaticR js_jquery_flot_time_min_js+ addScript $ StaticR js_jquery_flot_tooltip_min_js+ toWidget [hamlet| \<!--[if lte IE 8]> <script type="text/javascript" src="@{StaticR js_excanvas_min_js}"></script> <![endif]--> |]+ addStylesheet $ StaticR hledger_css+ addScript $ StaticR hledger_js+ $(widgetFile "default-layout")++ withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")++#ifndef DEVELOPMENT+ -- This function creates static content files in the static folder+ -- and names them based on a hash of their content. This allows+ -- expiration dates to be set far in the future without worry of+ -- users receiving stale content.+ addStaticContent = addStaticContentExternal minifym base64md5 staticDir (StaticR . flip StaticRoute [])+#endif++-- This instance is required to use forms. You can modify renderMessage to+-- achieve customized and internationalized form validation messages.+instance RenderMessage App FormMessage where+ renderMessage _ _ = defaultFormMessage+++----------------------------------------------------------------------+-- template and handler utilities++-- view data, used by the add form and handlers+-- XXX Parameter p - show/hide postings++-- | A bundle of data useful for hledger-web request handlers and templates.+data ViewData = VD+ { opts :: WebOpts -- ^ the command-line options at startup+ , today :: Day -- ^ today's date (for queries containing relative dates)+ , j :: Journal -- ^ the up-to-date parsed unfiltered journal+ , q :: Text -- ^ the current q parameter, the main query expression+ , m :: Query -- ^ a query parsed from the q parameter+ , qopts :: [QueryOpt] -- ^ query options parsed from the q parameter+ , caps :: [Capability] -- ^ capabilities enabled for this request+ } deriving (Show)++instance Show Text.Blaze.Markup where show _ = "<blaze markup>"++-- | Gather data used by handlers and templates in the current request.+getViewData :: Handler ViewData+getViewData = do+ App {appOpts = opts, appJournal} <- getYesod+ today <- liftIO getCurrentDay+ let copts = cliopts_ opts+ (j, merr) <-+ getCurrentJournal+ appJournal+ copts {reportopts_ = (reportopts_ copts) {no_elide_ = True}}+ today+ maybe (pure ()) (setMessage . toHtml) merr+ q <- fromMaybe "" <$> lookupGetParam "q"+ let (m, qopts) = parseQuery today q+ caps <- case capabilitiesHeader_ opts of+ Nothing -> return (capabilities_ opts)+ Just h -> do+ hs <- fmap (BC.split ',' . snd) . filter ((== h) . fst) . requestHeaders <$> waiRequest+ fmap join . for (join hs) $ \x -> case capabilityFromBS x of+ Left e -> [] <$ addMessage "" ("Unknown permission: " <> toHtml (BC.unpack e))+ Right c -> pure [c]+ return VD {opts, today, j, q, m, qopts, caps}++-- | Find out if the sidebar should be visible. Show it, unless there is a+-- showsidebar cookie set to "0", or a ?sidebar=0 query parameter.+shouldShowSidebar :: Handler Bool+shouldShowSidebar = do+ msidebarparam <- lookupGetParam "sidebar"+ msidebarcookie <- lookup "showsidebar" . reqCookies <$> getRequest+ return $ maybe (msidebarcookie /= Just "0") (/="0") msidebarparam++-- | Update our copy of the journal if the file changed. If there is an+-- error while reloading, keep the old one and return the error, and set a+-- ui message.+getCurrentJournal :: IORef Journal -> CliOpts -> Day -> Handler (Journal, Maybe String)+getCurrentJournal jref opts d = do+ -- XXX put this inside atomicModifyIORef' for thread safety+ j <- liftIO (readIORef jref)+ (ej, changed) <- liftIO $ journalReloadIfChanged opts d j+ -- re-apply any initial filter specified at startup+ let initq = queryFromOpts d (reportopts_ opts)+ case (changed, filterJournalTransactions initq <$> ej) of+ (False, _) -> return (j, Nothing)+ (True, Right j') -> do+ liftIO $ writeIORef jref j'+ return (j',Nothing)+ (True, Left e) -> do+ setMessage "error while reading journal"+ return (j, Just e)
+ Hledger/Web/Handler/AddR.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Hledger.Web.Handler.AddR+ ( getAddR+ , postAddR+ ) where++import Hledger+import Hledger.Cli.Commands.Add (appendToJournalFileOrStdout)+import Hledger.Web.Import+import Hledger.Web.Widget.AddForm (addForm)+import Hledger.Web.Widget.Common (fromFormSuccess)++getAddR :: Handler ()+getAddR = postAddR++postAddR :: Handler ()+postAddR = do+ VD{caps, j, today} <- getViewData+ when (CapAdd `notElem` caps) (permissionDenied "Missing the 'add' capability")++ ((res, view), enctype) <- runFormPost $ addForm j today+ t <- txnTieKnot <$> fromFormSuccess (showForm view enctype) res+ -- XXX(?) move into balanceTransaction+ liftIO $ ensureJournalFileExists (journalFilePath j)+ liftIO $ appendToJournalFileOrStdout (journalFilePath j) (showTransaction t)+ setMessage "Transaction added."+ redirect JournalR+ where+ showForm view enctype =+ sendResponse =<< defaultLayout [whamlet|+ <h2>Add transaction+ <div .row style="margin-top:1em">+ <form#addform.form.col-xs-12.col-md-8 method=post enctype=#{enctype}>+ ^{view}+ |]
+ Hledger/Web/Handler/Common.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++module Hledger.Web.Handler.Common+ ( getDownloadR+ , getFaviconR+ , getManageR+ , getRobotsR+ , getRootR+ ) where++import qualified Data.Text as T+import Yesod.Default.Handlers (getFaviconR, getRobotsR)++import Hledger (jfiles)+import Hledger.Web.Import+import Hledger.Web.Widget.Common (journalFile404)++getRootR :: Handler Html+getRootR = redirect JournalR++getManageR :: Handler Html+getManageR = do+ VD{caps, j} <- getViewData+ when (CapManage `notElem` caps) (permissionDenied "Missing the 'manage' capability")+ defaultLayout $ do+ setTitle "Manage journal"+ $(widgetFile "manage")++getDownloadR :: FilePath -> Handler TypedContent+getDownloadR f = do+ VD{caps, j} <- getViewData+ when (CapManage `notElem` caps) (permissionDenied "Missing the 'manage' capability")+ (f', txt) <- journalFile404 f j+ addHeader "Content-Disposition" ("attachment; filename=\"" <> T.pack f' <> "\"")+ sendResponse ("text/plain" :: ByteString, toContent txt)
+ Hledger/Web/Handler/EditR.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}++module Hledger.Web.Handler.EditR+ ( getEditR+ , postEditR+ ) where++import Hledger.Web.Import+import Hledger.Web.Widget.Common+ (fromFormSuccess, helplink, journalFile404, writeValidJournal)++editForm :: FilePath -> Text -> Markup -> MForm Handler (FormResult Text, Widget)+editForm f txt =+ identifyForm "edit" $ \extra -> do+ (tRes, tView) <- mreq textareaField fs (Just (Textarea txt))+ pure (unTextarea <$> tRes, $(widgetFile "edit-form"))+ where+ fs = FieldSettings "text" mzero mzero mzero [("class", "form-control"), ("rows", "25")]++getEditR :: FilePath -> Handler ()+getEditR = postEditR++postEditR :: FilePath -> Handler ()+postEditR f = do+ VD {caps, j} <- getViewData+ when (CapManage `notElem` caps) (permissionDenied "Missing the 'manage' capability")++ (f', txt) <- journalFile404 f j+ ((res, view), enctype) <- runFormPost (editForm f' txt)+ text <- fromFormSuccess (showForm view enctype) res+ writeValidJournal f text >>= \case+ Left e -> do+ setMessage $ "Failed to load journal: " <> toHtml e+ showForm view enctype+ Right () -> do+ setMessage $ "Saved journal " <> toHtml f <> "\n"+ redirect JournalR+ where+ showForm view enctype =+ sendResponse <=< defaultLayout $ do+ setTitle "Edit journal"+ [whamlet|<form method=post enctype=#{enctype}>^{view}|]
+ Hledger/Web/Handler/JournalR.hs view
@@ -0,0 +1,31 @@+-- | /journal handlers.++{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++module Hledger.Web.Handler.JournalR where++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Web.Import+import Hledger.Web.WebOptions+import Hledger.Web.Widget.AddForm (addModal)+import Hledger.Web.Widget.Common (accountQuery, mixedAmountAsHtml)++-- | The formatted journal view, with sidebar.+getJournalR :: Handler Html+getJournalR = do+ VD{caps, j, m, opts, qopts, today} <- getViewData+ when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")+ let title = case inAccount qopts of+ Nothing -> "General Journal"+ Just (a, inclsubs) -> "Transactions in " <> a <> if inclsubs then "" else " (excluding subaccounts)"+ title' = title <> if m /= Any then ", filtered" else ""+ acctlink a = (RegisterR, [("q", accountQuery a)])+ (_, items) = journalTransactionsReport (reportopts_ $ cliopts_ opts) j m++ defaultLayout $ do+ setTitle "journal - hledger-web"+ $(widgetFile "journal")
+ Hledger/Web/Handler/RegisterR.hs view
@@ -0,0 +1,60 @@+-- | /register handlers.++{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}++module Hledger.Web.Handler.RegisterR where++import Data.List (intersperse)+import qualified Data.Text as T+import Text.Hamlet (hamletFile)++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Web.Import+import Hledger.Web.WebOptions+import Hledger.Web.Widget.AddForm (addModal)+import Hledger.Web.Widget.Common (mixedAmountAsHtml)++-- | The main journal/account register view, with accounts sidebar.+getRegisterR :: Handler Html+getRegisterR = do+ VD{caps, j, m, opts, qopts, today} <- getViewData+ when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")++ let (a,inclsubs) = fromMaybe ("all accounts",True) $ inAccount qopts+ s1 = if inclsubs then "" else " (excluding subaccounts)"+ s2 = if m /= Any then ", filtered" else ""+ header = a <> s1 <> s2++ let ropts = reportopts_ (cliopts_ opts)+ acctQuery = fromMaybe Any (inAccountQuery qopts)+ r@(balancelabel,items) = accountTransactionsReport ropts j m acctQuery+ balancelabel' = if isJust (inAccount qopts) then balancelabel else "Total"+ defaultLayout $ do+ setTitle "register - hledger-web"+ $(widgetFile "register")++-- | Generate javascript/html for a register balance line chart based on+-- the provided "TransactionsReportItem"s.+registerChartHtml :: [(CommoditySymbol, (String, [TransactionsReportItem]))] -> HtmlUrl AppRoute+registerChartHtml percommoditytxnreports = $(hamletFile "templates/chart.hamlet")+ -- have to make sure plot is not called when our container (maincontent)+ -- is hidden, eg with add form toggled+ where+ charttitle = case maybe "" (fst . snd) $ listToMaybe percommoditytxnreports of+ "" -> ""+ s -> s <> ":"+ colorForCommodity = fromMaybe 0 . flip lookup commoditiesIndex+ commoditiesIndex = zip (map fst percommoditytxnreports) [0..] :: [(CommoditySymbol,Int)]+ simpleMixedAmountQuantity = maybe 0 aquantity . listToMaybe . amounts+ shownull c = if null c then " " else c++dayToJsTimestamp :: Day -> Integer+dayToJsTimestamp d =+ read (formatTime defaultTimeLocale "%s" t) * 1000 -- XXX read+ where+ t = UTCTime d (secondsToDiffTime 0)
+ Hledger/Web/Handler/UploadR.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++module Hledger.Web.Handler.UploadR+ ( getUploadR+ , postUploadR+ ) where++import qualified Data.ByteString.Lazy as BL+import Data.Conduit (connect)+import Data.Conduit.Binary (sinkLbs)+import qualified Data.Text.Encoding as TE++import Hledger.Web.Import+import Hledger.Web.Widget.Common (fromFormSuccess, journalFile404, writeValidJournal)++uploadForm :: FilePath -> Markup -> MForm Handler (FormResult FileInfo, Widget)+uploadForm f =+ identifyForm "upload" $ \extra -> do+ (res, _) <- mreq fileField fs Nothing+ -- Ignoring the view - setting the name of the element is enough here+ pure (res, $(widgetFile "upload-form"))+ where+ fs = FieldSettings "file" Nothing (Just "file") (Just "file") []++getUploadR :: FilePath -> Handler ()+getUploadR = postUploadR++postUploadR :: FilePath -> Handler ()+postUploadR f = do+ VD {caps, j} <- getViewData+ when (CapManage `notElem` caps) (permissionDenied "Missing the 'manage' capability")++ (f', _) <- journalFile404 f j+ ((res, view), enctype) <- runFormPost (uploadForm f')+ fi <- fromFormSuccess (showForm view enctype) res+ lbs <- BL.toStrict <$> connect (fileSource fi) sinkLbs++ -- Try to parse as UTF-8+ -- XXX Unfortunate - how to parse as system locale?+ text <- case TE.decodeUtf8' lbs of+ Left e -> do+ setMessage $+ "Encoding error: '" <> toHtml (show e) <> "'. " <>+ "If your file is not UTF-8 encoded, try the 'edit form', " <>+ "where the transcoding should be handled by the browser."+ showForm view enctype+ Right text -> return text+ writeValidJournal f text >>= \case+ Left e -> do+ setMessage $ "Failed to load journal: " <> toHtml e+ showForm view enctype+ Right () -> do+ setMessage $ "File " <> toHtml f <> " uploaded successfully"+ redirect JournalR+ where+ showForm view enctype =+ sendResponse <=< defaultLayout $ do+ setTitle "Upload journal"+ [whamlet|<form method=post enctype=#{enctype}>^{view}|]
+ Hledger/Web/Import.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE CPP #-}+module Hledger.Web.Import+ ( module Import+ ) where++import Prelude as Import hiding (head, init, last,+ readFile, tail, writeFile)+import Yesod as Import hiding (Route (..))++import Control.Monad as Import+import Data.Bifunctor as Import+import Data.ByteString as Import (ByteString)+import Data.Default as Import+import Data.Either as Import+import Data.Foldable as Import+import Data.List as Import (unfoldr)+import Data.Maybe as Import+import Data.Text as Import (Text)+import Data.Time as Import hiding (parseTime)+import Data.Traversable as Import+import Data.Void as Import (Void)+import Text.Blaze as Import (Markup)++import Hledger.Web.Foundation as Import+import Hledger.Web.Settings as Import+import Hledger.Web.Settings.StaticFiles as Import+import Hledger.Web.WebOptions as Import (Capability(..))++#if !(MIN_VERSION_base(4,11,0))+import Data.Monoid as Import ((<>))+#endif
Hledger/Web/Main.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE CPP, OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-} {-| hledger-web - a hledger add-on providing a web interface.@@ -7,32 +8,26 @@ -} -module Hledger.Web.Main-where+module Hledger.Web.Main where --- yesod scaffold imports-import Yesod.Default.Config --(fromArgs)--- import Yesod.Default.Main (defaultMain)-import Settings -- (parseExtra)-import Application (makeApplication)-import Data.String+import Control.Monad (when)+import Data.String (fromString)+import qualified Data.Text as T+import Network.Wai (Application) import Network.Wai.Handler.Warp (runSettings, defaultSettings, setHost, setPort) import Network.Wai.Handler.Launch (runHostPortUrl)----#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$>))-#endif-import Control.Monad-import Data.Default-import Data.Text (pack)+import Prelude hiding (putStrLn) import System.Exit (exitSuccess) import System.IO (hFlush, stdout)-import Text.Printf-import Prelude hiding (putStrLn)+import Text.Printf (printf)+import Yesod.Default.Config+import Yesod.Default.Main (defaultDevelApp) import Hledger-import Hledger.Utils.UTF8IOCompat (putStrLn) import Hledger.Cli hiding (progname,prognameandversion)+import Hledger.Utils.UTF8IOCompat (putStrLn)+import Hledger.Web.Application (makeApplication)+import Hledger.Web.Settings (Extra(..), parseExtra) import Hledger.Web.WebOptions @@ -42,30 +37,39 @@ when (debug_ (cliopts_ opts) > 0) $ printf "%s\n" prognameandversion >> printf "opts: %s\n" (show opts) runWith opts +hledgerWebDev :: IO (Int, Application)+hledgerWebDev =+ withJournalDoWeb defwebopts (\o j -> defaultDevelApp loader $ makeApplication o j)+ where+ loader =+ Yesod.Default.Config.loadConfig+ (configSettings Development) {csParseExtra = parseExtra}+ runWith :: WebOpts -> IO () runWith opts- | "help" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStr (showModeUsage webmode) >> exitSuccess- | "version" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStrLn prognameandversion >> exitSuccess- | "binary-filename" `inRawOpts` (rawopts_ $ cliopts_ opts) = putStrLn (binaryfilename progname)- | otherwise = do- requireJournalFileExists =<< (head `fmap` journalFilePathFromOpts (cliopts_ opts)) -- XXX head should be safe for now- withJournalDo' opts web+ | "help" `inRawOpts` rawopts_ (cliopts_ opts) = putStr (showModeUsage webmode) >> exitSuccess+ | "version" `inRawOpts` rawopts_ (cliopts_ opts) = putStrLn prognameandversion >> exitSuccess+ | "binary-filename" `inRawOpts` rawopts_ (cliopts_ opts) = putStrLn (binaryfilename progname)+ | otherwise = withJournalDoWeb opts web -withJournalDo' :: WebOpts -> (WebOpts -> Journal -> IO ()) -> IO ()-withJournalDo' opts@WebOpts {cliopts_ = cliopts} cmd = do- f <- head `fmap` journalFilePathFromOpts cliopts -- XXX head should be safe for now+-- | A version of withJournalDo specialised for hledger-web.+-- Disallows the special - file to avoid some bug,+-- takes WebOpts rather than CliOpts.+withJournalDoWeb :: WebOpts -> (WebOpts -> Journal -> IO a) -> IO a+withJournalDoWeb opts@WebOpts {cliopts_ = copts} cmd = do+ journalpaths <- journalFilePathFromOpts copts -- https://github.com/simonmichael/hledger/issues/202- -- -f- gives [Error#yesod-core] <stdin>: hGetContents: illegal operation (handle is closed) for some reason- -- Also we may be writing to this file. Just disallow it.- when (f == "-") $ error' "hledger-web doesn't support -f -, please specify a file path"+ -- -f- gives [Error#yesod-core] <stdin>: hGetContents: illegal operation (handle is closed)+ -- Also we may try to write to this file. Just disallow -.+ when ("-" `elem` journalpaths) $ -- always non-empty+ error' "hledger-web doesn't support -f -, please specify a file path"+ mapM_ requireJournalFileExists journalpaths - let fn = cmd opts- . pivotByOpts cliopts- . anonymiseByOpts cliopts- <=< journalApplyValue (reportopts_ cliopts)- <=< journalAddForecast cliopts- readJournalFile def f >>= either error' fn+ -- keep synced with withJournalDo TODO refactor+ readJournalFiles (inputopts_ copts) journalpaths+ >>= mapM (journalTransform copts)+ >>= either error' (cmd opts) -- | The web command. web :: WebOpts -> Journal -> IO ()@@ -76,11 +80,11 @@ h = host_ opts p = port_ opts u = base_url_ opts- staticRoot = pack <$> file_url_ opts+ staticRoot = T.pack <$> file_url_ opts appconfig = AppConfig{appEnv = Development ,appHost = fromString h ,appPort = p- ,appRoot = pack u+ ,appRoot = T.pack u ,appExtra = Extra "" Nothing staticRoot } app <- makeApplication opts j' appconfig@@ -90,10 +94,7 @@ then do putStrLn "Press ctrl-c to quit" hFlush stdout- let warpsettings =- setHost (fromString h) $- setPort p $- defaultSettings+ let warpsettings = setHost (fromString h) (setPort p defaultSettings) Network.Wai.Handler.Warp.runSettings warpsettings app else do putStrLn "Starting web browser..."
+ Hledger/Web/Settings.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE CPP, OverloadedStrings, QuasiQuotes #-}+-- | Settings are centralized, as much as possible, into this file. This+-- includes database connection settings, static file locations, etc.+-- In addition, you can configure a number of different aspects of Yesod+-- by overriding methods in the Yesod typeclass. That instance is+-- declared in the Foundation.hs file.+module Hledger.Web.Settings where++import Data.Default (def)+import Data.Semigroup ((<>))+import Data.Text (Text)+import Data.Yaml+import Language.Haskell.TH.Syntax (Q, Exp)+import Text.Hamlet+import Text.Shakespeare.Text (st)+import Yesod.Default.Config+import Yesod.Default.Util++development :: Bool+development =+#if DEVELOPMENT+ True+#else+ False+#endif++production :: Bool+production = not development++hledgerorgurl :: Text+hledgerorgurl = "http://hledger.org"++manualurl :: Text+manualurl = hledgerorgurl <> "/manual"++-- | The default IP address to listen on. May be overridden with --host.+defhost :: String+defhost = "127.0.0.1"++-- | The default TCP port to listen on. May be overridden with --port.+defport :: Int+defport = 5000++defbaseurl :: String -> Int -> String+defbaseurl host port =+ "http://" ++ host ++ if port /= 80 then ":" ++ show port else ""++-- Static setting below. Changing these requires a recompile++-- | The location of static files on your system. This is a file system+-- path. The default value works properly with your scaffolded site.+staticDir :: FilePath+staticDir = "static"++-- | The base URL for your static files. As you can see by the default+-- value, this can simply be "static" appended to your application root.+-- A powerful optimization can be serving static files from a separate+-- domain name. This allows you to use a web server optimized for static+-- files, more easily set expires and cache values, and avoid possibly+-- costly transference of cookies on static files. For more information,+-- please see:+-- http://code.google.com/speed/page-speed/docs/request.html#ServeFromCookielessDomain+--+-- If you change the resource pattern for StaticR in Foundation.hs, you will+-- have to make a corresponding change here.+--+-- To see how this value is used, see urlRenderOverride in Foundation.hs+staticRoot :: AppConfig DefaultEnv Extra -> Text+staticRoot conf = case extraStaticRoot $ appExtra conf of+ Just root -> root+ Nothing -> [st|#{appRoot conf}/static|]++-- | Settings for 'widgetFile', such as which template languages to support and+-- default Hamlet settings.+widgetFileSettings :: WidgetFileSettings+widgetFileSettings = def+ { wfsHamletSettings = defaultHamletSettings+ { hamletNewlines = AlwaysNewlines+ }+ }++-- The rest of this file contains settings which rarely need changing by a+-- user.++widgetFile :: String -> Q Exp+widgetFile = (if development then widgetFileReload+ else widgetFileNoReload)+ widgetFileSettings++data Extra = Extra+ { extraCopyright :: Text+ , extraAnalytics :: Maybe Text -- ^ Google Analytics+ , extraStaticRoot :: Maybe Text+ } deriving Show++parseExtra :: DefaultEnv -> Object -> Parser Extra+parseExtra _ o = Extra+ <$> o .: "copyright"+ <*> o .:? "analytics"+ <*> o .:? "staticRoot"
+ Hledger/Web/Settings/StaticFiles.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE TemplateHaskell #-}+module Hledger.Web.Settings.StaticFiles where++import System.IO (stdout, hFlush)+import Yesod.Static (Static, embed, publicFiles, staticDevel)++import Hledger.Web.Settings (staticDir, development)++-- | use this to create your static file serving site+-- staticSite :: IO Static.Static+-- staticSite = if development then Static.staticDevel staticDir+-- else Static.static staticDir+--+-- | This generates easy references to files in the static directory at compile time,+-- giving you compile-time verification that referenced files exist.+-- Warning: any files added to your static directory during run-time can't be+-- accessed this way. You'll have to use their FilePath or URL to access them.+-- $(staticFiles Settings.staticDir)+++staticSite :: IO Static+staticSite =+ if development+ then (do+ putStrLn ("Using web files from: " ++ staticDir ++ "/") >> hFlush stdout+ staticDevel staticDir)+ else (do+ -- putStrLn "Using built-in web files" >> hFlush stdout+ return $(embed staticDir))++$(publicFiles staticDir)
Hledger/Web/WebOptions.hs view
@@ -1,17 +1,20 @@ {-# LANGUAGE CPP #-}-module Hledger.Web.WebOptions-where-import Prelude-import Data.Default-#if !MIN_VERSION_base(4,8,0)-import Data.Functor.Compat ((<$>))-#endif-import Data.Maybe-import System.Environment+{-# LANGUAGE OverloadedStrings #-}+module Hledger.Web.WebOptions where -import Hledger.Cli hiding (progname,version,prognameandversion)-import Settings+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as BC+import Data.CaseInsensitive (CI, mk)+import Control.Monad (join)+import Data.Default (Default(def))+import Data.Maybe (fromMaybe)+import qualified Data.Text as T+import Data.Text (Text)+import System.Environment (getArgs) +import Hledger.Cli hiding (progname, version)+import Hledger.Web.Settings (defhost, defport, defbaseurl)+ progname, version :: String progname = "hledger-web" #ifdef VERSION@@ -22,81 +25,137 @@ prognameandversion :: String prognameandversion = progname ++ " " ++ version :: String -webflags :: [Flag [([Char], [Char])]]-webflags = [- flagNone ["serve","server"] (setboolopt "serve") ("serve and log requests, don't browse or auto-exit")- ,flagReq ["host"] (\s opts -> Right $ setopt "host" s opts) "IPADDR" ("listen on this IP address (default: "++defhost++")")- ,flagReq ["port"] (\s opts -> Right $ setopt "port" s opts) "PORT" ("listen on this TCP port (default: "++show defport++")")- ,flagReq ["base-url"] (\s opts -> Right $ setopt "base-url" s opts) "BASEURL" ("set the base url (default: http://IPADDR:PORT)")- ,flagReq ["file-url"] (\s opts -> Right $ setopt "file-url" s opts) "FILEURL" ("set the static files url (default: BASEURL/static)")- ]+webflags :: [Flag [(String, String)]]+webflags =+ [ flagNone+ ["serve", "server"]+ (setboolopt "serve")+ "serve and log requests, don't browse or auto-exit"+ , flagReq+ ["host"]+ (\s opts -> Right $ setopt "host" s opts)+ "IPADDR"+ ("listen on this IP address (default: " ++ defhost ++ ")")+ , flagReq+ ["port"]+ (\s opts -> Right $ setopt "port" s opts)+ "PORT"+ ("listen on this TCP port (default: " ++ show defport ++ ")")+ , flagReq+ ["base-url"]+ (\s opts -> Right $ setopt "base-url" s opts)+ "BASEURL"+ "set the base url (default: http://IPADDR:PORT)"+ , flagReq+ ["file-url"]+ (\s opts -> Right $ setopt "file-url" s opts)+ "FILEURL"+ "set the static files url (default: BASEURL/static)"+ , flagReq+ ["capabilities"]+ (\s opts -> Right $ setopt "capabilities" s opts)+ "CAP,CAP2"+ "enable these capabilities - comma-separated, possible values are: view, add, manage (default: view,add)"+ , flagReq+ ["capabilities-header"]+ (\s opts -> Right $ setopt "capabilities-header" s opts)+ "HEADER"+ "read enabled capabilities from a HTTP header (e.g. X-Sandstorm-Permissions, disabled by default)"+ ] -webmode :: Mode [([Char], [Char])]-webmode = (mode "hledger-web" [("command","web")]- "start serving the hledger web interface"- (argsFlag "[PATTERNS]") []){- modeGroupFlags = Group {- groupUnnamed = webflags- ,groupHidden = [flagNone ["binary-filename"] (setboolopt "binary-filename") "show the download filename for this executable, and exit"]- ,groupNamed = [generalflagsgroup1]- }- ,modeHelpSuffix=[- -- "Reads your ~/.hledger.journal file, or another specified by $LEDGER_FILE or -f, and starts the full-window curses ui."- ]- }+webmode :: Mode [(String, String)]+webmode =+ (mode+ "hledger-web"+ [("command", "web")]+ "start serving the hledger web interface"+ (argsFlag "[PATTERNS]")+ [])+ { modeGroupFlags =+ Group+ { groupUnnamed = webflags+ , groupHidden =+ [ flagNone+ ["binary-filename"]+ (setboolopt "binary-filename")+ "show the download filename for this executable, and exit"+ ]+ , groupNamed = [generalflagsgroup1]+ }+ , modeHelpSuffix = []+ } -- hledger-web options, used in hledger-web and above-data WebOpts = WebOpts {- serve_ :: Bool- ,host_ :: String- ,port_ :: Int- ,base_url_ :: String- ,file_url_ :: Maybe String- ,cliopts_ :: CliOpts- } deriving (Show)+data WebOpts = WebOpts+ { serve_ :: Bool+ , host_ :: String+ , port_ :: Int+ , base_url_ :: String+ , file_url_ :: Maybe String+ , capabilities_ :: [Capability]+ , capabilitiesHeader_ :: Maybe (CI ByteString)+ , cliopts_ :: CliOpts+ } deriving (Show) defwebopts :: WebOpts-defwebopts = WebOpts- def- def- def- def- def- def+defwebopts = WebOpts def def def def def [CapView, CapAdd] Nothing def --- instance Default WebOpts where def = defwebopts+instance Default WebOpts where def = defwebopts rawOptsToWebOpts :: RawOpts -> IO WebOpts-rawOptsToWebOpts rawopts = checkWebOpts <$> do- cliopts <- rawOptsToCliOpts rawopts- let- h = fromMaybe defhost $ maybestringopt "host" rawopts- p = fromMaybe defport $ maybeintopt "port" rawopts- b = maybe (defbaseurl h p) stripTrailingSlash $ maybestringopt "base-url" rawopts- return defwebopts {- serve_ = boolopt "serve" rawopts- ,host_ = h- ,port_ = p- ,base_url_ = b- ,file_url_ = stripTrailingSlash <$> maybestringopt "file-url" rawopts- ,cliopts_ = cliopts- }+rawOptsToWebOpts rawopts =+ checkWebOpts <$> do+ cliopts <- rawOptsToCliOpts rawopts+ let h = fromMaybe defhost $ maybestringopt "host" rawopts+ p = fromMaybe defport $ maybeintopt "port" rawopts+ b =+ maybe (defbaseurl h p) stripTrailingSlash $+ maybestringopt "base-url" rawopts+ caps' = join $ T.splitOn "," . T.pack <$> listofstringopt "capabilities" rawopts+ caps = case traverse capabilityFromText caps' of+ Left e -> error' ("Unknown capability: " ++ T.unpack e)+ Right [] -> [CapView, CapAdd]+ Right xs -> xs+ return+ defwebopts+ { serve_ = boolopt "serve" rawopts+ , host_ = h+ , port_ = p+ , base_url_ = b+ , file_url_ = stripTrailingSlash <$> maybestringopt "file-url" rawopts+ , capabilities_ = caps+ , capabilitiesHeader_ = mk . BC.pack <$> maybestringopt "capabilities-header" rawopts+ , cliopts_ = cliopts+ } where- stripTrailingSlash = reverse . dropWhile (=='/') . reverse -- yesod don't like it+ stripTrailingSlash = reverse . dropWhile (== '/') . reverse -- yesod don't like it checkWebOpts :: WebOpts -> WebOpts-checkWebOpts wopts =- either usageError (const wopts) $ do- let h = host_ wopts- if any (not . (`elem` ".0123456789")) h- then Left $ "--host requires an IP address, not "++show h- else Right ()+checkWebOpts wopts = do+ let h = host_ wopts+ if any (`notElem` (".0123456789" :: String)) h+ then usageError $ "--host requires an IP address, not " ++ show h+ else wopts getHledgerWebOpts :: IO WebOpts---getHledgerWebOpts = processArgs webmode >>= return . decodeRawOpts >>= rawOptsToWebOpts getHledgerWebOpts = do- args <- getArgs >>= expandArgsAt- let args' = replaceNumericFlags args - let cmdargopts = either usageError id $ process webmode args'- rawOptsToWebOpts $ decodeRawOpts cmdargopts + args <- fmap replaceNumericFlags . expandArgsAt =<< getArgs+ rawOptsToWebOpts . decodeRawOpts . either usageError id $ process webmode args +data Capability+ = CapView+ | CapAdd+ | CapManage+ deriving (Eq, Ord, Bounded, Enum, Show)++capabilityFromText :: Text -> Either Text Capability+capabilityFromText "view" = Right CapView+capabilityFromText "add" = Right CapAdd+capabilityFromText "manage" = Right CapManage+capabilityFromText x = Left x++capabilityFromBS :: ByteString -> Either ByteString Capability+capabilityFromBS "view" = Right CapView+capabilityFromBS "add" = Right CapAdd+capabilityFromBS "manage" = Right CapManage+capabilityFromBS x = Left x
+ Hledger/Web/Widget/AddForm.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TemplateHaskell #-}++module Hledger.Web.Widget.AddForm+ ( addForm+ , addModal+ ) where++import Control.Monad.State.Strict (evalStateT)+import Data.Bifunctor (first)+import Data.List (dropWhileEnd, nub, sort, unfoldr)+import Data.Maybe (isJust)+import Data.Semigroup ((<>))+import Data.Text (Text)+import qualified Data.Text as T+import Data.Time (Day)+import Text.Blaze.Internal (Markup, preEscapedString)+import Text.JSON+import Text.Megaparsec (eof, parseErrorPretty, runParser)+import Yesod++import Hledger+import Hledger.Web.Settings (widgetFile)++addModal ::+ ( MonadWidget m+ , r ~ Route (HandlerSite m)+#if MIN_VERSION_yesod(1,6,0)+ , m ~ WidgetFor (HandlerSite m)+#else+ , m ~ WidgetT (HandlerSite m) IO+#endif+ , RenderMessage (HandlerSite m) FormMessage+ )+ => r -> Journal -> Day -> m ()+addModal addR j today = do+ (addView, addEnctype) <- generateFormPost (addForm j today)+ [whamlet|+<div .modal #addmodal tabindex="-1" role="dialog" aria-labelledby="addLabel" aria-hidden="true">+ <div .modal-dialog .modal-lg>+ <div .modal-content>+ <div .modal-header>+ <button type="button" .close data-dismiss="modal" aria-hidden="true">×+ <h3 .modal-title #addLabel>Add a transaction+ <div .modal-body>+ <form#addform.form action=@{addR} method=POST enctype=#{addEnctype}>+ ^{addView}+|]++addForm ::+ (site ~ HandlerSite m, RenderMessage site FormMessage, MonadHandler m)+ => Journal+ -> Day+ -> Markup+#if MIN_VERSION_yesod(1,6,0)+ -> MForm m (FormResult Transaction, WidgetFor site ())+#else+ -> MForm m (FormResult Transaction, WidgetT site IO ())+#endif+addForm j today = identifyForm "add" $ \extra -> do+ (dateRes, dateView) <- mreq dateField dateFS Nothing+ (descRes, descView) <- mreq textField descFS Nothing+ (acctRes, _) <- mreq listField acctFS Nothing+ (amtRes, _) <- mreq listField amtFS Nothing++ let (msgs', postRes) = case validatePostings <$> acctRes <*> amtRes of+ FormSuccess (Left es) -> (es, FormFailure ["Postings validation failed"])+ FormSuccess (Right xs) -> ([], FormSuccess xs)+ FormMissing -> ([], FormMissing)+ FormFailure es -> ([], FormFailure es)+ msgs = zip [(1 :: Int)..] $ msgs' ++ replicate (4 - length msgs') ("", "", Nothing, Nothing)++ let descriptions = sort $ nub $ tdescription <$> jtxns j+ escapeJSSpecialChars = regexReplaceCI "</script>" "<\\/script>" -- #236+ listToJsonValueObjArrayStr = preEscapedString . escapeJSSpecialChars .+ encode . JSArray . fmap (\a -> JSObject $ toJSObject [("value", showJSON a)])+ journals = fst <$> jfiles j++ pure (makeTransaction <$> dateRes <*> descRes <*> postRes, $(widgetFile "add-form"))+ where+ makeTransaction date desc postings =+ nulltransaction {tdate = date, tdescription = desc, tpostings = postings}++ dateFS = FieldSettings "date" Nothing Nothing (Just "date")+ [("class", "form-control input-lg"), ("placeholder", "Date")]+ descFS = FieldSettings "desc" Nothing Nothing (Just "description")+ [("class", "form-control input-lg typeahead"), ("placeholder", "Description"), ("size", "40")]+ acctFS = FieldSettings "amount" Nothing Nothing (Just "account") []+ amtFS = FieldSettings "amount" Nothing Nothing (Just "amount") []+ dateField = checkMMap (pure . validateDate) (T.pack . show) textField+ validateDate s =+ first (const ("Invalid date format" :: Text)) $+ fixSmartDateStrEither' today (T.strip s)++ listField = Field+ { fieldParse = const . pure . Right . Just . dropWhileEnd T.null+ , fieldView = error "Don't render using this!"+ , fieldEnctype = UrlEncoded+ }++validatePostings :: [Text] -> [Text] -> Either [(Text, Text, Maybe Text, Maybe Text)] [Posting]+validatePostings a b =+ case traverse id $ (\(_, _, x) -> x) <$> postings of+ Left _ -> Left $ foldr catPostings [] postings+ Right [] -> Left+ [ ("", "", Just "Missing account", Just "Missing amount")+ , ("", "", Just "Missing account", Nothing)+ ]+ Right [p] -> Left+ [ (paccount p, T.pack . showMixedAmountWithoutPrice $ pamount p, Nothing, Nothing)+ , ("", "", Just "Missing account", Nothing)+ ]+ Right xs -> Right xs+ where+ postings = unfoldr go (True, a, b)++ go (_, x:xs, y:ys) = Just ((x, y, zipPosting (validateAccount x) (validateAmount y)), (True, xs, ys))+ go (True, x:y:xs, []) = Just ((x, "", zipPosting (validateAccount x) (Left "Missing amount")), (True, y:xs, []))+ go (True, x:xs, []) = Just ((x, "", zipPosting (validateAccount x) (Right missingamt)), (False, xs, []))+ go (False, x:xs, []) = Just ((x, "", zipPosting (validateAccount x) (Left "Missing amount")), (False, xs, []))+ go (_, [], y:ys) = Just (("", y, zipPosting (Left "Missing account") (validateAmount y)), (False, [], ys))+ go (_, [], []) = Nothing++ zipPosting = zipEither (\acc amt -> nullposting {paccount = acc, pamount = Mixed [amt]})++ catPostings (t, t', Left (e, e')) xs = (t, t', e, e') : xs+ catPostings (t, t', Right _) xs = (t, t', Nothing, Nothing) : xs++ errorToFormMsg = first (("Invalid value: " <>) . T.pack . parseErrorPretty)+ validateAccount = errorToFormMsg . runParser (accountnamep <* eof) "" . T.strip+ validateAmount = errorToFormMsg . runParser (evalStateT (amountp <* eof) mempty) "" . T.strip++-- Modification of Align, from the `these` package+zipEither :: (a -> a' -> r) -> Either e a -> Either e' a' -> Either (Maybe e, Maybe e') r+zipEither f a b = case (a, b) of+ (Right a', Right b') -> Right (f a' b')+ (Left a', Right _) -> Left (Just a', Nothing)+ (Right _, Left b') -> Left (Nothing, Just b')+ (Left a', Left b') -> Left (Just a', Just b')
+ Hledger/Web/Widget/Common.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++module Hledger.Web.Widget.Common+ ( accountQuery+ , accountOnlyQuery+ , balanceReportAsHtml+ , helplink+ , mixedAmountAsHtml+ , fromFormSuccess+ , writeValidJournal+ , journalFile404+ ) where++import Data.Default (def)+import Data.Foldable (find, for_)+import Data.Semigroup ((<>))+import Data.Text (Text)+import qualified Data.Text as T+import System.FilePath (takeFileName)+import Text.Blaze ((!), textValue)+import qualified Text.Blaze.Html5 as H+import qualified Text.Blaze.Html5.Attributes as A+import Text.Blaze.Internal (preEscapedString)+import Text.Hamlet (hamletFile)+import Yesod++import Hledger+import Hledger.Cli.Utils (writeFileWithBackupIfChanged)+import Hledger.Web.Settings (manualurl)++#if MIN_VERSION_yesod(1,6,0)+journalFile404 :: FilePath -> Journal -> HandlerFor m (FilePath, Text)+#else+journalFile404 :: FilePath -> Journal -> HandlerT m IO (FilePath, Text)+#endif+journalFile404 f j =+ case find ((== f) . fst) (jfiles j) of+ Just (_, txt) -> pure (takeFileName f, txt)+ Nothing -> notFound++fromFormSuccess :: Applicative m => m a -> FormResult a -> m a+fromFormSuccess h FormMissing = h+fromFormSuccess h (FormFailure _) = h+fromFormSuccess _ (FormSuccess a) = pure a++writeValidJournal :: MonadHandler m => FilePath -> Text -> m (Either String ())+writeValidJournal f txt =+ liftIO (readJournal def (Just f) txt) >>= \case+ Left e -> return (Left e)+ Right _ -> do+ _ <- liftIO (writeFileWithBackupIfChanged f txt)+ return (Right ())+++-- | Link to a topic in the manual.+helplink :: Text -> Text -> HtmlUrl r+helplink topic label _ = H.a ! A.href u ! A.target "hledgerhelp" $ toHtml label+ where u = textValue $ manualurl <> if T.null topic then "" else T.cons '#' topic++-- | Render a "BalanceReport" as html.+balanceReportAsHtml :: Eq r => (r, r) -> r -> Bool -> Journal -> [QueryOpt] -> BalanceReport -> HtmlUrl r+balanceReportAsHtml (journalR, registerR) here hideEmpty j qopts (items, total) =+ $(hamletFile "templates/balance-report.hamlet")+ where+ l = ledgerFromJournal Any j+ indent a = preEscapedString $ concat $ replicate (2 + 2 * a) " "+ hasSubAccounts acct = maybe True (not . null . asubs) (ledgerAccount l acct)+ matchesAcctSelector acct = Just True == ((`matchesAccount` acct) <$> inAccountQuery qopts)++accountQuery :: AccountName -> Text+accountQuery = ("inacct:" <>) . quoteIfSpaced++accountOnlyQuery :: AccountName -> Text+accountOnlyQuery = ("inacctonly:" <>) . quoteIfSpaced++mixedAmountAsHtml :: MixedAmount -> HtmlUrl a+mixedAmountAsHtml b _ =+ for_ (lines (showMixedAmountWithoutPrice b)) $ \t -> do+ H.span ! A.class_ c $ toHtml t+ H.br+ where+ c = case isNegativeMixedAmount b of+ Just True -> "negative amount"+ _ -> "positive amount"
− Import.hs
@@ -1,22 +0,0 @@-{-# LANGUAGE CPP #-}-module Import- ( module Import- ) where--import Prelude as Import hiding (head, init, last,- readFile, tail, writeFile)-import Yesod as Import hiding (Route (..))--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative as Import (pure, (<$>), (<*>))-#endif-import Data.Text as Import (Text)--import Foundation as Import-import Settings as Import-import Settings.Development as Import-import Settings.StaticFiles as Import--#if !(MIN_VERSION_base(4,11,0))-import Data.Monoid as Import ((<>))-#endif
− Settings.hs
@@ -1,92 +0,0 @@-{-# LANGUAGE CPP, OverloadedStrings, QuasiQuotes #-}--- | Settings are centralized, as much as possible, into this file. This--- includes database connection settings, static file locations, etc.--- In addition, you can configure a number of different aspects of Yesod--- by overriding methods in the Yesod typeclass. That instance is--- declared in the Foundation.hs file.-module Settings where--import Prelude-import Text.Shakespeare.Text (st)-import Language.Haskell.TH.Syntax-import Yesod.Default.Config-import Yesod.Default.Util-import Data.Text (Text)-import Data.Yaml-#if !MIN_VERSION_base(4,8,0)-import Control.Applicative-#endif-import Settings.Development-import Data.Default (def)-import Text.Hamlet---hledgerorgurl, manualurl :: String-hledgerorgurl = "http://hledger.org"-manualurl = hledgerorgurl++"/manual"---- | The default IP address to listen on. May be overridden with --host.-defhost :: String-defhost = "127.0.0.1"---- | The default TCP port to listen on. May be overridden with --port.-defport :: Int-defport = 5000--defbaseurl :: String -> Int -> String-defbaseurl host port =- "http://" ++ host ++ if port /= 80 then ":" ++ show port else ""---- Static setting below. Changing these requires a recompile---- | The location of static files on your system. This is a file system--- path. The default value works properly with your scaffolded site.-staticDir :: FilePath-staticDir = "static"---- | The base URL for your static files. As you can see by the default--- value, this can simply be "static" appended to your application root.--- A powerful optimization can be serving static files from a separate--- domain name. This allows you to use a web server optimized for static--- files, more easily set expires and cache values, and avoid possibly--- costly transference of cookies on static files. For more information,--- please see:--- http://code.google.com/speed/page-speed/docs/request.html#ServeFromCookielessDomain------ If you change the resource pattern for StaticR in Foundation.hs, you will--- have to make a corresponding change here.------ To see how this value is used, see urlRenderOverride in Foundation.hs-staticRoot :: AppConfig DefaultEnv Extra -> Text-staticRoot conf = case extraStaticRoot $ appExtra conf of- Just root -> root- Nothing -> [st|#{appRoot conf}/static|]---- | Settings for 'widgetFile', such as which template languages to support and--- default Hamlet settings.-widgetFileSettings :: WidgetFileSettings-widgetFileSettings = def- { wfsHamletSettings = defaultHamletSettings- { hamletNewlines = AlwaysNewlines- }- }---- The rest of this file contains settings which rarely need changing by a--- user.--widgetFile :: String -> Q Exp-widgetFile = (if development then widgetFileReload- else widgetFileNoReload)- widgetFileSettings--data Extra = Extra- { extraCopyright :: Text- , extraAnalytics :: Maybe Text -- ^ Google Analytics- , extraStaticRoot :: Maybe Text- } deriving Show--parseExtra :: DefaultEnv -> Object -> Parser Extra-parseExtra _ o = Extra- <$> o .: "copyright"- <*> o .:? "analytics"- <*> o .:? "staticRoot"
− Settings/Development.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE CPP #-}-module Settings.Development where--import Prelude--development :: Bool-development =-#if DEVELOPMENT- True-#else- False-#endif--production :: Bool-production = not development
− Settings/StaticFiles.hs
@@ -1,33 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}-module Settings.StaticFiles where--import Prelude (IO, putStrLn, (++), (>>), return)-import System.IO (stdout, hFlush)-import Yesod.Static-import qualified Yesod.Static as Static-import Settings (staticDir)-import Settings.Development---- | use this to create your static file serving site--- staticSite :: IO Static.Static--- staticSite = if development then Static.staticDevel staticDir--- else Static.static staticDir------ | This generates easy references to files in the static directory at compile time,--- giving you compile-time verification that referenced files exist.--- Warning: any files added to your static directory during run-time can't be--- accessed this way. You'll have to use their FilePath or URL to access them.--- $(staticFiles Settings.staticDir)---staticSite :: IO Static.Static-staticSite =- if development- then (do- putStrLn ("Using web files from: " ++ staticDir ++ "/") >> hFlush stdout- Static.staticDevel staticDir)- else (do- -- putStrLn "Using built-in web files" >> hFlush stdout- return $(Static.embed staticDir))--$(publicFiles staticDir)
config/routes view
@@ -1,10 +1,13 @@ /favicon.ico FaviconR GET /robots.txt RobotsR GET /static StaticR Static getStatic+ / RootR GET-/journal JournalR GET POST-/register RegisterR GET POST-/sidebar SidebarR GET+/journal JournalR GET+/register RegisterR GET+/add AddR GET POST --- /accounts AccountsR GET--- /api/accounts AccountsJsonR GET+/manage ManageR GET+/edit/#FilePath EditR GET POST+/upload/#FilePath UploadR GET POST+/download/#FilePath DownloadR GET
hledger-web.1 view
@@ -1,5 +1,5 @@ -.TH "hledger\-web" "1" "April 2018" "hledger\-web 1.9.1" "hledger User Manuals"+.TH "hledger\-web" "1" "June 2018" "hledger\-web 1.9.99" "hledger User Manuals"
hledger-web.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 1872196bf7e9ff50fae0f3ea64ea81d1155799a2779617be58c9acf7f6aabce8+-- hash: 819abf18972b92028b9ccb3e8b1c5404368f8ca74e855c6fa226884dd01995a8 name: hledger-web-version: 1.9.2+version: 1.10 synopsis: Web interface for the hledger accounting tool description: This is hledger's web interface. It provides a more user-friendly and collaborative UI than the@@ -25,7 +25,7 @@ maintainer: Simon Michael <simon@joyful.com> license: GPL-3 license-file: LICENSE-tested-with: GHC==7.10.3, GHC==8.0.2, GHC==8.2.1+tested-with: GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.1 build-type: Simple cabal-version: >= 1.10 extra-source-files:@@ -38,7 +38,6 @@ hledger-web.1 hledger-web.info hledger-web.txt- messages/en.msg README static/css/bootstrap-datepicker.standalone.min.css static/css/bootstrap-theme.css@@ -97,8 +96,16 @@ static/js/jquery.url.js static/js/typeahead.bundle.js static/js/typeahead.bundle.min.js+ templates/add-form.hamlet+ templates/balance-report.hamlet+ templates/chart.hamlet templates/default-layout-wrapper.hamlet templates/default-layout.hamlet+ templates/edit-form.hamlet+ templates/journal.hamlet+ templates/manage.hamlet+ templates/register.hamlet+ templates/upload-form.hamlet source-repository head type: git@@ -120,50 +127,52 @@ default: True library+ hs-source-dirs:+ ./. exposed-modules:- Application- Foundation- Handler.AddForm- Handler.Common- Handler.JournalR- Handler.RegisterR- Handler.RootR- Handler.SidebarR- Handler.Utils Hledger.Web+ Hledger.Web.Application+ Hledger.Web.Foundation+ Hledger.Web.Handler.AddR+ Hledger.Web.Handler.Common+ Hledger.Web.Handler.EditR+ Hledger.Web.Handler.JournalR+ Hledger.Web.Handler.RegisterR+ Hledger.Web.Handler.UploadR+ Hledger.Web.Import Hledger.Web.Main+ Hledger.Web.Settings+ Hledger.Web.Settings.StaticFiles Hledger.Web.WebOptions- Import- Settings- Settings.Development- Settings.StaticFiles+ Hledger.Web.Widget.AddForm+ Hledger.Web.Widget.Common other-modules: Paths_hledger_web- ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans- cpp-options: -DVERSION="1.9.2"+ ghc-options: -Wall -fwarn-tabs+ cpp-options: -DVERSION="1.10" build-depends: HUnit , base >=4.8 && <4.12- , base-compat >=0.8.1 , blaze-html , blaze-markup , bytestring+ , case-insensitive , clientsession , cmdargs >=0.10+ , conduit , conduit-extra >=1.1 , data-default , directory , filepath , hjsmin- , hledger >=1.9.1 && <2.0- , hledger-lib >=1.9.1 && <2.0+ , hledger >=1.10 && <1.11+ , hledger-lib >=1.10 && <1.11 , http-client , http-conduit , json- , megaparsec >=5.0+ , megaparsec >=6.4.1 , mtl- , parsec >=3- , safe >=0.2+ , semigroups , shakespeare >=2.0.2.2 , template-haskell , text >=1.2@@ -178,10 +187,8 @@ , yesod-core >=1.4 && <1.7 , yesod-form >=1.4 && <1.7 , yesod-static >=1.4 && <1.7- if (flag(dev)) || (flag(library-only))- cpp-options: -DDEVELOPMENT- if flag(dev)- ghc-options: -O0+ if impl(ghc >=8)+ ghc-options: -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates -Wredundant-constraints default-language: Haskell2010 executable hledger-web@@ -190,109 +197,15 @@ Paths_hledger_web hs-source-dirs: app- ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans- cpp-options: -DVERSION="1.9.2"+ ghc-options: -Wall -fwarn-tabs+ cpp-options: -DVERSION="1.10" build-depends:- HUnit- , base >=4.8 && <4.12- , base-compat >=0.8.1- , blaze-html- , blaze-markup- , bytestring- , clientsession- , cmdargs >=0.10- , conduit-extra >=1.1- , data-default- , directory- , filepath- , hjsmin- , hledger >=1.9.1 && <2.0- , hledger-lib >=1.9.1 && <2.0+ base , hledger-web- , http-client- , http-conduit- , json- , megaparsec >=5.0- , mtl- , parsec >=3- , safe >=0.2- , shakespeare >=2.0.2.2- , template-haskell- , text >=1.2- , time >=1.5- , transformers- , wai- , wai-extra- , wai-handler-launch >=1.3- , warp- , yaml- , yesod >=1.4 && <1.7- , yesod-core >=1.4 && <1.7- , yesod-form >=1.4 && <1.7- , yesod-static >=1.4 && <1.7- if (flag(dev)) || (flag(library-only))- cpp-options: -DDEVELOPMENT- if flag(dev)- ghc-options: -O0+ if impl(ghc >=8)+ ghc-options: -Wcompat -Wincomplete-uni-patterns -Wincomplete-record-updates -Wredundant-constraints if flag(library-only) buildable: False if flag(threaded) ghc-options: -threaded- default-language: Haskell2010--test-suite test- type: exitcode-stdio-1.0- main-is: main.hs- other-modules:- HomeTest- TestImport- Paths_hledger_web- hs-source-dirs:- tests- ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans- cpp-options: -DVERSION="1.9.2"- build-depends:- HUnit- , base >=4.8 && <4.12- , base-compat >=0.8.1- , blaze-html- , blaze-markup- , bytestring- , clientsession- , cmdargs >=0.10- , conduit-extra >=1.1- , data-default- , directory- , filepath- , hjsmin- , hledger >=1.9.1 && <2.0- , hledger-lib >=1.9.1 && <2.0- , hledger-web- , hspec- , http-client- , http-conduit- , json- , megaparsec >=5.0- , mtl- , parsec >=3- , safe >=0.2- , shakespeare >=2.0.2.2- , template-haskell- , text >=1.2- , time >=1.5- , transformers- , wai- , wai-extra- , wai-handler-launch >=1.3- , warp- , yaml- , yesod >=1.4 && <1.7- , yesod-core >=1.4 && <1.7- , yesod-form >=1.4 && <1.7- , yesod-static >=1.4 && <1.7- , yesod-test- if (flag(dev)) || (flag(library-only))- cpp-options: -DDEVELOPMENT- if flag(dev)- ghc-options: -O0 default-language: Haskell2010
hledger-web.info view
@@ -3,8 +3,8 @@ File: hledger-web.info, Node: Top, Next: OPTIONS, Up: (dir) -hledger-web(1) hledger-web 1.9.1-********************************+hledger-web(1) hledger-web 1.9.99+********************************* hledger-web is hledger's web interface. It starts a simple web application for browsing and adding transactions, and optionally opens@@ -209,7 +209,7 @@ Tag Table: Node: Top72-Node: OPTIONS3156-Ref: #options3241+Node: OPTIONS3158+Ref: #options3243 End Tag Table
hledger-web.txt view
@@ -248,4 +248,4 @@ -hledger-web 1.9.1 April 2018 hledger-web(1)+hledger-web 1.9.99 June 2018 hledger-web(1)
− messages/en.msg
@@ -1,1 +0,0 @@-Hello: Hello
static/hledger.css view
@@ -20,38 +20,7 @@ /*------------------------------------------------------------------------------------------*/ /* 4. typeahead styles */ -/*-.typeahead,-.tt-query, .tt-hint {- width: 396px;- height: 30px;- padding: 8px 12px;- font-size: 24px;- line-height: 30px;- border: 2px solid #ccc;- -webkit-border-radius: 8px;- -moz-border-radius: 8px;- border-radius: 8px;- outline: none;-}--.typeahead {- background-color: #fff;-}--.typeahead:focus {- border: 2px solid #0097cf;-}--.tt-query {- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);-}--*/-.tt-hint { color: #bbb; } @@ -70,9 +39,6 @@ max-height:300px; } -.tt-suggestions {-}- .tt-suggestion { padding: 3px 20px; font-size: 18px;@@ -82,7 +48,6 @@ .tt-suggestion.tt-cursor { color: #fff; background-color: #0097cf;- } .tt-suggestion p {@@ -100,7 +65,7 @@ ul { list-style-type: none;- padding: 0;+ padding: 0; } #main-content {@@ -136,51 +101,37 @@ #sidebar-menu .main-menu a { display: inline;- font-size: 16px;- font-weight: 500;- color: #2F2F2F;- padding: 4px 20px;+ font-size: 16px;+ font-weight: 500;+ color: #2F2F2F;+ padding: 4px 20px; } #sidebar-menu .main-menu a:hover {- color: #11427D;- text-decoration: none;- background-color: transparent;+ color: #11427D;+ text-decoration: none;+ background-color: transparent; } -#sidebar-menu .main-menu .only{+#sidebar-menu .main-menu .only { visibility: hidden; padding: 1px; } -#sidebar-menu .main-menu tr:hover > td > div > .only {+#sidebar-menu .main-menu tr:hover .only { visibility: visible; } -#sidebar-menu .main-menu .only:hover{- border-left: none;-}-#sidebar-menu .main-menu .balance {- float: right;-}--#sidebar-menu .main-menu .total {- border-left: none;- border-right: none;- border-bottom: none;- border-top: 1px solid black;-}--#sidebar-menu .main-menu .inacct {+#sidebar-menu .main-menu .inacct, #sidebar-menu .main-menu .inacct .acct-name { font-weight: bold;- color: #11427D;+ color: #11427D; background-color: #f9f9f9; } #sidebar-menu .main-menu .amount { float: right; overflow-x:auto;- font-weight: 500 !important;+ font-weight: 500 !important; } #sidebar-menu .main-menu .acct {@@ -188,7 +139,7 @@ vertical-align:bottom; } -.transactionsreport .nonhead {+.transactionsreport .posting td { border: none !important; } @@ -200,24 +151,6 @@ whitespace: nowrap; } -#main-content {- /*- -webkit-transition: width 0.3s ease, margin 0.3s ease;- -moz-transition: width 0.3s ease, margin 0.3s ease;- -o-transition: width 0.3s ease, margin 0.3s ease;- transition: width 0.3s ease, margin 0.3s ease;-*/-}--#sidebar-menu {- /*- -webkit-transition: width 0.3s ease, margin 0.3s ease,opacity 0.3s ease,height 1s ease 1s;- -moz-transition: width 0.3s ease, margin 0.3s ease,opacity 0.3s ease,height 1s ease 1s;- -o-transition: width 0.3s ease, margin 0.3s ease,opacity 0.3s ease,height 1s ease 1s;- transition: width 0.3s ease, margin 0.3s ease,opacity 0.3s ease,height 1s ease 1s;-*/-}- .col-any-0 { width:0 !important; height:0 !important;@@ -227,10 +160,6 @@ .tgl-icon { font-size:large;-}--#searchbar {- width: 100% !important; } @media screen and (max-width: 768px) {
static/hledger.js view
@@ -4,9 +4,13 @@ // STARTUP $(document).ready(function() {- // cache the input element as a variable- // for minor performance benefits- var dateEl = $('#dateWrap');+ // date picker+ // http://bootstrap-datepicker.readthedocs.io/en/latest/options.html+ var dateEl = $('#dateWrap').datepicker({+ showOnFocus: false,+ autoclose: true,+ format: 'yyyy-mm-dd'+ });; // ensure add form always focuses its first field $('#addmodal')@@ -18,36 +22,22 @@ dateEl.datepicker('hide'); }); - // show add form if ?add=1- if ($.url.param('add')) { addformShow(true); }-- // date picker- // http://bootstrap-datepicker.readthedocs.io/en/latest/options.html- dateEl.datepicker({- showOnFocus: false,- autoclose: true,- format: 'yyyy-mm-dd'- });-- // sidebar account hover handlers- $('#sidebar td a').mouseenter(function(){ $(this).parent().addClass('mouseover'); });- $('#sidebar td').mouseleave(function(){ $(this).removeClass('mouseover'); });- // keyboard shortcuts // 'body' seems to hold focus better than document in FF $('body').bind('keydown', 'h', function(){ $('#helpmodal').modal('toggle'); return false; }); $('body').bind('keydown', 'shift+/', function(){ $('#helpmodal').modal('toggle'); return false; }); $('body').bind('keydown', 'j', function(){ location.href = document.hledgerWebBaseurl+'/journal'; return false; }); $('body').bind('keydown', 's', function(){ sidebarToggle(); return false; });+ $('body').bind('keydown', 'e', function(){ emptyAccountsToggle(); return false; }); $('body').bind('keydown', 'a', function(){ addformShow(); return false; }); $('body').bind('keydown', 'n', function(){ addformShow(); return false; }); $('body').bind('keydown', 'f', function(){ $('#searchform input').focus(); return false; });+ $('body, #addform input, #addform select').bind('keydown', 'ctrl++', addformAddPosting); $('body, #addform input, #addform select').bind('keydown', 'ctrl+shift+=', addformAddPosting); $('body, #addform input, #addform select').bind('keydown', 'ctrl+=', addformAddPosting); $('body, #addform input, #addform select').bind('keydown', 'ctrl+-', addformDeletePosting); $('.amount-input:last').keypress(addformAddPosting); - // highlight the entry from the url hash if (window.location.hash && $(window.location.hash)[0]) { $(window.location.hash).addClass('highlighted');@@ -78,10 +68,9 @@ position: 'sw' }, grid: {- markings:- function (axes) {+ markings: function () { var now = Date.now();- var markings = [+ return [ { xaxis: { to: now }, // past yaxis: { to: 0 }, // <0@@ -103,7 +92,6 @@ lineWidth:1 }, ];- return markings; }, hoverable: true, autoHighlight: true,@@ -127,16 +115,17 @@ } function registerChartClick(ev, pos, item) {- if (item) {- targetselector = '#'+item.series.data[item.dataIndex][5];- $target = $(targetselector);- if ($target.length) {- window.location.hash = targetselector;- $('html, body').animate({- scrollTop: $target.offset().top- }, 1000);- }+ if (!item) {+ return; }+ var targetselector = '#' + item.series.data[item.dataIndex][5];+ var $target = $(targetselector);+ if ($target.length) {+ window.location.hash = targetselector;+ $('html, body').animate({+ scrollTop: $target.offset().top+ }, 1000);+ } } //----------------------------------------------------------------------@@ -174,59 +163,46 @@ // Insert another posting row in the add form. function addformAddPosting() {- $('.amount-input:last').off('keypress');- // do nothing if it's not currently visible- if (!$('#addform').is(':visible')) return;- // save a copy of last row- var lastrow = $('#addform .form-group:last').clone();+ if (!$('#addform').is(':visible')) {+ return;+ } - // replace the submit button with an amount field, clear and renumber it, add the keybindings- var num = $('#addform .account-group').length;+ var prevLastRow = $('#addform .account-group:last');+ prevLastRow.off('keypress'); - // insert the new last row- $('#addform .account-postings').append(lastrow);- // TODO: Enable typehead on dynamically created inputs+ // Clone the currently last row+ $('#addform .account-postings').append(prevLastRow.clone());+ var num = $('#addform .account-group').length; - var $acctinput = $('.account-input:last');- var $amntinput = $('.amount-input:last'); // clear and renumber the field, add keybindings- $acctinput- .val('')- .prop('id','account'+(num+1))- .prop('name','account'+(num+1))- .prop('placeholder','Account '+(num+1));- //lastrow.find('input') // not :last this time- $acctinput- .bind('keydown', 'ctrl+shift+=', addformAddPosting)- .bind('keydown', 'ctrl+=', addformAddPosting)- .bind('keydown', 'ctrl+-', addformDeletePosting);-- $amntinput+ // XXX Enable typehead on dynamically created inputs+ $('.amount-input:last') .val('')- .prop('id','amount'+(num+1))- .prop('name','amount'+(num+1))- .prop('placeholder','Amount '+(num+1))+ .prop('placeholder','Amount ' + num) .keypress(addformAddPosting); - $acctinput+ $('.account-input:last')+ .val('')+ .prop('placeholder', 'Account ' + num)+ .bind('keydown', 'ctrl++', addformAddPosting) .bind('keydown', 'ctrl+shift+=', addformAddPosting) .bind('keydown', 'ctrl+=', addformAddPosting) .bind('keydown', 'ctrl+-', addformDeletePosting);- } // Remove the add form's last posting row, if empty, keeping at least two. function addformDeletePosting() {- var num = $('#addform .account-group').length;- if (num <= 2) return;+ if ($('#addform .account-group').length <= 2) {+ return;+ } // remember if the last row's field or button had focus var focuslost = $('.account-input:last').is(':focus') || $('.amount-input:last').is(':focus'); // delete last row $('#addform .account-group:last').remove();- if(focuslost){- focus($('account-input:last'));+ if (focuslost) {+ focus($('.account-input:last')); } // Rebind keypress $('.amount-input:last').keypress(addformAddPosting);@@ -242,46 +218,7 @@ $.cookie('showsidebar', $('#sidebar-menu').hasClass('col-any-0') ? '0' : '1'); } -//-----------------------------------------------------------------------// MISC--function enableTypeahead($el, suggester) {- return $el.typeahead(- {- highlight: true- },- {- source: suggester.ttAdapter()- }- );+function emptyAccountsToggle() {+ $('.acct.empty').parent().toggleClass('hide');+ $.cookie('hideemptyaccts', $.cookie('hideemptyaccts') === '1' ? '0' : '1') }--// function journalSelect(ev) {-// var textareas = $('textarea', $('form#editform'));-// for (i=0; i<textareas.length; i++) {-// textareas[i].style.display = 'none';-// textareas[i].disabled = true;-// }-// var targ = getTarget(ev);-// if (targ.value) {-// var journalid = targ.value+'_textarea';-// var textarea = document.getElementById(journalid);-// }-// else {-// var textarea = textareas[0];-// }-// textarea.style.display = 'block';-// textarea.disabled = false;-// return true;-// }--// // Get the current event's target in a robust way.-// // http://www.quirksmode.org/js/events_properties.html-// function getTarget(ev) {-// var targ;-// if (!ev) var ev = window.event;-// if (ev.target) targ = ev.target;-// else if (ev.srcElement) targ = ev.srcElement;-// if (targ.nodeType == 3) targ = targ.parentNode;-// return targ;-// }
+ templates/add-form.hamlet view
@@ -0,0 +1,71 @@+<script>+ jQuery(document).ready(function() {+ descriptionsSuggester = new Bloodhound({+ local:#{listToJsonValueObjArrayStr descriptions},+ limit:100,+ datumTokenizer: function(d) { return [d.value]; },+ queryTokenizer: function(q) { return [q]; }+ });+ descriptionsSuggester.initialize();++ accountsSuggester = new Bloodhound({+ local:#{listToJsonValueObjArrayStr (journalAccountNamesDeclaredOrImplied j)},+ limit:100,+ datumTokenizer: function(d) { return [d.value]; },+ queryTokenizer: function(q) { return [q]; }+ });+ accountsSuggester.initialize();++ jQuery('input[name=description]').typeahead({ highlight: true }, { source: descriptionsSuggester.ttAdapter() });+ jQuery('input[name=account]').typeahead({ highlight: true }, { source: accountsSuggester.ttAdapter() });+ });+^{extra}++<div .form-group>+ <div .row>+ <div .col-md-3 .col-xs-6 .col-sm-6 :isJust (fvErrors dateView):.has-error>+ <div #dateWrap .form-group.input-group.date>+ ^{fvInput dateView}+ <div .input-group-addon>+ <span .glyphicon .glyphicon-th>+ $maybe err <- fvErrors dateView+ <span .help-block .error-block>#{err}+ <div .col-md-9 .col-xs-6 .col-sm-6 :isJust (fvErrors descView):.has-error>+ <div .form-group>+ ^{fvInput descView}+ $maybe err <- fvErrors descView+ <span .help-block .error-block>#{err}+ <div .row>+ <div .col-md-3 .col-xs-6 .col-sm-6>+ <div .col-md-9 .col-xs-6 .col-sm-6>++<div .account-postings>+ $forall (n, (acc, amt, accE, amtE)) <- msgs+ <div .form-group .row .account-group>+ <div .col-md-8 .col-xs-8 .col-sm-8 :isJust accE:.has-error>+ <input .account-input.form-control.input-lg.typeahead type=text+ name=account placeholder="Account #{n}" value="#{acc}">+ $maybe err <- accE+ <span .help-block .error-block>_{err}+ <div .col-md-4 .col-xs-4 .col-sm-4 :isJust amtE:.has-error>+ <input .amount-input.form-control.input-lg type=text+ name=amount placeholder="Amount #{n}" value="#{amt}">+ $maybe err <- amtE+ <span .help-block .error-block>_{err}++<div .row>+ <div .col-md-8 .col-xs-8 .col-sm-8>+ <div .col-md-4 .col-xs-4 .col-sm-4>+ <button type=submit .btn .btn-default .btn-lg name=submit>add++$if length journals > 1+ <br>+ <span .input-lg>to:+ <select #journalselect .form-control.input-lg name=journal style="width:auto; display:inline-block;">+ $forall p <- journals+ <option value=#{p}>#{p}+<span .small style="padding-left:2em;">+ Enter a value in the last field for #+ <a href="#" onclick="addformAddPosting(); return false;">+ more+ \ (or ctrl +, ctrl -)
+ templates/balance-report.hamlet view
@@ -0,0 +1,25 @@+<tr :here == journalR:.inacct>+ <td .top .acct>+ <a href=@{journalR} :here == journalR:.inacct+ title="Show general journal entries, most recent first">+ Journal+ <td .top>+$forall (acct, adisplay, aindent, abal) <- items+ <tr+ :matchesAcctSelector acct:.inacct+ :isZeroMixedAmount abal && hideEmpty:.hide>+ <td .acct :isZeroMixedAmount abal:.empty>+ <div .ff-wrapper>+ \#{indent aindent}+ <a.acct-name href="@?{(registerR, [("q", accountQuery acct)])}"+ title="Show transactions affecting this account and subaccounts">+ #{adisplay}+ $if hasSubAccounts acct+ <a href="@?{(registerR, [("q", accountOnlyQuery acct)])}" .only.hidden-sm.hidden-xs+ title="Show transactions affecting this account but not subaccounts">only+ <td>+ ^{mixedAmountAsHtml abal}+<tr .total>+ <td>+ <td>+ ^{mixedAmountAsHtml total}
+ templates/chart.hamlet view
@@ -0,0 +1,59 @@+<label #register-chart-label style=""><br>+<div #register-chart style="height:150px; margin-bottom:1em; display:block;">+<script type=text/javascript>+ \$(document).ready(function() {+ var $chartdiv = $('#register-chart');+ if ($chartdiv.is(':visible')) {+ \$('#register-chart-label').text('#{charttitle}');+ var seriesData = [+ $forall (c,(_,items)) <- percommoditytxnreports+ /* we render each commodity using two series:+ * one with extra data points added to show a stepped balance line */+ {+ data: [+ $forall i <- reverse items+ [+ #{dayToJsTimestamp $ triDate i},+ #{simpleMixedAmountQuantity $ triCommodityBalance c i}+ ],+ ],+ label: '#{shownull $ T.unpack c}',+ color: #{colorForCommodity c},+ lines: {+ show: true,+ steps: true,+ },+ points: {+ show: false,+ },+ clickable: false,+ hoverable: false,+ },+ /* and one with the original data, showing one clickable, hoverable point per transaction */+ {+ data: [+ $forall i <- reverse items+ [+ #{dayToJsTimestamp $ triDate i},+ #{simpleMixedAmountQuantity $ triCommodityBalance c i},+ '#{showMixedAmountWithZeroCommodity $ triCommodityAmount c i}',+ '#{showMixedAmountWithZeroCommodity $ triCommodityBalance c i}',+ '#{concat $ intersperse "\\n" $ lines $ show $ triOrigTransaction i}',+ #{tindex $ triOrigTransaction i}+ ],+ /* [] */+ ],+ label: '',+ color: #{colorForCommodity c},+ lines: {+ show: false,+ },+ points: {+ show: true,+ },+ },+ ]+ var plot = registerChart($chartdiv, seriesData);+ \$chartdiv.bind("plotclick", registerChartClick);+ };+ });
templates/default-layout-wrapper.hamlet view
@@ -29,7 +29,7 @@ <div .row .row-offcanvas .row-offcanvas-left> ^{pageBody pc} <footer>- #{extraCopyright $ appExtra $ settings master}+ #{extraCopyright $ appExtra $ settings master} $maybe analytics <- extraAnalytics $ appExtra $ settings master <script>@@ -47,61 +47,3 @@ <script> window.attachEvent('onload',function(){CFInstall.check({mode:'overlay'})}) \<![endif]-->-- <div .modal.fade #helpmodal tabindex="-1" role="dialog" aria-labelledby="helpLabel" aria-hidden="true">- <div .modal-dialog .modal-lg>- <div .modal-content>- <div .modal-header>- <button type="button" .close data-dismiss="modal" aria-hidden="true">×- <h3 .modal-title #helpLabel>Help- <div .modal-body>- <div .row>- <div .col-xs-6>- <p>- <b>Keyboard shortcuts- <ul>- <li> <code>h</code> or maybe <code>?</code> - view this help (escape or click to exit)- <li> <code>j</code> - go to the Journal view (home)- <li> <code>a</code> - add a transaction (escape to cancel)- <li> <code>s</code> - toggle sidebar- <li> <code>f</code> - focus search form ("find")- <p>- <b>General- <ul>- <li> The Journal view shows general journal entries, representing zero-sum movements of money (or other commodity) between hierarchical accounts- <li> The sidebar shows the resulting accounts and their final balances- <li> Parent account balances include subaccount balances- <li> Multiple currencies in balances are displayed one above the other- <li> Click account name links to see transactions affecting that account, with running balance- <li> Click date links to see journal entries on that date- <div .col-xs-6>- <p>- <b>Search- <ul>- <li> <code>acct:REGEXP</code> - filter on to/from account- <li> <code>desc:REGEXP</code> - filter on description- <li> <code>date:PERIODEXP</code>, <code>date2:PERIODEXP</code> - filter on date or secondary date- <li> <code>code:REGEXP</code> - filter on transaction's code (eg check number)- <li> <code>status:*</code>, <code>status:!</code>, <code>status:</code> - filter on transaction's cleared status (cleared, pending, uncleared)- <!-- <li> <code>empty:BOOL</code> - filter on whether amount is zero -->- <li> <code>amt:N</code>, <code>amt:<N</code>, <code>amt:>N</code> - filter on the unsigned amount magnitude. Or with a sign before N, filter on the signed value. (Single-commodity amounts only.)- <li> <code>cur:REGEXP</code> - filter on the currency/commodity symbol (must match all of it). Dollar sign must be written as <code>\$</code>- <li> <code>tag:NAME</code>, <code>tag:NAME=REGEX</code> - filter on tag name, or tag name and value- <!-- <li> <code>depth:N</code> - filter out accounts below this depth -->- <li> <code>real:BOOL</code> - filter on postings' real/virtual-ness- <li> Enclose search patterns containing spaces in single or double quotes- <li> Prepend <code>not:</code> to negate a search term- <li> Multiple search terms on different fields are AND'ed, multiple search terms on the same field are OR'ed- <li> These search terms also work with command-line hledger-- <div .modal #addmodal tabindex="-1" role="dialog" aria-labelledby="addLabel" aria-hidden="true">- <div .modal-dialog .modal-lg>- <div .modal-content>- <div .modal-header>- <button type="button" .close data-dismiss="modal" aria-hidden="true">×- <h3 .modal-title #addLabel>Add a transaction- <div .modal-body>- $maybe m <- lastmsg- $if isPrefixOf "Errors" (renderHtml m)- <div #message>#{m}- ^{addform staticRootUrl vd}
templates/default-layout.hamlet view
@@ -1,4 +1,81 @@-$maybe m <- lastmsg- $if not $ isPrefixOf "Errors" (renderHtml m)- <div #message>#{m}-^{widget}++<div#spacer .col-xs-2.#{topShowsm}.#{topShowmd}>+ <h1>+ <button .visible-xs.btn.btn-default type="button" data-toggle="offcanvas">+ <span .glyphicon.glyphicon-align-left.tgl-icon>++<div#topbar .col-md-8 .col-sm-8 .col-xs-10>+ <h1>#{takeFileName (journalFilePath j)}++$if elem CapView caps+ <div#sidebar-menu .sidebar-offcanvas.#{sideShowmd}.#{sideShowsm}>+ <table .main-menu .table>+ ^{accounts}++<div#main-content .col-xs-12.#{mainShowmd}.#{mainShowsm}>+ $maybe m <- msg+ <div #message .alert.alert-info>#{m}+ $if elem CapView caps+ <form#searchform.input-group method=GET>+ <input .form-control name=q value=#{q} placeholder="Search"+ title="Enter hledger search patterns to filter the data below">+ <div .input-group-btn>+ $if not (T.null q)+ <a href=@{here} .btn .btn-default title="Clear search terms">+ <span .glyphicon .glyphicon-remove-circle>+ <button .btn .btn-default type=submit title="Apply search terms">+ <span .glyphicon .glyphicon-search>+ $if elem CapManage caps+ <a href="@{ManageR}" .btn.btn-default title="Manage journal files">+ <span .glyphicon .glyphicon-wrench>+ <button .btn .btn-default type=button data-toggle="modal" data-target="#helpmodal"+ title="Show search and general help">+ <span .glyphicon .glyphicon-question-sign>+ ^{widget}++<div .modal.fade #helpmodal tabindex="-1" role="dialog" aria-labelledby="helpLabel" aria-hidden="true">+ <div .modal-dialog .modal-lg>+ <div .modal-content>+ <div .modal-header>+ <button type="button" .close data-dismiss="modal" aria-hidden="true">×+ <h3 .modal-title #helpLabel>Help+ <div .modal-body>+ <div .row>+ <div .col-xs-6>+ <p>+ <b>Keyboard shortcuts+ <ul>+ <li> <code>h</code> or maybe <code>?</code> - view this help (escape or click to exit)+ <li> <code>j</code> - go to the Journal view (home)+ <li> <code>a</code> - add a transaction (escape to cancel)+ <li> <code>s</code> - toggle sidebar+ <li> <code>f</code> - focus search form ("find")+ <li> <code>e</code> - hide empty accounts in sidebar+ <p>+ <b>General+ <ul>+ <li> The Journal view shows general journal entries, representing zero-sum movements of money (or other commodity) between hierarchical accounts+ <li> The sidebar shows the resulting accounts and their final balances+ <li> Parent account balances include subaccount balances+ <li> Multiple currencies in balances are displayed one above the other+ <li> Click account name links to see transactions affecting that account, with running balance+ <li> Click date links to see journal entries on that date+ <div .col-xs-6>+ <p>+ <b>Search+ <ul>+ <li> <code>acct:REGEXP</code> - filter on to/from account+ <li> <code>desc:REGEXP</code> - filter on description+ <li> <code>date:PERIODEXP</code>, <code>date2:PERIODEXP</code> - filter on date or secondary date+ <li> <code>code:REGEXP</code> - filter on transaction's code (eg check number)+ <li> <code>status:*</code>, <code>status:!</code>, <code>status:</code> - filter on transaction's cleared status (cleared, pending, uncleared)+ <!-- <li> <code>empty:BOOL</code> - filter on whether amount is zero -->+ <li> <code>amt:N</code>, <code>amt:<N</code>, <code>amt:>N</code> - filter on the unsigned amount magnitude. Or with a sign before N, filter on the signed value. (Single-commodity amounts only.)+ <li> <code>cur:REGEXP</code> - filter on the currency/commodity symbol (must match all of it). Dollar sign must be written as <code>\$</code>+ <li> <code>tag:NAME</code>, <code>tag:NAME=REGEX</code> - filter on tag name, or tag name and value+ <!-- <li> <code>depth:N</code> - filter out accounts below this depth -->+ <li> <code>real:BOOL</code> - filter on postings' real/virtual-ness+ <li> Enclose search patterns containing spaces in single or double quotes+ <li> Prepend <code>not:</code> to negate a search term+ <li> Multiple search terms on different fields are AND'ed, multiple search terms on the same field are OR'ed+ <li> These search terms also work with command-line hledger
+ templates/edit-form.hamlet view
@@ -0,0 +1,17 @@+#{extra}+<h2>+ Edit file #+ <i>#{f}+<div.alert.alert-danger>+ Are you sure? This will overwrite your journal!+<table.table.table-condensed>+ <tr>+ <td colspan=2 style="border:0">+ ^{fvInput tView}+ <tr>+ <td style="border:0">+ <span.help>+ ^{helplink "file-format" "File format help"}+ <td .text-right style="border:0">+ <a.btn.btn-default href="@{ManageR}">Go back+ <input.btn.btn-default type=submit value="Save">
+ templates/journal.hamlet view
@@ -0,0 +1,39 @@+<h2>+ #{title'}++$if elem CapAdd caps+ <a #addformlink href="#" role="button" style="cursor:pointer; margin-top:1em;"+ data-toggle="modal" data-target="#addmodal" title="Add a new transaction to the journal">+ Add a transaction++<div .table-responsive>+ <table .transactionsreport .table .table-condensed>+ <thead>+ <th .date style="text-align:left;">Date+ <th .description style="text-align:left;">Description+ <th .account style="text-align:left;">Account+ <th .amount style="text-align:right;">Amount++ $forall (torig, _, split, _, amt, _) <- items+ <tr .title #transaction-#{tindex torig}>+ <td .date nowrap>+ #{show (tdate torig)}+ <td colspan=2>+ #{textElideRight 60 (tdescription torig)}+ <td .amount style="text-align:right;">+ $if not split && not (isZeroMixedAmount amt)+ ^{mixedAmountAsHtml amt}++ $forall Posting { paccount = acc, pamount = amt } <- tpostings torig+ <tr .posting title="#{show torig}">+ <td>+ <td>+ <td>+ + <a href="@?{acctlink acc}##{tindex torig}" title="#{acc}">+ #{elideAccountName 40 acc}+ <td .amount style="text-align:right;">+ ^{mixedAmountAsHtml amt}++$if elem CapAdd caps+ ^{addModal AddR j today}
+ templates/manage.hamlet view
@@ -0,0 +1,22 @@+<h2>+ Your journal's files++<div.row>+ <div .col-xs-12.col-sm-8.col-md-6>+ <table .table.table-condensed>+ <thead>+ <th>+ File+ <th>+ <tbody>+ $forall (path, _) <- jfiles j+ <tr>+ <td style="vertical-align:middle">+ #{path}+ <td style="text-align:right">+ <a.btn.btn-default href=@{EditR path}>+ Edit+ <a.btn.btn-default href=@{UploadR path}>+ Upload+ <a.btn.btn-default href=@{DownloadR path}>+ Download
+ templates/register.hamlet view
@@ -0,0 +1,37 @@+<h2>+ #{header}++<div .hidden-xs>+ ^{registerChartHtml $ transactionsReportByCommodity r}++<div.table-responsive>+ <table .table.table-striped.table-condensed>+ <thead>+ <tr>+ <th style="text-align:left;">+ Date+ <span .glyphicon.glyphicon-chevron-up>+ <th style="text-align:left;">Description+ <th style="text-align:left;">To/From Account(s)+ <th style="text-align:right; white-space:normal;">Amount Out/In+ <th style="text-align:right; white-space:normal;">+ #{balancelabel'}++ <tbody>+ $forall (torig, tacct, split, acct, amt, bal) <- items+ <tr ##{tindex torig} title="#{show torig}" style="vertical-align:top;">+ <td .date>+ <a href="@{JournalR}#transaction-#{tindex torig}">+ #{show (tdate tacct)}+ <td title="#{show torig}">+ #{textElideRight 30 (tdescription tacct)}+ <td .account>+ #{elideRight 40 acct}+ <td .amount style="text-align:right; white-space:nowrap;">+ $if not split || not (isZeroMixedAmount amt)+ ^{mixedAmountAsHtml amt}+ <td style="text-align:right;">+ ^{mixedAmountAsHtml bal}++$if elem CapAdd caps+ ^{addModal AddR j today}
+ templates/upload-form.hamlet view
@@ -0,0 +1,14 @@+<h2>+ Upload to file #+ <i>#{f}+<div.alert.alert-danger>+ Are you sure? This will overwrite your journal!+<div.form-group>+ <label .btn.btn-primary for="file">+ <input type=file id=file name=file style="display:none"+ onchange="\$('#file-info').html(this.files[0].name)" />+ Select file+ <span .label.label-info id="file-info">+<div.form-group>+ <input .btn.btn-default type=submit value="Upload">+#{extra}
− tests/HomeTest.hs
@@ -1,25 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module HomeTest- ( homeSpecs- ) where--import TestImport--homeSpecs :: Specs-homeSpecs =- ydescribe "Some hledger-web tests" $-- yit "serves a reasonable-looking register page" $ do- get RegisterR- statusIs 200- bodyContains "accounts"-- -- post "/" $ do- -- addNonce- -- fileByLabel "Choose a file" "tests/main.hs" "text/plain" -- talk about self-reference- -- byLabel "What's on the file?" "Some Content"-- -- statusIs 200- -- htmlCount ".message" 1- -- htmlAllContain ".message" "Some Content"- -- htmlAllContain ".message" "text/plain"
− tests/TestImport.hs
@@ -1,12 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module TestImport- ( module Yesod.Test- , module Foundation- , Specs- ) where--import Yesod.Test--import Foundation--type Specs = YesodSpec App
− tests/main.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Main where--import Import-import Yesod.Default.Config-import Yesod.Test-import Test.Hspec (hspec)-import Application (makeFoundation)-import Hledger.Web.WebOptions (defwebopts)--import HomeTest--main :: IO ()-main = do- conf <- Yesod.Default.Config.loadConfig $ (configSettings Testing)- { csParseExtra = parseExtra- }- foundation <- makeFoundation conf defwebopts- hspec $ do- yesodSpec foundation $ do- homeSpecs