hledger-web 1.31 → 1.32
raw patch · 20 files changed
+359/−324 lines, 20 filesdep +safedep ~hledgerdep ~hledger-libdep ~textPVP ok
version bump matches the API change (PVP)
Dependencies added: safe
Dependency ranges changed: hledger, hledger-lib, text, yesod
API changes (from Hackage documentation)
- 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: [opts] :: ViewData -> WebOpts
- Hledger.Web.Foundation: [q] :: ViewData -> Query
- Hledger.Web.Foundation: [qopts] :: ViewData -> [QueryOpt]
- Hledger.Web.Foundation: [qparam] :: ViewData -> Text
- Hledger.Web.Foundation: [settings] :: App -> AppConfig DefaultEnv Extra
- Hledger.Web.Foundation: [today] :: ViewData -> Day
- Hledger.Web.Foundation: checkServerSideUiEnabled :: Handler ()
- 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 a = Html -> MForm Handler (FormResult a, 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.AddR: putAddR :: Handler RepJson
- Hledger.Web.Handler.EditR: getEditR :: FilePath -> Handler ()
- Hledger.Web.Handler.EditR: postEditR :: FilePath -> Handler ()
- Hledger.Web.Handler.JournalR: getJournalR :: Handler Html
- Hledger.Web.Handler.MiscR: getAccountnamesR :: Handler TypedContent
- Hledger.Web.Handler.MiscR: getAccountsR :: Handler TypedContent
- Hledger.Web.Handler.MiscR: getAccounttransactionsR :: Text -> Handler TypedContent
- Hledger.Web.Handler.MiscR: getCommoditiesR :: Handler TypedContent
- Hledger.Web.Handler.MiscR: getDownloadR :: FilePath -> Handler TypedContent
- Hledger.Web.Handler.MiscR: getFaviconR :: MonadHandler m => m ()
- Hledger.Web.Handler.MiscR: getManageR :: Handler Html
- Hledger.Web.Handler.MiscR: getPricesR :: Handler TypedContent
- Hledger.Web.Handler.MiscR: getRobotsR :: MonadHandler m => m ()
- Hledger.Web.Handler.MiscR: getRootR :: Handler Html
- Hledger.Web.Handler.MiscR: getTransactionsR :: Handler TypedContent
- Hledger.Web.Handler.MiscR: getVersionR :: Handler TypedContent
- Hledger.Web.Handler.RegisterR: dayToJsTimestamp :: Day -> Integer
- Hledger.Web.Handler.RegisterR: decorateLinks :: [(acct, ([char], [char]))] -> [(Maybe acct, char)]
- Hledger.Web.Handler.RegisterR: elideRightDecorated :: Int -> [(Maybe d, Char)] -> [(Maybe d, Char)]
- Hledger.Web.Handler.RegisterR: getRegisterR :: Handler Html
- Hledger.Web.Handler.RegisterR: otherTransactionAccounts :: Query -> Query -> Transaction -> [Posting]
- Hledger.Web.Handler.RegisterR: preferReal :: [Posting] -> [Posting]
- Hledger.Web.Handler.RegisterR: registerChartHtml :: Text -> String -> [(CommoditySymbol, [AccountTransactionsReportItem])] -> HtmlUrl AppRoute
- Hledger.Web.Handler.RegisterR: undecorateLinks :: [(Maybe acct, char)] -> [(acct, ([char], [char]))]
- Hledger.Web.Handler.UploadR: getUploadR :: FilePath -> Handler ()
- Hledger.Web.Handler.UploadR: postUploadR :: FilePath -> Handler ()
- Hledger.Web.Import: CapAdd :: Capability
- Hledger.Web.Import: CapManage :: Capability
- Hledger.Web.Import: CapView :: Capability
- Hledger.Web.Import: [caps] :: ViewData -> [Capability]
- Hledger.Web.Import: data Capability
- 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 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 :: Journal -> Day -> Markup -> MForm Handler (FormResult (Transaction, FilePath), Widget)
- Hledger.Web.Widget.AddForm: addModal :: Route App -> Journal -> Day -> Widget
- 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 -> Text -> [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: removeDates :: Text -> [Text]
- Hledger.Web.Widget.Common: removeInacct :: Text -> [Text]
- Hledger.Web.Widget.Common: replaceInacct :: Text -> Text -> Text
- Hledger.Web.Widget.Common: transactionFragment :: Journal -> Transaction -> String
- Hledger.Web.Widget.Common: writeJournalTextIfValidAndChanged :: MonadHandler m => FilePath -> Text -> ExceptT String m ()
+ Hledger.Web.Import: AddPermission :: Permission
+ Hledger.Web.Import: EditPermission :: Permission
+ Hledger.Web.Import: MsgInvalidDatetimeFormat :: Text -> FormMessage
+ Hledger.Web.Import: ViewPermission :: Permission
+ Hledger.Web.Import: [perms] :: ViewData -> [Permission]
+ Hledger.Web.Import: data Permission
+ Hledger.Web.Import: data RouteOpts
+ Hledger.Web.Import: datetimeLocalField :: forall (m :: Type -> Type). (Monad m, RenderMessage (HandlerSite m) FormMessage) => Field m LocalTime
+ Hledger.Web.Import: defaultOpts :: RouteOpts
+ Hledger.Web.Import: mkYesodDataOpts :: RouteOpts -> String -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: mkYesodDispatchOpts :: RouteOpts -> String -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: mkYesodOpts :: RouteOpts -> String -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: mkYesodSubDataOpts :: RouteOpts -> String -> [ResourceTree String] -> Q [Dec]
+ Hledger.Web.Import: omitField :: ToJSON a => a -> Bool
+ Hledger.Web.Import: omittedField :: FromJSON a => Maybe a
+ Hledger.Web.Import: require :: Permission -> Handler ()
+ Hledger.Web.Import: setEqDerived :: Bool -> RouteOpts -> RouteOpts
+ Hledger.Web.Import: setReadDerived :: Bool -> RouteOpts -> RouteOpts
+ Hledger.Web.Import: setShowDerived :: Bool -> RouteOpts -> RouteOpts
+ Hledger.Web.WebOptions: AddAccess :: AccessLevel
+ Hledger.Web.WebOptions: AddPermission :: Permission
+ Hledger.Web.WebOptions: EditAccess :: AccessLevel
+ Hledger.Web.WebOptions: EditPermission :: Permission
+ Hledger.Web.WebOptions: SandstormAccess :: AccessLevel
+ Hledger.Web.WebOptions: ViewAccess :: AccessLevel
+ Hledger.Web.WebOptions: ViewPermission :: Permission
+ Hledger.Web.WebOptions: [allow_] :: WebOpts -> !AccessLevel
+ Hledger.Web.WebOptions: accessLevelToPermissions :: AccessLevel -> [Permission]
+ Hledger.Web.WebOptions: data AccessLevel
+ Hledger.Web.WebOptions: data Permission
+ Hledger.Web.WebOptions: instance GHC.Classes.Eq Hledger.Web.WebOptions.AccessLevel
+ Hledger.Web.WebOptions: instance GHC.Classes.Eq Hledger.Web.WebOptions.Permission
+ Hledger.Web.WebOptions: instance GHC.Classes.Ord Hledger.Web.WebOptions.AccessLevel
+ Hledger.Web.WebOptions: instance GHC.Classes.Ord Hledger.Web.WebOptions.Permission
+ Hledger.Web.WebOptions: instance GHC.Enum.Bounded Hledger.Web.WebOptions.AccessLevel
+ Hledger.Web.WebOptions: instance GHC.Enum.Bounded Hledger.Web.WebOptions.Permission
+ Hledger.Web.WebOptions: instance GHC.Enum.Enum Hledger.Web.WebOptions.AccessLevel
+ Hledger.Web.WebOptions: instance GHC.Enum.Enum Hledger.Web.WebOptions.Permission
+ Hledger.Web.WebOptions: instance GHC.Show.Show Hledger.Web.WebOptions.AccessLevel
+ Hledger.Web.WebOptions: instance GHC.Show.Show Hledger.Web.WebOptions.Permission
+ Hledger.Web.WebOptions: parseAccessLevel :: String -> Either String AccessLevel
+ Hledger.Web.WebOptions: parsePermission :: ByteString -> Either Text Permission
+ Hledger.Web.WebOptions: showPermission :: Permission -> String
- Hledger.Web.Import: (.=) :: (KeyValue kv, ToJSON v) => Key -> v -> kv
+ Hledger.Web.Import: (.=) :: (KeyValue e kv, ToJSON v) => Key -> v -> kv
- Hledger.Web.Import: VD :: WebOpts -> Day -> Journal -> Text -> Query -> [QueryOpt] -> [Capability] -> ViewData
+ Hledger.Web.Import: VD :: WebOpts -> Day -> Journal -> Text -> Query -> [QueryOpt] -> [Permission] -> ViewData
- Hledger.Web.WebOptions: WebOpts :: Bool -> Bool -> Maybe String -> String -> Int -> String -> Maybe String -> [Capability] -> Maybe (CI ByteString) -> CliOpts -> Maybe String -> WebOpts
+ Hledger.Web.WebOptions: WebOpts :: !Bool -> !Bool -> !Maybe String -> !String -> !Int -> !String -> !Maybe String -> !AccessLevel -> !CliOpts -> !Maybe String -> WebOpts
- Hledger.Web.WebOptions: [base_url_] :: WebOpts -> String
+ Hledger.Web.WebOptions: [base_url_] :: WebOpts -> !String
- Hledger.Web.WebOptions: [cliopts_] :: WebOpts -> CliOpts
+ Hledger.Web.WebOptions: [cliopts_] :: WebOpts -> !CliOpts
- Hledger.Web.WebOptions: [cors_] :: WebOpts -> Maybe String
+ Hledger.Web.WebOptions: [cors_] :: WebOpts -> !Maybe String
- Hledger.Web.WebOptions: [file_url_] :: WebOpts -> Maybe String
+ Hledger.Web.WebOptions: [file_url_] :: WebOpts -> !Maybe String
- Hledger.Web.WebOptions: [host_] :: WebOpts -> String
+ Hledger.Web.WebOptions: [host_] :: WebOpts -> !String
- Hledger.Web.WebOptions: [port_] :: WebOpts -> Int
+ Hledger.Web.WebOptions: [port_] :: WebOpts -> !Int
- Hledger.Web.WebOptions: [serve_] :: WebOpts -> Bool
+ Hledger.Web.WebOptions: [serve_] :: WebOpts -> !Bool
- Hledger.Web.WebOptions: [serve_api_] :: WebOpts -> Bool
+ Hledger.Web.WebOptions: [serve_api_] :: WebOpts -> !Bool
- Hledger.Web.WebOptions: [socket_] :: WebOpts -> Maybe String
+ Hledger.Web.WebOptions: [socket_] :: WebOpts -> !Maybe String
Files
- CHANGES.md +31/−0
- Hledger/Web.hs +16/−5
- Hledger/Web/Foundation.hs +24/−12
- Hledger/Web/Handler/AddR.hs +4/−4
- Hledger/Web/Handler/EditR.hs +2/−2
- Hledger/Web/Handler/JournalR.hs +5/−3
- Hledger/Web/Handler/MiscR.hs +28/−28
- Hledger/Web/Handler/RegisterR.hs +5/−3
- Hledger/Web/Handler/UploadR.hs +2/−2
- Hledger/Web/Import.hs +1/−1
- Hledger/Web/Settings.hs +5/−2
- Hledger/Web/WebOptions.hs +63/−50
- hledger-web.1 +117/−145
- hledger-web.cabal +16/−21
- hledger-web.info +27/−30
- hledger-web.txt +6/−9
- templates/default-layout.hamlet +3/−3
- templates/edit-form.hamlet +1/−1
- templates/journal.hamlet +2/−2
- templates/register.hamlet +1/−1
CHANGES.md view
@@ -21,6 +21,37 @@ User-visible changes in hledger-web. See also the hledger changelog. +# 1.32 2023-12-01++Features++- The hledger-web app on the Sandstorm cloud platform has been updated to+ a recent version (Jacob Weisz, #2102), and now uses Sandstorm's access+ control. (Jakub Zárybnický, #821)++Improvements++- The --capabilities and --capabilities-header options have been replaced+ with an easier `--allow=view|add|edit|sandstorm` option.+ `add` is the default access level, while `sandstorm` is for use on Sandstorm.+ UI and docs now speak of "permissions" rather than "capabilities".+ (#834)++- The Sandstorm app's permissions and roles have been renamed for clarity. (#834)++- Permissions are now checked earlier, before the web app is started,+ producing clearer command line errors when appropriate.++- Account's `adeclarationinfo` field is now included in JSON output. (#2097) (S. Zeid)++Fixes++- The app can now serve on address 0.0.0.0 (exposing it on all interfaces),+ which previously didn't work.+ (#2099) (Philipp Klocke)++- The broken "File format help" link in the edit form has been fixed. (#2103)+ # 1.31 2023-09-03 Improvements
Hledger/Web.hs view
@@ -1,11 +1,22 @@ {-|-Re-export the modules of the hledger-web program.++This is the root module of the @hledger-web@ package,+providing hledger's web user interface and JSON API.+The main function and command-line options are exported.++== See also:++- hledger-lib:Hledger+- hledger:Hledger.Cli+- [The README files](https://github.com/search?q=repo%3Asimonmichael%2Fhledger+path%3A**%2FREADME*&type=code&ref=advsearch)+- [The high-level developer docs](https://hledger.org/dev.html)+ -} -module Hledger.Web- ( module Hledger.Web.WebOptions- , module Hledger.Web.Main- ) where+module Hledger.Web (+ module Hledger.Web.Main,+ module Hledger.Web.WebOptions+) where import Hledger.Web.WebOptions import Hledger.Web.Main
Hledger/Web/Foundation.hs view
@@ -16,7 +16,7 @@ module Hledger.Web.Foundation where import Control.Applicative ((<|>))-import Control.Monad (join, when)+import Control.Monad (join, when, unless) -- import Control.Monad.Except (runExceptT) -- now re-exported by Hledger import qualified Data.ByteString.Char8 as BC import Data.Traversable (for)@@ -96,7 +96,7 @@ -- 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+ approot = guessApprootOr (ApprootMaster $ appRoot . settings) makeSessionBackend _ = do hledgerdata <- getXdgDirectory XdgCache "hledger"@@ -114,7 +114,7 @@ master <- getYesod here <- fromMaybe RootR <$> getCurrentRoute- VD{opts, j, qparam, q, qopts, caps} <- getViewData+ VD{opts, j, qparam, q, qopts, perms} <- getViewData msg <- getMessage showSidebar <- shouldShowSidebar @@ -132,6 +132,7 @@ let accounts = balanceReportAsHtml (JournalR, RegisterR) here hideEmptyAccts j qparam qopts $+ styleAmounts (journalCommodityStylesWith HardRounding j) $ balanceReport rspec' j topShowmd = if showSidebar then "col-md-4" else "col-any-0" :: Text@@ -198,7 +199,7 @@ , qparam :: Text -- ^ the current "q" request parameter , q :: Query -- ^ a query parsed from the q parameter , qopts :: [QueryOpt] -- ^ query options parsed from the q parameter- , caps :: [Capability] -- ^ capabilities enabled for this request+ , perms :: [Permission] -- ^ permissions enabled for this request (by --allow and/or X-Sandstorm-Permissions) } deriving (Show) instance Show Text.Blaze.Markup where show _ = "<blaze markup>"@@ -233,16 +234,19 @@ -- if either of the above gave an error, display it maybe (pure ()) (setMessage . toHtml) $ mjerr <|> mqerr - -- do some permissions checking- caps <- case capabilitiesHeader_ opts of- Nothing -> return (capabilities_ opts)- Just h -> do+ -- find out which permissions are enabled+ perms <- case allow_ opts of+ -- if started with --allow=sandstorm, take permissions from X-Sandstorm-Permissions header+ SandstormAccess -> do+ let h = "X-Sandstorm-Permissions" 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]+ fmap join . for (join hs) $ \x -> case parsePermission x of+ Left e -> [] <$ addMessage "" ("Unknown permission: " <> toHtml e)+ Right p -> pure [p]+ -- otherwise take them from the access level specified by --allow's access level+ cliaccess -> pure $ accessLevelToPermissions cliaccess - return VD{opts, today, j, qparam, q, qopts, caps}+ return VD{opts, today, j, qparam, q, qopts, perms} checkServerSideUiEnabled :: Handler () checkServerSideUiEnabled = do@@ -280,3 +284,11 @@ liftIO . writeIORef jref $ filterJournalTransactions depthlessinitialq j' return (j',Nothing) Right (_, False) -> return (j, Nothing)++-- | In a request handler, check for the given permission+-- and fail with a message if it's not present.+require :: Permission -> Handler ()+require p = do+ VD{perms} <- getViewData+ unless (p `elem` perms) $ permissionDenied $+ "Missing the '" <> T.pack (showPermission p) <> "' permission"
Hledger/Web/Handler/AddR.hs view
@@ -30,8 +30,8 @@ postAddR :: Handler () postAddR = do checkServerSideUiEnabled- VD{caps, j, today} <- getViewData- when (CapAdd `notElem` caps) (permissionDenied "Missing the 'add' capability")+ VD{j, today} <- getViewData+ require AddPermission ((res, view), enctype) <- runFormPost $ addForm j today case res of@@ -59,8 +59,8 @@ -- The web form handler above should probably use PUT as well. putAddR :: Handler RepJson putAddR = do- VD{caps, j, opts} <- getViewData- when (CapAdd `notElem` caps) (permissionDenied "Missing the 'add' capability")+ VD{j, opts} <- getViewData+ require AddPermission (r :: Result Transaction) <- parseCheckJsonBody case r of
Hledger/Web/Handler/EditR.hs view
@@ -31,8 +31,8 @@ postEditR :: FilePath -> Handler () postEditR f = do checkServerSideUiEnabled- VD {caps, j} <- getViewData- when (CapManage `notElem` caps) (permissionDenied "Missing the 'manage' capability")+ VD {j} <- getViewData+ require EditPermission (f', txt) <- journalFile404 f j ((res, view), enctype) <- runFormPost (editForm f' txt)
Hledger/Web/Handler/JournalR.hs view
@@ -20,15 +20,17 @@ getJournalR :: Handler Html getJournalR = do checkServerSideUiEnabled- VD{caps, j, q, opts, qparam, qopts, today} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")+ VD{perms, j, q, opts, qparam, qopts, today} <- getViewData+ require ViewPermission let title = case inAccount qopts of Nothing -> "General Journal" Just (a, inclsubs) -> "Transactions in " <> a <> if inclsubs then "" else " (excluding subaccounts)" title' = title <> if q /= Any then ", filtered" else "" acctlink a = (RegisterR, [("q", replaceInacct qparam $ accountQuery a)]) rspec = (reportspec_ $ cliopts_ opts){_rsQuery = filterQuery (not . queryIsDepth) q}- items = reverse $ entriesReport rspec j+ items = reverse $+ styleAmounts (journalCommodityStylesWith HardRounding j) $+ entriesReport rspec j transactionFrag = transactionFragment j defaultLayout $ do
Hledger/Web/Handler/MiscR.hs view
@@ -38,17 +38,17 @@ getManageR :: Handler Html getManageR = do checkServerSideUiEnabled- VD{caps, j} <- getViewData- when (CapManage `notElem` caps) (permissionDenied "Missing the 'manage' capability")+ VD{j} <- getViewData+ require EditPermission defaultLayout $ do- setTitle "Manage journal"+ setTitle "Edit journal" $(widgetFile "manage") getDownloadR :: FilePath -> Handler TypedContent getDownloadR f = do checkServerSideUiEnabled- VD{caps, j} <- getViewData- when (CapManage `notElem` caps) (permissionDenied "Missing the 'manage' capability")+ VD{j} <- getViewData+ require EditPermission (f', txt) <- journalFile404 f j addHeader "Content-Disposition" ("attachment; filename=\"" <> T.pack f' <> "\"") sendResponse ("text/plain" :: ByteString, toContent txt)@@ -57,53 +57,53 @@ getVersionR :: Handler TypedContent getVersionR = do- VD{caps} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")- selectRep $ do- provideJson $ packageversion+ require ViewPermission+ selectRep $ provideJson $ packageversion getAccountnamesR :: Handler TypedContent getAccountnamesR = do- VD{caps, j} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")- selectRep $ do- provideJson $ journalAccountNames j+ VD{j} <- getViewData+ require ViewPermission+ selectRep $ provideJson $ journalAccountNames j getTransactionsR :: Handler TypedContent getTransactionsR = do- VD{caps, j} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")- selectRep $ do- provideJson $ jtxns j+ VD{j} <- getViewData+ require ViewPermission+ selectRep $ provideJson $ jtxns j getPricesR :: Handler TypedContent getPricesR = do- VD{caps, j} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")- selectRep $ do+ VD{j} <- getViewData+ require ViewPermission+ selectRep $ provideJson $ map priceDirectiveToMarketPrice $ jpricedirectives j getCommoditiesR :: Handler TypedContent getCommoditiesR = do- VD{caps, j} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")+ VD{j} <- getViewData+ require ViewPermission selectRep $ do provideJson $ (M.keys . jinferredcommodities) j getAccountsR :: Handler TypedContent getAccountsR = do- VD{caps, j} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")+ VD{j} <- getViewData+ require ViewPermission selectRep $ do- provideJson $ laccounts $ ledgerFromJournal Any j+ provideJson $+ styleAmounts (journalCommodityStylesWith HardRounding j) $+ flattenAccounts $ mapAccounts (accountSetDeclarationInfo j) $ ledgerRootAccount $ ledgerFromJournal Any j getAccounttransactionsR :: Text -> Handler TypedContent getAccounttransactionsR a = do- VD{caps, j} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")+ VD{j} <- getViewData+ require ViewPermission let rspec = defreportspec thisacctq = Acct $ accountNameToAccountRegex a -- includes subs selectRep $ do- provideJson $ accountTransactionsReport rspec{_rsQuery=Any} j thisacctq+ provideJson $+ styleAmounts (journalCommodityStylesWith HardRounding j) $+ accountTransactionsReport rspec{_rsQuery=Any} j thisacctq
Hledger/Web/Handler/RegisterR.hs view
@@ -26,8 +26,8 @@ getRegisterR :: Handler Html getRegisterR = do checkServerSideUiEnabled- VD{caps, j, q, opts, qparam, qopts, today} <- getViewData- when (CapView `notElem` caps) (permissionDenied "Missing the 'view' capability")+ VD{perms, j, q, opts, qparam, qopts, today} <- getViewData+ require ViewPermission let (a,inclsubs) = fromMaybe ("all accounts",True) $ inAccount qopts s1 = if inclsubs then "" else " (excluding subaccounts)"@@ -45,7 +45,9 @@ zip xs $ zip (map (T.unpack . accountSummarisedName . paccount) xs) $ tail $ (", "<$xs) ++ [""]- items = accountTransactionsReport rspec{_rsQuery=q} j acctQuery+ items =+ styleAmounts (journalCommodityStylesWith HardRounding j) $+ accountTransactionsReport rspec{_rsQuery=q} j acctQuery balancelabel | isJust (inAccount qopts), balanceaccum_ (_rsReportOpts rspec) == Historical = "Historical Total" | isJust (inAccount qopts) = "Period Total"
Hledger/Web/Handler/UploadR.hs view
@@ -35,8 +35,8 @@ postUploadR :: FilePath -> Handler () postUploadR f = do checkServerSideUiEnabled- VD {caps, j} <- getViewData- when (CapManage `notElem` caps) (permissionDenied "Missing the 'manage' capability")+ VD {j} <- getViewData+ require EditPermission (f', _) <- journalFile404 f j ((res, view), enctype) <- runFormPost (uploadForm f')
Hledger/Web/Import.hs view
@@ -23,4 +23,4 @@ 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(..))+import Hledger.Web.WebOptions as Import (Permission(..))
Hledger/Web/Settings.hs view
@@ -12,6 +12,7 @@ import Data.Default (def) import Data.Maybe (fromMaybe) import Data.Text (Text)+import qualified Data.Text as T import Data.Yaml import Language.Haskell.TH.Syntax (Q, Exp) import Text.Hamlet@@ -19,6 +20,8 @@ import Yesod.Default.Config import Yesod.Default.Util +import Hledger.Cli.Version (packagemajorversion)+ development :: Bool development = #if DEVELOPMENT@@ -31,10 +34,10 @@ production = not development hledgerorgurl :: Text-hledgerorgurl = "http://hledger.org"+hledgerorgurl = "https://hledger.org" manualurl :: Text-manualurl = hledgerorgurl <> "hledger.html"+manualurl = hledgerorgurl <> "/" <> T.pack packagemajorversion <> "/hledger.html" -- | The default IP address to listen on. May be overridden with --host. defhost :: String
Hledger/Web/WebOptions.hs view
@@ -6,17 +6,18 @@ import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as BC import Data.ByteString.UTF8 (fromString)-import Data.CaseInsensitive (CI, mk) import Data.Default (Default(def)) import Data.Maybe (fromMaybe)-import qualified Data.Text as T import Data.Text (Text) import System.Environment (getArgs) import Network.Wai as WAI import Network.Wai.Middleware.Cors+import Safe (lastMay) import Hledger.Cli hiding (packageversion, progname, prognameandversion) import Hledger.Web.Settings (defhost, defport, defbaseurl)+import qualified Data.Text as T+import Data.Char (toLower) -- cf Hledger.Cli.Version @@ -46,6 +47,11 @@ (setboolopt "serve-api") "like --serve, but serve only the JSON web API, without the server-side web UI" , flagReq+ ["allow"]+ (\s opts -> Right $ setopt "allow" s opts)+ "view|add|edit"+ "set the user's access level for changing data (default: `add`). It also accepts `sandstorm` for use on that platform (reads permissions from the `X-Sandstorm-Permissions` request header)."+ , flagReq ["cors"] (\s opts -> Right $ setopt "cors" s opts) "ORIGIN"@@ -75,16 +81,6 @@ (\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[,CAP..]"- "enable the view, add, and/or manage capabilities (default: view,add)"- , flagReq- ["capabilities-header"]- (\s opts -> Right $ setopt "capabilities-header" s opts)- "HTTPHEADER"- "read capabilities to enable from a HTTP header, like X-Sandstorm-Permissions (default: disabled)" , flagNone ["test"] (setboolopt "test")@@ -117,17 +113,16 @@ -- hledger-web options, used in hledger-web and above data WebOpts = WebOpts- { serve_ :: Bool- , serve_api_ :: Bool- , cors_ :: Maybe String- , host_ :: String- , port_ :: Int- , base_url_ :: String- , file_url_ :: Maybe String- , capabilities_ :: [Capability]- , capabilitiesHeader_ :: Maybe (CI ByteString)- , cliopts_ :: CliOpts- , socket_ :: Maybe String+ { serve_ :: !Bool+ , serve_api_ :: !Bool+ , cors_ :: !(Maybe String)+ , host_ :: !String+ , port_ :: !Int+ , base_url_ :: !String+ , file_url_ :: !(Maybe String)+ , allow_ :: !AccessLevel+ , cliopts_ :: !CliOpts+ , socket_ :: !(Maybe String) } deriving (Show) defwebopts :: WebOpts@@ -139,8 +134,7 @@ , port_ = def , base_url_ = "" , file_url_ = Nothing- , capabilities_ = [CapView, CapAdd]- , capabilitiesHeader_ = Nothing+ , allow_ = AddAccess , cliopts_ = def , socket_ = Nothing }@@ -153,15 +147,15 @@ cliopts <- rawOptsToCliOpts rawopts let h = fromMaybe defhost $ maybestringopt "host" rawopts p = fromMaybe defport $ maybeposintopt "port" rawopts- b =- maybe (defbaseurl h p) stripTrailingSlash $- maybestringopt "base-url" rawopts- caps' = T.splitOn "," . T.pack =<< listofstringopt "capabilities" rawopts- caps = case traverse capabilityFromText caps' of- Left e -> error' ("Unknown capability: " ++ T.unpack e) -- PARTIAL:- Right [] -> [CapView, CapAdd]- Right xs -> xs+ b = maybe (defbaseurl h p) stripTrailingSlash $ maybestringopt "base-url" rawopts sock = stripTrailingSlash <$> maybestringopt "socket" rawopts+ access =+ case lastMay $ listofstringopt "allow" rawopts of+ Nothing -> AddAccess+ Just t ->+ case parseAccessLevel t of+ Right al -> al+ Left err -> error' ("Unknown access level: " ++ err) -- PARTIAL: return defwebopts { serve_ = case sock of@@ -173,8 +167,7 @@ , port_ = p , base_url_ = b , file_url_ = stripTrailingSlash <$> maybestringopt "file-url" rawopts- , capabilities_ = caps- , capabilitiesHeader_ = mk . BC.pack <$> maybestringopt "capabilities-header" rawopts+ , allow_ = access , cliopts_ = cliopts , socket_ = sock }@@ -189,28 +182,48 @@ args <- fmap (replaceNumericFlags . ensureDebugHasArg) . expandArgsAt =<< getArgs rawOptsToWebOpts . either usageError id $ process webmode args -data Capability- = CapView- | CapAdd- | CapManage+data Permission+ = ViewPermission -- ^ allow viewing things (read only)+ | AddPermission -- ^ allow adding transactions, or more generally allow appending text to input files + | EditPermission -- ^ allow editing input files 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+parsePermission :: ByteString -> Either Text Permission+parsePermission "view" = Right ViewPermission+parsePermission "add" = Right AddPermission+parsePermission "edit" = Right EditPermission+parsePermission x = Left $ T.pack $ BC.unpack x -capabilityFromBS :: ByteString -> Either ByteString Capability-capabilityFromBS "view" = Right CapView-capabilityFromBS "add" = Right CapAdd-capabilityFromBS "manage" = Right CapManage-capabilityFromBS x = Left x+-- | Convert to the lower case permission name.+showPermission :: Permission -> String+showPermission p = map toLower $ reverse $ drop 10 $ reverse $ show p +-- | For the --allow option: how much access to allow to hledger-web users ?+data AccessLevel =+ ViewAccess -- ^ view permission only+ | AddAccess -- ^ view and add permissions+ | EditAccess -- ^ view, add and edit permissions+ | SandstormAccess -- ^ the permissions specified by the X-Sandstorm-Permissions HTTP request header+ deriving (Eq, Ord, Bounded, Enum, Show)++parseAccessLevel :: String -> Either String AccessLevel+parseAccessLevel "view" = Right ViewAccess+parseAccessLevel "add" = Right AddAccess+parseAccessLevel "edit" = Right EditAccess+parseAccessLevel "sandstorm" = Right SandstormAccess+parseAccessLevel s = Left $ s <> ", should be one of: view, add, edit, sandstorm"++-- | Convert an --allow access level to the permissions used internally.+-- SandstormAccess generates an empty list, to be filled in later.+accessLevelToPermissions :: AccessLevel -> [Permission]+accessLevelToPermissions ViewAccess = [ViewPermission]+accessLevelToPermissions AddAccess = [ViewPermission, AddPermission]+accessLevelToPermissions EditAccess = [ViewPermission, AddPermission, EditPermission]+accessLevelToPermissions SandstormAccess = [] -- detected from request header+ simplePolicyWithOrigin :: Origin -> CorsResourcePolicy simplePolicyWithOrigin origin = simpleCorsResourcePolicy { corsOrigins = Just ([origin], False) }- corsPolicyFromString :: String -> WAI.Middleware corsPolicyFromString origin =
hledger-web.1 view
@@ -1,21 +1,18 @@ -.TH "HLEDGER-WEB" "1" "September 2023" "hledger-web-1.31 " "hledger User Manuals"+.TH "HLEDGER-WEB" "1" "December 2023" "hledger-web-1.32 " "hledger User Manuals" .SH NAME-.PP hledger-web - robust, friendly plain text accounting (Web version) .SH SYNOPSIS-.PP-\f[V]hledger-web [--serve|--serve-api] [OPTS] [ARGS]\f[R]+\f[CR]hledger-web [--serve|--serve-api] [OPTS] [ARGS]\f[R] .PD 0 .P .PD-\f[V]hledger web -- [--serve|--serve-api] [OPTS] [ARGS]\f[R]+\f[CR]hledger web -- [--serve|--serve-api] [OPTS] [ARGS]\f[R] .SH DESCRIPTION-.PP-This manual is for hledger\[aq]s web interface, version 1.31.+This manual is for hledger\[aq]s web interface, version 1.32. See also the hledger manual for common concepts and file formats. .PP hledger is a robust, user-friendly, cross-platform set of programs for@@ -40,9 +37,9 @@ every edit. .PP Like hledger, it reads from (and appends to) a journal file specified by-the \f[V]LEDGER_FILE\f[R] environment variable (defaulting to-\f[V]$HOME/.hledger.journal\f[R]); or you can specify files with-\f[V]-f\f[R] options.+the \f[CR]LEDGER_FILE\f[R] environment variable (defaulting to+\f[CR]$HOME/.hledger.journal\f[R]); or you can specify files with+\f[CR]-f\f[R] options. It can also read timeclock files, timedot files, or any CSV/SSV/TSV file with a date field. (See hledger(1) -> Input for details.)@@ -54,15 +51,14 @@ minutes of inactivity (no requests received and no open browser windows viewing it). .IP \[bu] 2-With \f[V]--serve\f[R]: the app runs without stopping, and without+With \f[CR]--serve\f[R]: the app runs without stopping, and without opening a browser. .IP \[bu] 2-With \f[V]--serve-api\f[R]: only the JSON API is served.+With \f[CR]--serve-api\f[R]: only the JSON API is served. .PP In all cases hledger-web runs as a foreground process, logging requests to stdout. .SH OPTIONS-.PP Command-line options and arguments may be used to set an initial filter on the data. These filter options are not shown in the web UI, but it will be applied@@ -70,85 +66,82 @@ .PP hledger-web provides the following options: .TP-\f[V]--serve\f[R]+\f[CR]--serve\f[R] serve and log requests, don\[aq]t browse or auto-exit after timeout .TP-\f[V]--serve-api\f[R]+\f[CR]--serve-api\f[R] like --serve, but serve only the JSON web API, without the server-side web UI .TP-\f[V]--host=IPADDR\f[R]+\f[CR]--host=IPADDR\f[R] listen on this IP address (default: 127.0.0.1) .TP-\f[V]--port=PORT\f[R]+\f[CR]--port=PORT\f[R] listen on this TCP port (default: 5000) .TP-\f[V]--socket=SOCKETFILE\f[R]+\f[CR]--socket=SOCKETFILE\f[R] use a unix domain socket file to listen for requests instead of a TCP socket.-Implies \f[V]--serve\f[R].+Implies \f[CR]--serve\f[R]. It can only be used if the operating system can provide this type of socket. .TP-\f[V]--base-url=URL\f[R]+\f[CR]--base-url=URL\f[R] set the base url (default: http://IPADDR:PORT). Note: affects url generation but not route parsing. Can be useful if running behind a reverse web proxy that does path rewriting. .TP-\f[V]--file-url=URL\f[R]+\f[CR]--file-url=URL\f[R] set the static files url (default: BASEURL/static). hledger-web normally serves static files itself, but if you wanted to serve them from another server for efficiency, you would set the url with this. .TP-\f[V]--capabilities=CAP[,CAP..]\f[R]-enable the view, add, and/or manage capabilities (default: view,add)-.TP-\f[V]--capabilities-header=HTTPHEADER\f[R]-read capabilities to enable from a HTTP header, like-X-Sandstorm-Permissions (default: disabled)+\f[CR]--allow=view|add|edit\f[R]+set the user\[aq]s access level for changing data (default:+\f[CR]add\f[R]).+It also accepts \f[CR]sandstorm\f[R] for use on that platform (reads+permissions from the \f[CR]X-Sandstorm-Permissions\f[R] request header). .TP-\f[V]--test\f[R]+\f[CR]--test\f[R] run hledger-web\[aq]s tests and exit. hspec test runner args may follow a --, eg: hledger-web --test -- --help .PP By default the server listens on IP address 127.0.0.1, accessible only to local requests.-You can use \f[V]--host\f[R] to change this, eg \f[V]--host 0.0.0.0\f[R]-to listen on all configured addresses.+You can use \f[CR]--host\f[R] to change this, eg+\f[CR]--host 0.0.0.0\f[R] to listen on all configured addresses. .PP-Similarly, use \f[V]--port\f[R] to set a TCP port other than 5000, eg if-you are running multiple hledger-web instances.+Similarly, use \f[CR]--port\f[R] to set a TCP port other than 5000, eg+if you are running multiple hledger-web instances. .PP-Both of these options are ignored when \f[V]--socket\f[R] is used.-In this case, it creates an \f[V]AF_UNIX\f[R] socket file at the+Both of these options are ignored when \f[CR]--socket\f[R] is used.+In this case, it creates an \f[CR]AF_UNIX\f[R] socket file at the supplied path and uses that for communication. This is an alternative way of running multiple hledger-web instances behind a reverse proxy that handles authentication for different users. The path can be derived in a predictable way, eg by using the username within the path.-As an example, \f[V]nginx\f[R] as reverse proxy can use the variable-\f[V]$remote_user\f[R] to derive a path from the username used in a HTTP-basic authentication.-The following \f[V]proxy_pass\f[R] directive allows access to all-\f[V]hledger-web\f[R] instances that created a socket in-\f[V]/tmp/hledger/\f[R]:+As an example, \f[CR]nginx\f[R] as reverse proxy can use the variable+\f[CR]$remote_user\f[R] to derive a path from the username used in a+HTTP basic authentication.+The following \f[CR]proxy_pass\f[R] directive allows access to all+\f[CR]hledger-web\f[R] instances that created a socket in+\f[CR]/tmp/hledger/\f[R]: .IP-.nf-\f[C]+.EX proxy_pass http://unix:/tmp/hledger/${remote_user}.socket;-\f[R]-.fi+.EE .PP-You can use \f[V]--base-url\f[R] to change the protocol, hostname, port+You can use \f[CR]--base-url\f[R] to change the protocol, hostname, port and path that appear in hyperlinks, useful eg for integrating hledger-web within a larger website.-The default is \f[V]http://HOST:PORT/\f[R] using the server\[aq]s-configured host address and TCP port (or \f[V]http://HOST\f[R] if PORT+The default is \f[CR]http://HOST:PORT/\f[R] using the server\[aq]s+configured host address and TCP port (or \f[CR]http://HOST\f[R] if PORT is 80). .PP-With \f[V]--file-url\f[R] you can set a different base url for static+With \f[CR]--file-url\f[R] you can set a different base url for static files, eg for better caching or cookie-less serving on high performance websites. .PP@@ -156,144 +149,144 @@ hledger manual\[aq]s command line tips also apply here): .SS General help options .TP-\f[V]-h --help\f[R]+\f[CR]-h --help\f[R] show general or COMMAND help .TP-\f[V]--man\f[R]+\f[CR]--man\f[R] show general or COMMAND user manual with man .TP-\f[V]--info\f[R]+\f[CR]--info\f[R] show general or COMMAND user manual with info .TP-\f[V]--version\f[R]+\f[CR]--version\f[R] show general or ADDONCMD version .TP-\f[V]--debug[=N]\f[R]+\f[CR]--debug[=N]\f[R] show debug output (levels 1-9, default: 1) .SS General input options .TP-\f[V]-f FILE --file=FILE\f[R]+\f[CR]-f FILE --file=FILE\f[R] use a different input file.-For stdin, use - (default: \f[V]$LEDGER_FILE\f[R] or-\f[V]$HOME/.hledger.journal\f[R])+For stdin, use - (default: \f[CR]$LEDGER_FILE\f[R] or+\f[CR]$HOME/.hledger.journal\f[R]) .TP-\f[V]--rules-file=RULESFILE\f[R]+\f[CR]--rules-file=RULESFILE\f[R] Conversion rules file to use when reading CSV (default: FILE.rules) .TP-\f[V]--separator=CHAR\f[R]+\f[CR]--separator=CHAR\f[R] Field separator to expect when reading CSV (default: \[aq],\[aq]) .TP-\f[V]--alias=OLD=NEW\f[R]+\f[CR]--alias=OLD=NEW\f[R] rename accounts named OLD to NEW .TP-\f[V]--anon\f[R]+\f[CR]--anon\f[R] anonymize accounts and payees .TP-\f[V]--pivot FIELDNAME\f[R]+\f[CR]--pivot FIELDNAME\f[R] use some other field or tag for the account name .TP-\f[V]-I --ignore-assertions\f[R]+\f[CR]-I --ignore-assertions\f[R] disable balance assertion checks (note: does not disable balance assignments) .TP-\f[V]-s --strict\f[R]+\f[CR]-s --strict\f[R] do extra error checking (check that all posted accounts are declared) .SS General reporting options .TP-\f[V]-b --begin=DATE\f[R]+\f[CR]-b --begin=DATE\f[R] include postings/txns on or after this date (will be adjusted to preceding subperiod start when using a report interval) .TP-\f[V]-e --end=DATE\f[R]+\f[CR]-e --end=DATE\f[R] include postings/txns before this date (will be adjusted to following subperiod end when using a report interval) .TP-\f[V]-D --daily\f[R]+\f[CR]-D --daily\f[R] multiperiod/multicolumn report by day .TP-\f[V]-W --weekly\f[R]+\f[CR]-W --weekly\f[R] multiperiod/multicolumn report by week .TP-\f[V]-M --monthly\f[R]+\f[CR]-M --monthly\f[R] multiperiod/multicolumn report by month .TP-\f[V]-Q --quarterly\f[R]+\f[CR]-Q --quarterly\f[R] multiperiod/multicolumn report by quarter .TP-\f[V]-Y --yearly\f[R]+\f[CR]-Y --yearly\f[R] multiperiod/multicolumn report by year .TP-\f[V]-p --period=PERIODEXP\f[R]+\f[CR]-p --period=PERIODEXP\f[R] set start date, end date, and/or reporting interval all at once using period expressions syntax .TP-\f[V]--date2\f[R]+\f[CR]--date2\f[R] match the secondary date instead (see command help for other effects) .TP-\f[V]--today=DATE\f[R]+\f[CR]--today=DATE\f[R] override today\[aq]s date (affects relative smart dates, for tests/examples) .TP-\f[V]-U --unmarked\f[R]+\f[CR]-U --unmarked\f[R] include only unmarked postings/txns (can combine with -P or -C) .TP-\f[V]-P --pending\f[R]+\f[CR]-P --pending\f[R] include only pending postings/txns .TP-\f[V]-C --cleared\f[R]+\f[CR]-C --cleared\f[R] include only cleared postings/txns .TP-\f[V]-R --real\f[R]+\f[CR]-R --real\f[R] include only non-virtual postings .TP-\f[V]-NUM --depth=NUM\f[R]+\f[CR]-NUM --depth=NUM\f[R] hide/aggregate accounts or postings more than NUM levels deep .TP-\f[V]-E --empty\f[R]+\f[CR]-E --empty\f[R] show items with zero amount, normally hidden (and vice-versa in hledger-ui/hledger-web) .TP-\f[V]-B --cost\f[R]+\f[CR]-B --cost\f[R] convert amounts to their cost/selling amount at transaction time .TP-\f[V]-V --market\f[R]+\f[CR]-V --market\f[R] convert amounts to their market value in default valuation commodities .TP-\f[V]-X --exchange=COMM\f[R]+\f[CR]-X --exchange=COMM\f[R] convert amounts to their market value in commodity COMM .TP-\f[V]--value\f[R]+\f[CR]--value\f[R] convert amounts to cost or market value, more flexibly than -B/-V/-X .TP-\f[V]--infer-equity\f[R]+\f[CR]--infer-equity\f[R] infer conversion equity postings from costs .TP-\f[V]--infer-costs\f[R]+\f[CR]--infer-costs\f[R] infer costs from conversion equity postings .TP-\f[V]--infer-market-prices\f[R]+\f[CR]--infer-market-prices\f[R] use costs as additional market prices, as if they were P directives .TP-\f[V]--forecast\f[R]+\f[CR]--forecast\f[R] generate transactions from periodic rules, between the latest recorded txn and 6 months from today, or during the specified PERIOD (= is required). Auto posting rules will be applied to these transactions as well. Also, in hledger-ui make future-dated transactions visible. .TP-\f[V]--auto\f[R]+\f[CR]--auto\f[R] generate extra postings by applying auto posting rules to all txns (not just forecast txns) .TP-\f[V]--verbose-tags\f[R]+\f[CR]--verbose-tags\f[R] add visible tags indicating transactions or postings which have been generated/modified .TP-\f[V]--commodity-style\f[R]+\f[CR]--commodity-style\f[R] Override the commodity style in the output for the specified commodity. For example \[aq]EUR1.000,00\[aq]. .TP-\f[V]--color=WHEN (or --colour=WHEN)\f[R]+\f[CR]--color=WHEN (or --colour=WHEN)\f[R] Should color-supporting commands use ANSI color codes in text output. \[aq]auto\[aq] (default): whenever stdout seems to be a color-supporting terminal.@@ -302,7 +295,7 @@ \[aq]never\[aq] or \[aq]no\[aq]: never. A NO_COLOR environment variable overrides this. .TP-\f[V]--pretty[=WHEN]\f[R]+\f[CR]--pretty[=WHEN]\f[R] Show prettier output, e.g. using unicode box-drawing characters. Accepts \[aq]yes\[aq] (the default) or \[aq]no\[aq] (\[aq]y\[aq],@@ -315,13 +308,12 @@ .PP Some reporting options can also be written as query arguments. .SH PERMISSIONS-.PP By default, hledger-web allows anyone who can reach it to view the journal and to add new transactions, but not to change existing data. .PP You can restrict who can reach it by .IP \[bu] 2-setting the IP address it listens on (see \f[V]--host\f[R] above).+setting the IP address it listens on (see \f[CR]--host\f[R] above). By default it listens on 127.0.0.1, accessible to all users on the local machine. .IP \[bu] 2@@ -331,27 +323,26 @@ .PP You can restrict what the users who reach it can do, by .IP \[bu] 2-using the \f[V]--capabilities=CAP[,CAP..]\f[R] flag when you start it,+using the \f[CR]--capabilities=CAP[,CAP..]\f[R] flag when you start it, enabling one or more of the following capabilities.-The default value is \f[V]view,add\f[R]:+The default value is \f[CR]view,add\f[R]: .RS 2 .IP \[bu] 2-\f[V]view\f[R] - allows viewing the journal file and all included files+\f[CR]view\f[R] - allows viewing the journal file and all included files .IP \[bu] 2-\f[V]add\f[R] - allows adding new transactions to the main journal file+\f[CR]add\f[R] - allows adding new transactions to the main journal file .IP \[bu] 2-\f[V]manage\f[R] - allows editing, uploading or downloading the main or+\f[CR]manage\f[R] - allows editing, uploading or downloading the main or included files .RE .IP \[bu] 2-using the \f[V]--capabilities-header=HTTPHEADER\f[R] flag to specify a+using the \f[CR]--capabilities-header=HTTPHEADER\f[R] flag to specify a HTTP header from which it will read capabilities to enable. hledger-web on Sandstorm uses the X-Sandstorm-Permissions header to integrate with Sandstorm\[aq]s permissions. This is disabled by default. .SH EDITING, UPLOADING, DOWNLOADING-.PP-If you enable the \f[V]manage\f[R] capability mentioned above,+If you enable the \f[CR]manage\f[R] capability mentioned above, you\[aq]ll see a new \[dq]spanner\[dq] button to the right of the search form. Clicking this will let you edit, upload, or download the journal file or@@ -372,7 +363,6 @@ (Probably. This needs re-testing.) .SH RELOADING-.PP hledger-web detects changes made to the files by other means (eg if you edit it directly, outside of hledger-web), and it will show the new data when you reload the page or navigate to a new page.@@ -382,24 +372,20 @@ (Note: if you are viewing files mounted from another machine, make sure that both machine clocks are roughly in step.) .SH JSON API-.PP In addition to the web UI, hledger-web also serves a JSON API that can be used to get data or add new transactions.-If you want the JSON API only, you can use the \f[V]--serve-api\f[R]+If you want the JSON API only, you can use the \f[CR]--serve-api\f[R] flag. Eg: .IP-.nf-\f[C]+.EX $ hledger-web -f examples/sample.journal --serve-api \&...-\f[R]-.fi+.EE .PP You can get JSON data from these routes: .IP-.nf-\f[C]+.EX /version /accountnames /transactions@@ -407,15 +393,13 @@ /commodities /accounts /accounttransactions/ACCOUNTNAME-\f[R]-.fi+.EE .PP Eg, all account names in the journal (similar to the accounts command). (hledger-web\[aq]s JSON does not include newlines, here we use python to prettify it): .IP-.nf-\f[C]+.EX $ curl -s http://127.0.0.1:5000/accountnames | python -m json.tool [ \[dq]assets\[dq],@@ -432,13 +416,11 @@ \[dq]liabilities\[dq], \[dq]liabilities:debts\[dq] ]-\f[R]-.fi+.EE .PP Or all transactions: .IP-.nf-\f[C]+.EX $ curl -s http://127.0.0.1:5000/transactions | python -m json.tool [ {@@ -457,8 +439,7 @@ \[dq]aismultiplier\[dq]: false, \[dq]aprice\[dq]: null, \&...-\f[R]-.fi+.EE .PP Most of the JSON corresponds to hledger\[aq]s data types; for details of what the fields mean, see the Hledger.Data.Json haddock docs and click@@ -469,34 +450,31 @@ type. To understand that, go to the Hledger.Web.Handler.MiscR haddock and look at the source for the appropriate handler to see what it returns.-Eg for \f[V]/accounttransactions\f[R] it\[aq]s getAccounttransactionsR,-returning a \[dq]\f[V]accountTransactionsReport ...\f[R]\[dq].+Eg for \f[CR]/accounttransactions\f[R] it\[aq]s getAccounttransactionsR,+returning a \[dq]\f[CR]accountTransactionsReport ...\f[R]\[dq]. Looking up the haddock for that we can see that /accounttransactions returns an AccountTransactionsReport, which consists of a report title and a list of AccountTransactionsReportItem (etc). .PP You can add a new transaction to the journal with a PUT request to-\f[V]/add\f[R], if hledger-web was started with the \f[V]add\f[R]+\f[CR]/add\f[R], if hledger-web was started with the \f[CR]add\f[R] capability (enabled by default). The payload must be the full, exact JSON representation of a hledger transaction (partial data won\[aq]t do).-You can get sample JSON from hledger-web\[aq]s \f[V]/transactions\f[R]-or \f[V]/accounttransactions\f[R], or you can export it with+You can get sample JSON from hledger-web\[aq]s \f[CR]/transactions\f[R]+or \f[CR]/accounttransactions\f[R], or you can export it with hledger-lib, eg like so: .IP-.nf-\f[C]+.EX \&.../hledger$ stack ghci hledger-lib >>> writeJsonFile \[dq]txn.json\[dq] (head $ jtxns samplejournal) >>> :q-\f[R]-.fi+.EE .PP Here\[aq]s how it looks as of hledger-1.17 (remember, this JSON corresponds to hledger\[aq]s Transaction and related data types): .IP-.nf-\f[C]+.EX { \[dq]tcomment\[dq]: \[dq]\[dq], \[dq]tpostings\[dq]: [@@ -582,21 +560,17 @@ \[dq]tdescription\[dq]: \[dq]income\[dq], \[dq]tstatus\[dq]: \[dq]Unmarked\[dq] }-\f[R]-.fi+.EE .PP And here\[aq]s how to test adding it with curl. This should add a new entry to your journal: .IP-.nf-\f[C]+.EX $ curl http://127.0.0.1:5000/add -X PUT -H \[aq]Content-Type: application/json\[aq] --data-binary \[at]txn.json-\f[R]-.fi+.EE .SH DEBUG OUTPUT .SS Debug output-.PP-You can add \f[V]--debug[=N]\f[R] to the command line to log debug+You can add \f[CR]--debug[=N]\f[R] to the command line to log debug output. N ranges from 1 (least output, the default) to 9 (maximum output). Typically you would start with 1 and increase until you are seeing@@ -608,14 +582,12 @@ .PD 0 .P .PD-\f[V]hledger-web --debug=3 2>hledger-web.log\f[R].+\f[CR]hledger-web --debug=3 2>hledger-web.log\f[R]. .SH ENVIRONMENT-.PP \f[B]LEDGER_FILE\f[R] The main journal file to use when not specified-with \f[V]-f/--file\f[R].-Default: \f[V]$HOME/.hledger.journal\f[R].+with \f[CR]-f/--file\f[R].+Default: \f[CR]$HOME/.hledger.journal\f[R]. .SH BUGS-.PP We welcome bug reports in the hledger issue tracker (shortcut: http://bugs.hledger.org), or on the #hledger chat or hledger mail list (https://hledger.org/support).
hledger-web.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.1.+-- This file has been generated from package.yaml by hpack version 0.36.0. -- -- see: https://github.com/sol/hpack name: hledger-web-version: 1.31-synopsis: Web-based user interface for the hledger accounting system-description: A simple web-based user interface for the hledger accounting system,+version: 1.32+synopsis: Web user interface for the hledger accounting system+description: A simple web user interface for the hledger accounting system, providing a more modern UI than the command-line or terminal interfaces. It can be used as a local single-user UI, or as a multi-user UI for viewing\/adding\/editing on the web.@@ -130,7 +130,12 @@ library exposed-modules: Hledger.Web+ Hledger.Web.Main+ Hledger.Web.WebOptions Hledger.Web.Application+ Hledger.Web.Import+ Hledger.Web.Test+ other-modules: Hledger.Web.Foundation Hledger.Web.Handler.AddR Hledger.Web.Handler.EditR@@ -138,20 +143,15 @@ Hledger.Web.Handler.MiscR Hledger.Web.Handler.RegisterR Hledger.Web.Handler.UploadR- Hledger.Web.Import- Hledger.Web.Main Hledger.Web.Settings Hledger.Web.Settings.StaticFiles- Hledger.Web.Test- Hledger.Web.WebOptions Hledger.Web.Widget.AddForm Hledger.Web.Widget.Common- other-modules: Paths_hledger_web hs-source-dirs: ./ ghc-options: -Wall -Wredundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns- cpp-options: -DVERSION="1.31"+ cpp-options: -DVERSION="1.32" build-depends: Decimal >=0.5.1 , aeson >=1 && <2.3@@ -171,8 +171,8 @@ , extra >=1.6.3 , filepath , hjsmin- , hledger ==1.31.*- , hledger-lib ==1.31.*+ , hledger ==1.32.*+ , hledger-lib ==1.32.* , hspec , http-client , http-conduit@@ -180,9 +180,10 @@ , megaparsec >=7.0.0 && <9.6 , mtl >=2.2.1 , network+ , safe >=0.3.19 , shakespeare >=2.0.2.2 , template-haskell- , text >=1.2+ , text >=1.2.4.1 , time >=1.5 , transformers , unix-compat@@ -212,7 +213,7 @@ hs-source-dirs: app ghc-options: -Wall -Wredundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns- cpp-options: -DVERSION="1.31"+ cpp-options: -DVERSION="1.32" build-depends: base >=4.14 && <4.19 , hledger-web@@ -232,16 +233,10 @@ hs-source-dirs: test ghc-options: -Wall -Wredundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns- cpp-options: -DVERSION="1.31"+ cpp-options: -DVERSION="1.32" build-depends: base >=4.14 && <4.19- , hledger- , hledger-lib , hledger-web- , hspec- , text- , yesod- , yesod-test default-language: Haskell2010 if (flag(dev)) || (flag(library-only)) cpp-options: -DDEVELOPMENT
hledger-web.info view
@@ -16,7 +16,7 @@ 'hledger-web [--serve|--serve-api] [OPTS] [ARGS]' 'hledger web -- [--serve|--serve-api] [OPTS] [ARGS]' - This manual is for hledger's web interface, version 1.31. See also+ This manual is for hledger's web interface, version 1.32. See also the hledger manual for common concepts and file formats. hledger is a robust, user-friendly, cross-platform set of programs@@ -110,14 +110,11 @@ normally serves static files itself, but if you wanted to serve them from another server for efficiency, you would set the url with this.-'--capabilities=CAP[,CAP..]'-- enable the view, add, and/or manage capabilities (default:- view,add)-'--capabilities-header=HTTPHEADER'+'--allow=view|add|edit' - read capabilities to enable from a HTTP header, like- X-Sandstorm-Permissions (default: disabled)+ set the user's access level for changing data (default: 'add'). It+ also accepts 'sandstorm' for use on that platform (reads+ permissions from the 'X-Sandstorm-Permissions' request header). '--test' run hledger-web's tests and exit. hspec test runner args may@@ -648,28 +645,28 @@ Node: Top225 Node: OPTIONS2577 Ref: #options2682-Node: General help options5993-Ref: #general-help-options6143-Node: General input options6425-Ref: #general-input-options6611-Node: General reporting options7313-Ref: #general-reporting-options7478-Node: PERMISSIONS10868-Ref: #permissions11007-Node: EDITING UPLOADING DOWNLOADING12219-Ref: #editing-uploading-downloading12400-Node: RELOADING13234-Ref: #reloading13368-Node: JSON API13801-Ref: #json-api13916-Node: DEBUG OUTPUT19404-Ref: #debug-output19529-Node: Debug output19556-Ref: #debug-output-119657-Node: ENVIRONMENT20074-Ref: #environment20193-Node: BUGS20310-Ref: #bugs20394+Node: General help options5970+Ref: #general-help-options6120+Node: General input options6402+Ref: #general-input-options6588+Node: General reporting options7290+Ref: #general-reporting-options7455+Node: PERMISSIONS10845+Ref: #permissions10984+Node: EDITING UPLOADING DOWNLOADING12196+Ref: #editing-uploading-downloading12377+Node: RELOADING13211+Ref: #reloading13345+Node: JSON API13778+Ref: #json-api13893+Node: DEBUG OUTPUT19381+Ref: #debug-output19506+Node: Debug output19533+Ref: #debug-output-119634+Node: ENVIRONMENT20051+Ref: #environment20170+Node: BUGS20287+Ref: #bugs20371 End Tag Table
hledger-web.txt view
@@ -9,7 +9,7 @@ hledger web -- [--serve|--serve-api] [OPTS] [ARGS] DESCRIPTION- This manual is for hledger's web interface, version 1.31. See also the+ This manual is for hledger's web interface, version 1.32. See also the hledger manual for common concepts and file formats. hledger is a robust, user-friendly, cross-platform set of programs for@@ -87,13 +87,10 @@ them from another server for efficiency, you would set the url with this. - --capabilities=CAP[,CAP..]- enable the view, add, and/or manage capabilities (default:- view,add)-- --capabilities-header=HTTPHEADER- read capabilities to enable from a HTTP header, like X-Sand-- storm-Permissions (default: disabled)+ --allow=view|add|edit+ set the user's access level for changing data (default: add).+ It also accepts sandstorm for use on that platform (reads per-+ missions from the X-Sandstorm-Permissions request header). --test run hledger-web's tests and exit. hspec test runner args may follow a --, eg: hledger-web --test -- --help@@ -567,4 +564,4 @@ SEE ALSO hledger(1), hledger-ui(1), hledger-web(1), ledger(1) -hledger-web-1.31 September 2023 HLEDGER-WEB(1)+hledger-web-1.32 December 2023 HLEDGER-WEB(1)
templates/default-layout.hamlet view
@@ -7,7 +7,7 @@ <div#topbar .col-md-8 .col-sm-8 .col-xs-10> <h1>#{takeFileName (journalFilePath j)} -$if elem CapView caps+$if elem ViewPermission perms <div#sidebar-menu .sidebar-offcanvas.#{sideShowmd}.#{sideShowsm}> <table .main-menu .table> ^{accounts}@@ -15,7 +15,7 @@ <div#main-content .col-xs-12.#{mainShowmd}.#{mainShowsm}> $maybe m <- msg <div #message .alert.alert-info>#{m}- $if elem CapView caps+ $if elem ViewPermission perms <form#searchform.input-group method=GET> <input .form-control name=q value=#{qparam} placeholder="Search" title="Enter hledger search patterns to filter the data below">@@ -25,7 +25,7 @@ <span .glyphicon .glyphicon-remove-circle> <button .btn .btn-default type=submit title="Apply search terms"> <span .glyphicon .glyphicon-search>- $if elem CapManage caps+ $if elem EditPermission perms <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"
templates/edit-form.hamlet view
@@ -11,7 +11,7 @@ <tr> <td style="border:0"> <span.help>- ^{helplink "file-format" "File format help"}+ ^{helplink "data-formats" "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
@@ -1,7 +1,7 @@ <h2> #{title'} -$if elem CapAdd caps+$if elem AddPermission perms <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@@ -33,5 +33,5 @@ <td .amount style="text-align:right;"> ^{mixedAmountAsHtml amt} -$if elem CapAdd caps+$if elem AddPermission perms ^{addModal AddR j today}
templates/register.hamlet view
@@ -35,5 +35,5 @@ <td style="text-align:right;"> ^{mixedAmountAsHtml bal} -$if elem CapAdd caps+$if elem AddPermission perms ^{addModal AddR j today}