Some predefined boxes for a dashboard

This commit is contained in:
eikek 2022-01-26 21:22:20 +01:00
parent 0337be98f9
commit 370679daed
25 changed files with 1004 additions and 80 deletions

@ -1961,7 +1961,7 @@ paths:
- $ref: "#/components/parameters/bookmarkId"
delete:
operationId: "sec-querybookmark-delete"
tags: [Query Bookmark]
tags: [Query Bookmarks]
summary: Delete a bookmark.
description: |
Deletes a bookmarks by its id.

@ -101,7 +101,9 @@ module Api exposing
, itemDetailShare
, itemIndexSearch
, itemSearch
, itemSearchBookmark
, itemSearchStats
, itemSearchStatsBookmark
, login
, loginSession
, logout
@ -2028,24 +2030,70 @@ itemIndexSearch flags query receive =
}
itemSearch : Flags -> ItemQuery -> (Result Http.Error ItemLightList -> msg) -> Cmd msg
itemSearch flags search receive =
Http2.authPost
itemSearchTask : Flags -> ItemQuery -> Task.Task Http.Error ItemLightList
itemSearchTask flags search =
Http2.authTask
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/search"
, method = "POST"
, headers = []
, account = getAccount flags
, body = Http.jsonBody (Api.Model.ItemQuery.encode search)
, expect = Http.expectJson receive Api.Model.ItemLightList.decoder
, resolver = Http2.jsonResolver Api.Model.ItemLightList.decoder
, timeout = Nothing
}
itemSearch : Flags -> ItemQuery -> (Result Http.Error ItemLightList -> msg) -> Cmd msg
itemSearch flags search receive =
itemSearchTask flags search |> Task.attempt receive
{-| Same as `itemSearch` but interprets the `query` field as a bookmark id.
-}
itemSearchBookmark : Flags -> ItemQuery -> (Result Http.Error ItemLightList -> msg) -> Cmd msg
itemSearchBookmark flags bmSearch receive =
let
getBookmark =
getBookmarkByIdTask flags bmSearch.query
|> Task.map (\bm -> { bmSearch | query = bm.query })
search q =
itemSearchTask flags q
in
Task.andThen search getBookmark
|> Task.attempt receive
itemSearchStatsTask : Flags -> ItemQuery -> Task.Task Http.Error SearchStats
itemSearchStatsTask flags search =
Http2.authTask
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/searchStats"
, method = "POST"
, headers = []
, account = getAccount flags
, body = Http.jsonBody (Api.Model.ItemQuery.encode search)
, resolver = Http2.jsonResolver Api.Model.SearchStats.decoder
, timeout = Nothing
}
itemSearchStats : Flags -> ItemQuery -> (Result Http.Error SearchStats -> msg) -> Cmd msg
itemSearchStats flags search receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/searchStats"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.ItemQuery.encode search)
, expect = Http.expectJson receive Api.Model.SearchStats.decoder
}
itemSearchStatsTask flags search |> Task.attempt receive
itemSearchStatsBookmark : Flags -> ItemQuery -> (Result Http.Error SearchStats -> msg) -> Cmd msg
itemSearchStatsBookmark flags search receive =
let
getBookmark =
getBookmarkByIdTask flags search.query
|> Task.map (\bm -> { search | query = bm.query })
getStats q =
itemSearchStatsTask flags q
in
Task.andThen getStats getBookmark
|> Task.attempt receive
itemDetail : Flags -> String -> (Result Http.Error ItemDetail -> msg) -> Cmd msg
@ -2335,6 +2383,21 @@ getBookmarksTask flags =
}
getBookmarkByIdTask : Flags -> String -> Task.Task Http.Error BookmarkedQuery
getBookmarkByIdTask flags id =
let
findBm all =
Data.Bookmarks.findById id all
mapNotFound maybeBookmark =
Maybe.map Task.succeed maybeBookmark
|> Maybe.withDefault (Task.fail (Http.BadStatus 404))
in
getBookmarksTask flags
|> Task.map findBm
|> Task.andThen mapNotFound
getBookmarks : Flags -> (Result Http.Error AllBookmarks -> msg) -> Cmd msg
getBookmarks flags receive =
let

@ -18,15 +18,18 @@ import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.VersionInfo exposing (VersionInfo)
import Browser exposing (UrlRequest)
import Browser.Navigation exposing (Key)
import Data.Dashboard exposing (Dashboard)
import Data.Flags exposing (Flags)
import Data.ServerEvent exposing (ServerEvent)
import Data.UiSettings exposing (StoredUiSettings, UiSettings)
import Data.UiTheme exposing (UiTheme)
import Http
import Messages
import Messages.UiLanguage exposing (UiLanguage)
import Page exposing (Page(..))
import Page.CollectiveSettings.Data
import Page.Dashboard.Data
import Page.Dashboard.DefaultDashboard
import Page.ItemDetail.Data
import Page.Login.Data
import Page.ManageData.Data
@ -102,6 +105,7 @@ init key url flags_ settings =
( dbm, dbc ) =
Page.Dashboard.Data.init flags
(Page.Dashboard.DefaultDashboard.getDefaultDashboard flags settings)
searchViewMode =
if settings.searchMenuVisible then
@ -214,9 +218,4 @@ defaultPage _ =
getUiLanguage : Model -> UiLanguage
getUiLanguage model =
case model.flags.account of
Just _ ->
model.uiSettings.uiLang
Nothing ->
model.anonymousUiLang
Data.UiSettings.getUiLanguage model.flags model.uiSettings model.anonymousUiLang

@ -364,6 +364,7 @@ applyClientSettings texts model settings =
, setTheme
, Sub.none
)
, updateDashboard texts Page.Dashboard.Data.reloadUiSettings
, updateUserSettings texts Page.UserSettings.Data.UpdateSettings
, updateSearch texts Page.Search.Data.UiSettingsUpdated
, updateItemDetail texts Page.ItemDetail.Data.UiSettingsUpdated
@ -375,7 +376,12 @@ updateDashboard : Messages -> Page.Dashboard.Data.Msg -> Model -> ( Model, Cmd M
updateDashboard texts lmsg model =
let
( dbm, dbc, dbs ) =
Page.Dashboard.Update.update texts.dashboard model.key model.flags lmsg model.dashboardModel
Page.Dashboard.Update.update texts.dashboard
model.uiSettings
model.key
model.flags
lmsg
model.dashboardModel
in
( { model | dashboardModel = dbm }
, Cmd.map DashboardMsg dbc

@ -207,7 +207,7 @@ loadingDimmer : { label : String, active : Bool } -> Html msg
loadingDimmer cfg =
let
content =
div [ class "text-gray-200" ]
div [ class "text-gray-200 " ]
[ i [ class "fa fa-circle-notch animate-spin" ] []
, span [ class "ml-2" ]
[ text cfg.label

@ -0,0 +1,184 @@
module Comp.BoxQueryView exposing (..)
import Api
import Api.Model.ItemLight exposing (ItemLight)
import Api.Model.ItemLightList exposing (ItemLightList)
import Api.Model.ItemQuery exposing (ItemQuery)
import Comp.Basic
import Data.BoxContent exposing (QueryData, SearchQuery(..))
import Data.Flags exposing (Flags)
import Data.ItemTemplate as IT
import Data.Items
import Data.SearchMode
import Html exposing (Html, a, div, i, table, tbody, td, text, th, thead, tr)
import Html.Attributes exposing (class, classList)
import Http
import Messages.Comp.BoxQueryView exposing (Texts)
import Page exposing (Page(..))
import Styles
type alias Model =
{ results : ViewResult
, meta : QueryData
}
type ViewResult
= Loading
| Loaded ItemLightList
| Failed Http.Error
type Msg
= ItemsResp (Result Http.Error ItemLightList)
init : Flags -> QueryData -> ( Model, Cmd Msg )
init flags data =
( { results = Loading
, meta = data
}
, case data.query of
SearchQueryString q ->
Api.itemSearch flags (mkQuery q data) ItemsResp
SearchQueryBookmark bmId ->
Api.itemSearchBookmark flags (mkQuery bmId data) ItemsResp
)
--- Update
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ItemsResp (Ok list) ->
( { model | results = Loaded list }, Cmd.none )
ItemsResp (Err err) ->
( { model | results = Failed err }, Cmd.none )
--- View
view : Texts -> Model -> Html Msg
view texts model =
case model.results of
Loading ->
div [ class "h-24 " ]
[ Comp.Basic.loadingDimmer
{ label = ""
, active = True
}
]
Failed err ->
div
[ class "py-4"
, class Styles.errorMessage
]
[ text texts.errorOccurred
, text ": "
, text (texts.httpError err)
]
Loaded list ->
if list.groups == [] then
viewEmpty texts
else
viewItems texts model.meta list
viewItems : Texts -> QueryData -> ItemLightList -> Html Msg
viewItems texts meta list =
let
items =
Data.Items.flatten list
in
table [ class "w-full divide-y dark:divide-slate-500" ]
(viewItemHead meta ++ [ tbody [] <| List.map (viewItemRow texts meta) items ])
viewItemHead : QueryData -> List (Html Msg)
viewItemHead meta =
case meta.header of
[] ->
[]
labels ->
[ thead []
[ tr []
(List.map (\n -> th [ class "text-left text-sm" ] [ text n ]) labels)
]
]
viewItemRow : Texts -> QueryData -> ItemLight -> Html Msg
viewItemRow texts meta item =
let
( col1, cols ) =
getColumns meta
render tpl =
IT.render tpl texts.templateCtx item
td1 =
td [ class "py-2 px-1" ]
[ a
[ class Styles.link
, Page.href (ItemDetailPage item.id)
]
[ text (render col1)
]
]
tdRem index col =
td
[ class "py-2 px-1"
, classList [ ( "hidden md:table-cell", index > 1 ) ]
]
[ text (render col)
]
in
tr []
(td1 :: List.indexedMap tdRem cols)
viewEmpty : Texts -> Html Msg
viewEmpty texts =
div [ class "flex justify-center items-center h-full" ]
[ div [ class "px-4 py-4 text-center align-middle text-lg" ]
[ i [ class "fa fa-eraser mr-2" ] []
, text texts.noResults
]
]
--- Helpers
getColumns : QueryData -> ( IT.ItemTemplate, List IT.ItemTemplate )
getColumns meta =
case meta.columns of
x :: xs ->
( x, xs )
[] ->
( IT.name, [ IT.correspondent, IT.dateShort ] )
mkQuery : String -> QueryData -> ItemQuery
mkQuery q meta =
{ query = q
, limit = Just meta.limit
, offset = Nothing
, searchMode = Just <| Data.SearchMode.asString Data.SearchMode.Normal
, withDetails = Just meta.details
}

@ -0,0 +1,160 @@
module Comp.BoxSummaryView exposing (..)
import Api
import Api.Model.ItemQuery exposing (ItemQuery)
import Api.Model.SearchStats exposing (SearchStats)
import Comp.Basic
import Comp.SearchStatsView
import Data.BoxContent exposing (SearchQuery(..), SummaryData, SummaryShow(..))
import Data.Flags exposing (Flags)
import Html exposing (Html, div, text)
import Html.Attributes exposing (class)
import Http
import Messages.Comp.BoxSummaryView exposing (Texts)
import Styles
import Util.List
type alias Model =
{ results : ViewResult
, show : SummaryShow
}
type ViewResult
= Loading
| Loaded SearchStats
| Failed Http.Error
type Msg
= StatsResp (Result Http.Error SearchStats)
init : Flags -> SummaryData -> ( Model, Cmd Msg )
init flags data =
( { results = Loading
, show = data.show
}
, case data.query of
SearchQueryString q ->
Api.itemSearchStats flags (mkQuery q) StatsResp
SearchQueryBookmark bmId ->
Api.itemSearchStatsBookmark flags (mkQuery bmId) StatsResp
)
--- Update
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
StatsResp (Ok stats) ->
( { model | results = Loaded stats }, Cmd.none )
StatsResp (Err err) ->
( { model | results = Failed err }, Cmd.none )
--- View
view : Texts -> Model -> Html Msg
view texts model =
case model.results of
Loading ->
div [ class "h-24 " ]
[ Comp.Basic.loadingDimmer
{ label = ""
, active = True
}
]
Failed err ->
div
[ class "py-4"
, class Styles.errorMessage
]
[ text texts.errorOccurred
, text ": "
, text (texts.httpError err)
]
Loaded stats ->
case model.show of
Data.BoxContent.SummaryShowFields flag ->
Comp.SearchStatsView.view2
texts.statsView
flag
""
stats
SummaryShowGeneral ->
viewGeneral texts stats
viewGeneral : Texts -> SearchStats -> Html Msg
viewGeneral texts stats =
let
tagCount =
List.length stats.tagCloud.items
fieldCount =
List.length stats.fieldStats
orgCount =
List.length stats.corrOrgStats
persCount =
(stats.corrPersStats ++ stats.concPersStats)
|> List.map (.ref >> .id)
|> Util.List.distinct
|> List.length
equipCount =
List.length stats.concEquipStats
mklabel name =
div [ class "py-1 text-lg" ] [ text name ]
value num =
div [ class "py-1 font-mono text-lg" ] [ text <| String.fromInt num ]
in
div [ class "opacity-90" ]
[ div [ class "flex flex-row" ]
[ div [ class "flex flex-col mr-4" ]
[ mklabel texts.basics.items
, mklabel texts.basics.tags
, mklabel texts.basics.customFields
, mklabel texts.basics.organization
, mklabel texts.basics.person
, mklabel texts.basics.equipment
]
, div [ class "flex flex-col" ]
[ value stats.count
, value tagCount
, value fieldCount
, value orgCount
, value persCount
, value equipCount
]
]
]
--- Helpers
mkQuery : String -> ItemQuery
mkQuery query =
{ query = query
, limit = Nothing
, offset = Nothing
, searchMode = Nothing
, withDetails = Nothing
}

@ -1,28 +1,180 @@
module Comp.BoxView exposing (..)
import Comp.BoxQueryView
import Comp.BoxSummaryView
import Data.Box exposing (Box)
import Data.BoxContent exposing (BoxContent(..), MessageData)
import Data.Flags exposing (Flags)
import Html exposing (Html, div)
import Html exposing (Html, div, text)
import Html.Attributes exposing (class, classList)
import Markdown
import Messages.Comp.BoxView exposing (Texts)
import Styles as S
type alias Model =
{}
{ box : Box
, content : ContentModel
}
type ContentModel
= ContentMessage Data.BoxContent.MessageData
| ContentUpload (Maybe String)
| ContentQuery Comp.BoxQueryView.Model
| ContentSummary Comp.BoxSummaryView.Model
type Msg
= Dummy
= QueryMsg Comp.BoxQueryView.Msg
| SummaryMsg Comp.BoxSummaryView.Msg
init : Flags -> Box -> ( Model, Cmd Msg )
init flags box =
( {}, Cmd.none )
let
( cm, cc ) =
contentInit flags box.content
in
( { box = box
, content = cm
}
, cc
)
contentInit : Flags -> BoxContent -> ( ContentModel, Cmd Msg )
contentInit flags content =
case content of
BoxMessage data ->
( ContentMessage data, Cmd.none )
BoxUpload source ->
( ContentUpload source, Cmd.none )
BoxQuery data ->
let
( qm, qc ) =
Comp.BoxQueryView.init flags data
in
( ContentQuery qm, Cmd.map QueryMsg qc )
BoxSummary data ->
let
( sm, sc ) =
Comp.BoxSummaryView.init flags data
in
( ContentSummary sm, Cmd.map SummaryMsg sc )
--- Update
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
QueryMsg lm ->
case model.content of
ContentQuery qm ->
let
( cm, cc ) =
Comp.BoxQueryView.update lm qm
in
( { model | content = ContentQuery cm }, Cmd.map QueryMsg cc )
_ ->
unit model
SummaryMsg lm ->
case model.content of
ContentSummary qm ->
let
( cm, cc ) =
Comp.BoxSummaryView.update lm qm
in
( { model | content = ContentSummary cm }, Cmd.map SummaryMsg cc )
_ ->
unit model
unit : Model -> ( Model, Cmd Msg )
unit model =
( model, Cmd.none )
--- View
view : Model -> Html Msg
view model =
div [] []
view : Texts -> Model -> Html Msg
view texts model =
div
[ classList [ ( S.box ++ "rounded", model.box.decoration ) ]
, class (spanStyle model.box)
, class "relative h-full"
, classList [ ( "hidden", not model.box.visible ) ]
]
[ boxHeader model
, div [ class "px-2 py-1 h-5/6" ]
[ boxContent texts model
]
]
boxHeader : Model -> Html Msg
boxHeader model =
div
[ class "border-b dark:border-slate-500 flex flex-row py-1 bg-blue-50 dark:bg-slate-700 rounded-t"
, classList [ ( "hidden", not model.box.decoration || model.box.name == "" ) ]
]
[ div [ class "flex text-lg tracking-medium italic px-2" ]
[ text model.box.name
]
]
boxContent : Texts -> Model -> Html Msg
boxContent texts model =
case model.content of
ContentMessage m ->
messageContent m
ContentUpload sourceId ->
Debug.todo "not implemented"
ContentQuery qm ->
Html.map QueryMsg
(Comp.BoxQueryView.view texts.queryView qm)
ContentSummary qm ->
Html.map SummaryMsg
(Comp.BoxSummaryView.view texts.summaryView qm)
spanStyle : Box -> String
spanStyle box =
case box.colspan of
1 ->
""
2 ->
"col-span-1 md:col-span-2"
3 ->
"col-span-1 md:col-span-3"
4 ->
"col-span-1 md:col-span-4"
_ ->
"col-span-1 md:col-span-5"
messageContent : MessageData -> Html msg
messageContent data =
div [ class "markdown-preview" ]
[ Markdown.toHtml [] data.title
, Markdown.toHtml [] data.body
]

@ -1,4 +1,4 @@
module Comp.DashboardView exposing (Model, Msg, init, view, viewBox)
module Comp.DashboardView exposing (Model, Msg, init, update, view, viewBox)
import Comp.BoxView
import Data.Box exposing (Box)
@ -7,16 +7,17 @@ import Data.Flags exposing (Flags)
import Dict exposing (Dict)
import Html exposing (Html, div)
import Html.Attributes exposing (class)
import Messages.Comp.DashboardView exposing (Texts)
type alias Model =
{ dashboard : Dashboard
, boxModels : List Comp.BoxView.Model
, boxModels : Dict Int Comp.BoxView.Model
}
type Msg
= BoxMsg Comp.BoxView.Msg
= BoxMsg Int Comp.BoxView.Msg
init : Flags -> Dashboard -> ( Model, Cmd Msg )
@ -24,32 +25,61 @@ init flags db =
let
( boxModels, cmds ) =
List.map (Comp.BoxView.init flags) db.boxes
|> List.map (Tuple.mapSecond <| Cmd.map BoxMsg)
|> List.indexedMap (\a -> \( bm, bc ) -> ( bm, Cmd.map (BoxMsg a) bc ))
|> List.unzip
in
( { dashboard = db
, boxModels = boxModels
, boxModels =
List.indexedMap Tuple.pair boxModels
|> Dict.fromList
}
, Cmd.batch cmds
)
--- Update
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
BoxMsg index lm ->
case Dict.get index model.boxModels of
Just bm ->
let
( cm, cc ) =
Comp.BoxView.update lm bm
in
( { model | boxModels = Dict.insert index cm model.boxModels }
, Cmd.map (BoxMsg index) cc
)
Nothing ->
unit model
unit : Model -> ( Model, Cmd Msg )
unit model =
( model, Cmd.none )
--- View
view : Model -> Html Msg
view model =
view : Texts -> Model -> Html Msg
view texts model =
div
[ class (gridStyle model.dashboard)
]
(List.map viewBox model.boxModels)
(List.indexedMap (viewBox texts) <| Dict.values model.boxModels)
viewBox : Comp.BoxView.Model -> Html Msg
viewBox box =
Html.map BoxMsg
(Comp.BoxView.view box)
viewBox : Texts -> Int -> Comp.BoxView.Model -> Html Msg
viewBox texts index box =
Html.map (BoxMsg index)
(Comp.BoxView.view texts.boxView box)

@ -8,6 +8,7 @@
module Comp.SearchStatsView exposing
( nameOrLabel
, sortFields
, view
, view2
)
@ -36,8 +37,13 @@ sortFields fields =
--- View2
view2 : Texts -> String -> SearchStats -> Html msg
view2 texts classes stats =
view : Texts -> String -> SearchStats -> Html msg
view texts classes stats =
view2 texts True classes stats
view2 : Texts -> Bool -> String -> SearchStats -> Html msg
view2 texts showCount classes stats =
let
isNumField f =
f.sum > 0
@ -78,7 +84,10 @@ view2 texts classes stats =
in
div [ class classes ]
[ div [ class "flex flex-col md:flex-row" ]
[ div [ class "px-8 py-4" ]
[ div
[ class "px-8 py-4"
, classList [ ( "hidden", not showCount ) ]
]
[ B.stats
{ rootClass = ""
, valueClass = "text-4xl"

@ -11,6 +11,7 @@ module Data.Bookmarks exposing
, bookmarksDecoder
, empty
, exists
, findById
, sort
)
@ -34,6 +35,12 @@ type alias Bookmarks =
List BookmarkedQuery
findById : String -> Bookmarks -> Maybe BookmarkedQuery
findById id all =
List.filter (\e -> e.id == id) all
|> List.head
{-| Checks wether a bookmark of this name already exists.
-}
exists : String -> Bookmarks -> Bool

@ -1,10 +1,17 @@
module Data.BoxContent exposing (BoxContent(..), MessageData, QueryData, SummaryData)
module Data.BoxContent exposing
( BoxContent(..)
, MessageData
, QueryData
, SearchQuery(..)
, SummaryData
, SummaryShow(..)
)
import Data.ItemArrange exposing (ItemArrange)
import Data.ItemTemplate exposing (ItemTemplate)
type BoxContent
= BoxUpload
= BoxUpload (Maybe String)
| BoxMessage MessageData
| BoxQuery QueryData
| BoxSummary SummaryData
@ -17,11 +24,25 @@ type alias MessageData =
type alias QueryData =
{ query : String
, view : ItemArrange
{ query : SearchQuery
, limit : Int
, details : Bool
, header : List String
, columns : List ItemTemplate
}
type alias SummaryData =
{ query : String
{ query : SearchQuery
, show : SummaryShow
}
type SummaryShow
= SummaryShowFields Bool
| SummaryShowGeneral
type SearchQuery
= SearchQueryString String
| SearchQueryBookmark String

@ -18,6 +18,7 @@ module Data.UiSettings exposing
, defaults
, fieldHidden
, fieldVisible
, getUiLanguage
, merge
, mergeDefaults
, pdfUrl
@ -444,6 +445,16 @@ pdfUrl settings flags originalUrl =
Data.Pdf.serverUrl originalUrl
getUiLanguage : Flags -> UiSettings -> UiLanguage -> UiLanguage
getUiLanguage flags settings default =
case flags.account of
Just _ ->
settings.uiLang
Nothing ->
default
--- Helpers

@ -0,0 +1,46 @@
module Messages.Comp.BoxQueryView exposing (Texts, de, gb)
import Data.ItemTemplate as IT
import Http
import Messages.Basics
import Messages.Comp.HttpError
import Messages.Data.Direction
import Messages.DateFormat as DF
import Messages.UiLanguage
type alias Texts =
{ httpError : Http.Error -> String
, errorOccurred : String
, basics : Messages.Basics.Texts
, noResults : String
, templateCtx : IT.TemplateContext
}
gb : Texts
gb =
{ httpError = Messages.Comp.HttpError.gb
, errorOccurred = "Error retrieving data."
, basics = Messages.Basics.gb
, noResults = "No items found."
, templateCtx =
{ dateFormatLong = DF.formatDateLong Messages.UiLanguage.English
, dateFormatShort = DF.formatDateShort Messages.UiLanguage.English
, directionLabel = Messages.Data.Direction.gb
}
}
de : Texts
de =
{ httpError = Messages.Comp.HttpError.de
, errorOccurred = "Fehler beim Laden der Daten."
, basics = Messages.Basics.de
, noResults = "Keine Dokumente gefunden."
, templateCtx =
{ dateFormatLong = DF.formatDateLong Messages.UiLanguage.German
, dateFormatShort = DF.formatDateShort Messages.UiLanguage.German
, directionLabel = Messages.Data.Direction.de
}
}

@ -0,0 +1,32 @@
module Messages.Comp.BoxSummaryView exposing (Texts, de, gb)
import Http
import Messages.Basics
import Messages.Comp.HttpError
import Messages.Comp.SearchStatsView
type alias Texts =
{ httpError : Http.Error -> String
, errorOccurred : String
, statsView : Messages.Comp.SearchStatsView.Texts
, basics : Messages.Basics.Texts
}
gb : Texts
gb =
{ httpError = Messages.Comp.HttpError.gb
, errorOccurred = "Error retrieving data."
, statsView = Messages.Comp.SearchStatsView.gb
, basics = Messages.Basics.gb
}
de : Texts
de =
{ httpError = Messages.Comp.HttpError.de
, errorOccurred = "Fehler beim Laden der Daten."
, statsView = Messages.Comp.SearchStatsView.de
, basics = Messages.Basics.de
}

@ -0,0 +1,24 @@
module Messages.Comp.BoxView exposing (Texts, de, gb)
import Messages.Comp.BoxQueryView
import Messages.Comp.BoxSummaryView
type alias Texts =
{ queryView : Messages.Comp.BoxQueryView.Texts
, summaryView : Messages.Comp.BoxSummaryView.Texts
}
gb : Texts
gb =
{ queryView = Messages.Comp.BoxQueryView.gb
, summaryView = Messages.Comp.BoxSummaryView.gb
}
de : Texts
de =
{ queryView = Messages.Comp.BoxQueryView.de
, summaryView = Messages.Comp.BoxSummaryView.de
}

@ -0,0 +1,20 @@
module Messages.Comp.DashboardView exposing (Texts, de, gb)
import Messages.Comp.BoxView
type alias Texts =
{ boxView : Messages.Comp.BoxView.Texts
}
gb : Texts
gb =
{ boxView = Messages.Comp.BoxView.gb
}
de : Texts
de =
{ boxView = Messages.Comp.BoxView.de
}

@ -10,6 +10,7 @@ module Messages.DateFormat exposing
, formatDateLong
, formatDateShort
, formatDateTimeLong
, formatDateTimeShort
)
import DateFormat exposing (Token)
@ -68,6 +69,11 @@ formatDateShort lang millis =
format lang .dateShort millis
formatDateTimeShort : UiLanguage -> Int -> String
formatDateTimeShort lang millis =
format lang .dateTimeShort millis
--- Language Definitions

@ -1,6 +1,7 @@
module Messages.Page.Dashboard exposing (Texts, de, gb)
import Messages.Comp.BookmarkChooser
import Messages.Comp.DashboardView
import Messages.Comp.EquipmentManage
import Messages.Comp.FolderManage
import Messages.Comp.NotificationHookManage
@ -10,6 +11,7 @@ import Messages.Comp.PersonManage
import Messages.Comp.ShareManage
import Messages.Comp.SourceManage
import Messages.Comp.TagManage
import Messages.Page.DefaultDashboard
type alias Texts =
@ -23,6 +25,8 @@ type alias Texts =
, equipManage : Messages.Comp.EquipmentManage.Texts
, tagManage : Messages.Comp.TagManage.Texts
, folderManage : Messages.Comp.FolderManage.Texts
, dashboard : Messages.Comp.DashboardView.Texts
, defaultDashboard : Messages.Page.DefaultDashboard.Texts
}
@ -38,6 +42,8 @@ gb =
, equipManage = Messages.Comp.EquipmentManage.gb
, tagManage = Messages.Comp.TagManage.gb
, folderManage = Messages.Comp.FolderManage.gb
, dashboard = Messages.Comp.DashboardView.gb
, defaultDashboard = Messages.Page.DefaultDashboard.gb
}
@ -53,4 +59,6 @@ de =
, equipManage = Messages.Comp.EquipmentManage.de
, tagManage = Messages.Comp.TagManage.de
, folderManage = Messages.Comp.FolderManage.de
, dashboard = Messages.Comp.DashboardView.de
, defaultDashboard = Messages.Page.DefaultDashboard.de
}

@ -0,0 +1,57 @@
module Messages.Page.DefaultDashboard exposing (Texts, de, gb)
import Messages.Basics
type alias Texts =
{ basics : Messages.Basics.Texts
, default : String
, welcomeName : String
, welcomeTitle : String
, welcomeBody : String
, summaryName : String
, dueInDays : Int -> String
, dueHeaderColumns : List String
, newDocsName : String
}
gb : Texts
gb =
let
b =
Messages.Basics.gb
in
{ basics = b
, default = "Default"
, welcomeName = "Welcome Message"
, welcomeTitle = "# Welcome to Docspell"
, welcomeBody = "Docspell keeps your documents organized."
, summaryName = "Summary"
, dueInDays = \n -> "Due in " ++ String.fromInt n ++ " days"
, dueHeaderColumns = dueHeaderCols b
, newDocsName = "New Documents"
}
de : Texts
de =
let
b =
Messages.Basics.de
in
{ basics = b
, default = "Standard"
, welcomeName = "Willkommens-Nachricht"
, welcomeTitle = "# Willkommen zu Docspell"
, welcomeBody = "Docspell behält die Übersicht über deine Dokumene."
, summaryName = "Zahlen"
, dueInDays = \n -> "Fällig in " ++ String.fromInt n ++ " Tagen"
, newDocsName = "Neue Dokumente"
, dueHeaderColumns = dueHeaderCols b
}
dueHeaderCols : Messages.Basics.Texts -> List String
dueHeaderCols b =
[ b.name, b.correspondent, b.date ]

@ -11,6 +11,8 @@ module Page.Dashboard.Data exposing
, Msg(..)
, SideMenuModel
, init
, reloadDashboard
, reloadUiSettings
)
import Api
@ -26,8 +28,8 @@ import Comp.ShareManage
import Comp.SourceManage
import Comp.TagManage
import Data.Bookmarks exposing (AllBookmarks)
import Data.Dashboard exposing (Dashboard)
import Data.Flags exposing (Flags)
import Page.Dashboard.DefaultDashboard as DefaultDashboard
type alias SideMenuModel =
@ -41,11 +43,11 @@ type alias Model =
}
init : Flags -> ( Model, Cmd Msg )
init flags =
init : Flags -> Dashboard -> ( Model, Cmd Msg )
init flags db =
let
( dm, dc ) =
Comp.DashboardView.init flags DefaultDashboard.value
Comp.DashboardView.init flags db
in
( { sideMenu =
{ bookmarkChooser = Comp.BookmarkChooser.init Data.Bookmarks.empty
@ -69,6 +71,16 @@ initCmd flags =
Api.getBookmarks flags ignoreBookmarkError
reloadDashboard : Msg
reloadDashboard =
InitDashboard
reloadUiSettings : Msg
reloadUiSettings =
InitDashboard
type Msg
= GetBookmarksResp AllBookmarks
| BookmarkMsg Comp.BookmarkChooser.Msg

@ -1,57 +1,121 @@
module Page.Dashboard.DefaultDashboard exposing (..)
module Page.Dashboard.DefaultDashboard exposing (getDefaultDashboard, value)
import Data.Box exposing (Box)
import Data.BoxContent exposing (BoxContent(..))
import Data.BoxContent exposing (BoxContent(..), SearchQuery(..), SummaryShow(..))
import Data.Dashboard exposing (Dashboard)
import Data.ItemArrange
import Data.Flags exposing (Flags)
import Data.ItemTemplate as IT
import Data.UiSettings exposing (UiSettings)
import Messages
import Messages.Page.DefaultDashboard exposing (Texts)
import Messages.UiLanguage
value : Dashboard
value =
{ name = "Default"
value : Texts -> Dashboard
value texts =
{ name = texts.default
, columns = 2
, boxes =
[ messageBox
, newDocuments
, summary
[ messageBox texts
, summary2
, newDocuments texts
, dueDocuments texts
, summary texts
]
}
messageBox : Box
messageBox =
{ name = "Welcome Message"
getDefaultDashboard : Flags -> UiSettings -> Dashboard
getDefaultDashboard flags settings =
let
lang =
Data.UiSettings.getUiLanguage flags settings Messages.UiLanguage.English
texts =
Messages.get lang
in
value texts.dashboard.defaultDashboard
--- Boxes
messageBox : Texts -> Box
messageBox texts =
{ name = texts.welcomeName
, visible = True
, decoration = False
, colspan = 2
, content =
BoxMessage
{ title = "Welcome to Docspell"
, body = ""
{ title = texts.welcomeTitle
, body = texts.welcomeBody
}
}
newDocuments : Box
newDocuments =
{ name = "New Documents"
newDocuments : Texts -> Box
newDocuments texts =
{ name = texts.newDocsName
, visible = True
, decoration = True
, colspan = 1
, content =
BoxQuery
{ query = "inbox:yes"
, view = Data.ItemArrange.List
{ query = SearchQueryString "inbox:yes"
, limit = 5
, details = True
, header = []
, columns = []
}
}
summary : Box
summary =
{ name = "Summary"
dueDocuments : Texts -> Box
dueDocuments texts =
{ name = texts.dueInDays 10
, visible = True
, decoration = True
, colspan = 1
, content =
BoxSummary { query = "" }
BoxQuery
{ query = SearchQueryString "due>today;-10d due<today;+10d"
, limit = 5
, details = True
, header = texts.dueHeaderColumns
, columns =
[ IT.name
, IT.correspondent
, IT.dueDateShort
]
}
}
summary : Texts -> Box
summary texts =
{ name = texts.summaryName
, visible = True
, decoration = True
, colspan = 1
, content =
BoxSummary
{ query = SearchQueryString ""
, show = SummaryShowGeneral
}
}
summary2 : Box
summary2 =
{ name = ""
, visible = True
, decoration = True
, colspan = 2
, content =
BoxSummary
{ query = SearchQueryString ""
, show = SummaryShowFields False
}
}

@ -20,6 +20,7 @@ import Comp.ShareManage
import Comp.SourceManage
import Comp.TagManage
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Messages.Page.Dashboard exposing (Texts)
import Page exposing (Page(..))
import Page.Dashboard.Data exposing (..)
@ -27,8 +28,8 @@ import Page.Dashboard.DefaultDashboard
import Set
update : Texts -> Nav.Key -> Flags -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
update texts navKey flags msg model =
update : Texts -> UiSettings -> Nav.Key -> Flags -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
update texts settings navKey flags msg model =
case msg of
GetBookmarksResp list ->
let
@ -59,8 +60,11 @@ update texts navKey flags msg model =
InitDashboard ->
let
board =
Page.Dashboard.DefaultDashboard.getDefaultDashboard flags settings
( dm, dc ) =
Comp.DashboardView.init flags Page.Dashboard.DefaultDashboard.value
Comp.DashboardView.init flags board
in
( { model | content = Home dm }, Cmd.map DashboardMsg dc, Sub.none )
@ -242,7 +246,16 @@ update texts navKey flags msg model =
unit model
DashboardMsg lm ->
unit model
case model.content of
Home m ->
let
( dm, dc ) =
Comp.DashboardView.update lm m
in
( { model | content = Home dm }, Cmd.map DashboardMsg dc, Sub.none )
_ ->
unit model
unit : Model -> ( Model, Cmd Msg, Sub Msg )

@ -48,7 +48,7 @@ viewContent texts flags settings model =
[ case model.content of
Home m ->
Html.map DashboardMsg
(Comp.DashboardView.view m)
(Comp.DashboardView.view texts.dashboard m)
Webhook m ->
viewHookManage texts settings m

@ -563,7 +563,7 @@ editMenuBar texts model svm =
searchStats : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
searchStats texts _ settings model =
if settings.searchStatsVisible then
[ Comp.SearchStatsView.view2 texts.searchStatsView "my-2" model.searchStats
[ Comp.SearchStatsView.view texts.searchStatsView "my-2" model.searchStats
]
else