Editable dashboard

This commit is contained in:
eikek
2022-01-26 21:27:26 +01:00
parent 2c2b34cd89
commit e83bf6b750
41 changed files with 2813 additions and 130 deletions

View File

@ -0,0 +1,467 @@
module Comp.BoxEdit exposing
( BoxAction(..)
, Model
, Msg
, UpdateResult
, init
, update
, view
)
import Comp.Basic as B
import Comp.BoxMessageEdit
import Comp.BoxQueryEdit
import Comp.BoxStatsEdit
import Comp.BoxUploadEdit
import Comp.FixedDropdown
import Comp.MenuBar as MB
import Data.Box exposing (Box)
import Data.BoxContent exposing (BoxContent(..))
import Data.DropdownStyle as DS
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Html exposing (Html, div, i, input, label, text)
import Html.Attributes exposing (class, classList, placeholder, type_, value)
import Html.Events exposing (onInput, onMouseEnter, onMouseLeave)
import Messages.Comp.BoxEdit exposing (Texts)
import Styles as S
type alias Model =
{ box : Box
, content : ContentModel
, colspanModel : Comp.FixedDropdown.Model Int
, focus : Bool
, deleteRequested : Bool
}
type ContentModel
= ContentMessage Comp.BoxMessageEdit.Model
| ContentQuery Comp.BoxQueryEdit.Model
| ContentStats Comp.BoxStatsEdit.Model
| ContentUpload Comp.BoxUploadEdit.Model
type Msg
= ToggleVisible
| ToggleDecoration
| SetName String
| ColspanMsg (Comp.FixedDropdown.Msg Int)
| MessageMsg Comp.BoxMessageEdit.Msg
| UploadMsg Comp.BoxUploadEdit.Msg
| QueryMsg Comp.BoxQueryEdit.Msg
| StatsMsg Comp.BoxStatsEdit.Msg
| SetFocus Bool
| RequestDelete
| DeleteBox
| CancelDelete
| MoveLeft
| MoveRight
init : Flags -> Box -> ( Model, Cmd Msg, Sub Msg )
init flags box =
let
( cm, cc, cs ) =
contentInit flags box.content
in
( { box = box
, content = cm
, colspanModel = Comp.FixedDropdown.init [ 1, 2, 3, 4, 5 ]
, focus = False
, deleteRequested = False
}
, cc
, cs
)
contentInit : Flags -> BoxContent -> ( ContentModel, Cmd Msg, Sub Msg )
contentInit flags content =
case content of
BoxMessage data ->
( ContentMessage (Comp.BoxMessageEdit.init data), Cmd.none, Sub.none )
BoxUpload data ->
let
( um, uc ) =
Comp.BoxUploadEdit.init flags data
in
( ContentUpload um, Cmd.map UploadMsg uc, Sub.none )
BoxQuery data ->
let
( qm, qc, qs ) =
Comp.BoxQueryEdit.init flags data
in
( ContentQuery qm, Cmd.map QueryMsg qc, Sub.map QueryMsg qs )
BoxStats data ->
let
( qm, qc, qs ) =
Comp.BoxStatsEdit.init flags data
in
( ContentStats qm, Cmd.map StatsMsg qc, Sub.map StatsMsg qs )
--- Update
type BoxAction
= BoxNoAction
| BoxMoveLeft
| BoxMoveRight
| BoxDelete
type alias UpdateResult =
{ model : Model
, cmd : Cmd Msg
, sub : Sub Msg
, action : BoxAction
}
update : Flags -> Msg -> Model -> UpdateResult
update flags msg model =
case msg of
MessageMsg lm ->
case model.content of
ContentMessage m ->
let
( mm, data ) =
Comp.BoxMessageEdit.update lm m
boxn =
model.box
box_ =
{ boxn | content = BoxMessage data }
in
{ model = { model | content = ContentMessage mm, box = box_ }
, cmd = Cmd.none
, sub = Sub.none
, action = BoxNoAction
}
_ ->
unit model
UploadMsg lm ->
case model.content of
ContentUpload m ->
let
( um, data ) =
Comp.BoxUploadEdit.update lm m
boxn =
model.box
box_ =
{ boxn | content = BoxUpload data }
in
{ model = { model | content = ContentUpload um, box = box_ }
, cmd = Cmd.none
, sub = Sub.none
, action = BoxNoAction
}
_ ->
unit model
QueryMsg lm ->
case model.content of
ContentQuery m ->
let
result =
Comp.BoxQueryEdit.update flags lm m
boxn =
model.box
box_ =
{ boxn | content = BoxQuery result.data }
in
{ model = { model | content = ContentQuery result.model, box = box_ }
, cmd = Cmd.map QueryMsg result.cmd
, sub = Sub.map QueryMsg result.sub
, action = BoxNoAction
}
_ ->
unit model
StatsMsg lm ->
case model.content of
ContentStats m ->
let
result =
Comp.BoxStatsEdit.update flags lm m
boxn =
model.box
box_ =
{ boxn | content = BoxStats result.data }
in
{ model = { model | content = ContentStats result.model, box = box_ }
, cmd = Cmd.map StatsMsg result.cmd
, sub = Sub.map StatsMsg result.sub
, action = BoxNoAction
}
_ ->
unit model
ColspanMsg lm ->
let
( cm, num ) =
Comp.FixedDropdown.update lm model.colspanModel
boxn =
model.box
box_ =
{ boxn | colspan = Maybe.withDefault boxn.colspan num }
in
unit { model | box = box_, colspanModel = cm }
ToggleVisible ->
let
box =
model.box
box_ =
{ box | visible = not box.visible }
in
unit { model | box = box_ }
ToggleDecoration ->
let
box =
model.box
box_ =
{ box | decoration = not box.decoration }
in
unit { model | box = box_ }
SetName name ->
let
box =
model.box
box_ =
{ box | name = name }
in
unit { model | box = box_ }
SetFocus flag ->
unit { model | focus = flag }
RequestDelete ->
unit { model | deleteRequested = True }
DeleteBox ->
UpdateResult model Cmd.none Sub.none BoxDelete
CancelDelete ->
unit { model | deleteRequested = False }
MoveLeft ->
UpdateResult model Cmd.none Sub.none BoxMoveLeft
MoveRight ->
UpdateResult model Cmd.none Sub.none BoxMoveRight
unit : Model -> UpdateResult
unit model =
UpdateResult model Cmd.none Sub.none BoxNoAction
--- View
view : Texts -> Flags -> UiSettings -> Model -> Html Msg
view texts flags settings model =
div
[ class (S.box ++ "rounded md:relative")
, class " h-full"
, classList [ ( "ring ring-opacity-50 ring-blue-600 dark:ring-sky-600", model.focus ) ]
, onMouseEnter (SetFocus True)
, onMouseLeave (SetFocus False)
]
[ B.contentDimmer model.deleteRequested
(div [ class "flex flex-col" ]
[ div [ class "text-xl" ]
[ i [ class "fa fa-info-circle mr-2" ] []
, text texts.reallyDeleteBox
]
, div [ class "mt-4 flex flex-row items-center space-x-2" ]
[ MB.viewItem <|
MB.DeleteButton
{ tagger = DeleteBox
, title = ""
, label = texts.basics.yes
, icon = Just "fa fa-check"
}
, MB.viewItem <|
MB.SecondaryButton
{ tagger = CancelDelete
, title = ""
, label = texts.basics.no
, icon = Just "fa fa-times"
}
]
]
)
, boxHeader texts model
, formHeader (texts.boxContent.forContent model.box.content)
, div [ class "mb-4 pl-2" ]
[ metaForm texts flags model
]
, formHeader texts.contentProperties
, div [ class "pl-4 pr-2 py-2 h-5/6" ]
[ boxContent texts flags settings model
]
]
formHeader : String -> Html msg
formHeader heading =
div
[ class "mx-2 border-b dark:border-slate-500 text-lg mt-1"
]
[ text heading
]
metaForm : Texts -> Flags -> Model -> Html Msg
metaForm texts _ model =
let
colspanCfg =
{ display = String.fromInt
, icon = \_ -> Nothing
, selectPlaceholder = ""
, style = DS.mainStyle
}
in
div [ class "my-1 px-2 " ]
[ div []
[ label [ class S.inputLabel ]
[ text texts.basics.name
]
, input
[ type_ "text"
, placeholder texts.namePlaceholder
, class S.textInput
, value model.box.name
, onInput SetName
]
[]
]
, div [ class "mt-1" ]
[ MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> ToggleVisible
, label = texts.visible
, value = model.box.visible
, id = ""
}
]
, div [ class "mt-1" ]
[ MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> ToggleDecoration
, label = texts.decorations
, value = model.box.decoration
, id = ""
}
]
, div [ class "mt-1" ]
[ label [ class S.inputLabel ]
[ text texts.colspan ]
, Html.map ColspanMsg
(Comp.FixedDropdown.viewStyled2
colspanCfg
False
(Just model.box.colspan)
model.colspanModel
)
]
]
boxHeader : Texts -> Model -> Html Msg
boxHeader texts model =
div
[ class "flex flex-row py-1 bg-blue-50 dark:bg-slate-700 rounded-t"
]
[ div [ class "flex flex-row items-center text-lg tracking-medium italic px-2" ]
[ i
[ class (Data.Box.boxIcon model.box)
, class "mr-2"
]
[]
, text model.box.name
]
, div [ class "flex flex-grow justify-end pr-1" ]
[ MB.viewItem <|
MB.CustomButton
{ tagger = MoveLeft
, title = texts.moveToLeft
, label = ""
, icon = Just "fa fa-arrow-left"
, inputClass =
[ ( S.secondaryBasicButton, True )
, ( "text-xs", True )
]
}
, MB.viewItem <|
MB.CustomButton
{ tagger = MoveRight
, title = texts.moveToRight
, label = ""
, icon = Just "fa fa-arrow-right"
, inputClass =
[ ( S.secondaryBasicButton, True )
, ( "text-xs mr-3", True )
]
}
, MB.viewItem <|
MB.CustomButton
{ tagger = RequestDelete
, title = texts.deleteBox
, label = ""
, icon = Just "fa fa-trash"
, inputClass =
[ ( S.deleteButton, True )
, ( "text-xs", True )
]
}
]
]
boxContent : Texts -> Flags -> UiSettings -> Model -> Html Msg
boxContent texts flags settings model =
case model.content of
ContentMessage m ->
Html.map MessageMsg
(Comp.BoxMessageEdit.view texts.messageEdit m)
ContentUpload m ->
Html.map UploadMsg
(Comp.BoxUploadEdit.view texts.uploadEdit m)
ContentQuery m ->
Html.map QueryMsg
(Comp.BoxQueryEdit.view texts.queryEdit settings m)
ContentStats m ->
Html.map StatsMsg
(Comp.BoxStatsEdit.view texts.statsEdit settings m)

View File

@ -0,0 +1,92 @@
module Comp.BoxMessageEdit exposing (Model, Msg, init, update, view)
import Data.BoxContent exposing (MessageData)
import Html exposing (Html, div, input, label, text, textarea)
import Html.Attributes exposing (autocomplete, class, name, placeholder, type_, value)
import Html.Events exposing (onInput)
import Messages.Comp.BoxMessageEdit exposing (Texts)
import Styles as S
type alias Model =
{ data : MessageData
}
type Msg
= SetTitle String
| SetBody String
init : MessageData -> Model
init data =
{ data = data
}
--- Update
update : Msg -> Model -> ( Model, MessageData )
update msg model =
case msg of
SetTitle str ->
let
data =
model.data
data_ =
{ data | title = str }
in
( { model | data = data_ }, data_ )
SetBody str ->
let
data =
model.data
data_ =
{ data | body = str }
in
( { model | data = data_ }, data_ )
--- View
view : Texts -> Model -> Html Msg
view texts model =
div []
[ div []
[ label [ class S.inputLabel ]
[ text texts.titleLabel
]
, input
[ type_ "text"
, name "message-title"
, autocomplete False
, onInput SetTitle
, value model.data.title
, placeholder texts.titlePlaceholder
, class S.textInput
]
[]
]
, div [ class "mt-2" ]
[ label [ class S.inputLabel ]
[ text texts.bodyLabel
]
, textarea
[ value model.data.body
, onInput SetBody
, class S.textAreaInput
, placeholder texts.bodyPlaceholder
]
[]
]
, div [ class "opacity-75 text-sm mt-1" ]
[ text texts.infoText
]
]

View File

@ -0,0 +1,190 @@
module Comp.BoxQueryEdit exposing (..)
import Comp.BoxSearchQueryInput
import Comp.IntField
import Comp.ItemColumnDropdown
import Comp.MenuBar as MB
import Data.Bookmarks
import Data.BoxContent exposing (QueryData, SearchQuery(..))
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Html exposing (Html, div, label, text)
import Html.Attributes exposing (class)
import Messages.Comp.BoxQueryEdit exposing (Texts)
import Styles as S
type alias Model =
{ data : QueryData
, searchQueryModel : Comp.BoxSearchQueryInput.Model
, limitModel : Comp.IntField.Model
, limitValue : Maybe Int
, columnModel : Comp.ItemColumnDropdown.Model
}
type Msg
= SearchQueryMsg Comp.BoxSearchQueryInput.Msg
| LimitMsg Comp.IntField.Msg
| ColumnMsg Comp.ItemColumnDropdown.Msg
| ToggleColumnHeaders
init : Flags -> QueryData -> ( Model, Cmd Msg, Sub Msg )
init flags data =
let
( qm, qc, qs ) =
Comp.BoxSearchQueryInput.init flags data.query Data.Bookmarks.empty
emptyModel =
{ data = data
, searchQueryModel = qm
, limitModel = Comp.IntField.init (Just 1) Nothing False
, limitValue = Just data.limit
, columnModel = Comp.ItemColumnDropdown.init data.columns
}
in
( emptyModel, Cmd.map SearchQueryMsg qc, Sub.map SearchQueryMsg qs )
--- Update
type alias UpdateResult =
{ model : Model
, cmd : Cmd Msg
, sub : Sub Msg
, data : QueryData
}
update : Flags -> Msg -> Model -> UpdateResult
update flags msg model =
case msg of
SearchQueryMsg lm ->
let
result =
Comp.BoxSearchQueryInput.update flags lm model.searchQueryModel
setData data =
{ data | query = Maybe.withDefault data.query result.query }
nextModel =
withData setData { model | searchQueryModel = result.model }
in
{ model = nextModel
, cmd = Cmd.map SearchQueryMsg result.cmd
, sub = Sub.map SearchQueryMsg result.sub
, data = nextModel.data
}
LimitMsg lm ->
let
( im, n ) =
Comp.IntField.update lm model.limitModel
data =
model.data
data_ =
case n of
Just num ->
{ data | limit = num }
Nothing ->
data
in
{ model = { model | limitModel = im, limitValue = n, data = data_ }
, cmd = Cmd.none
, sub = Sub.none
, data = data_
}
ColumnMsg lm ->
let
( cm, cc ) =
Comp.ItemColumnDropdown.update lm model.columnModel
selection =
Comp.ItemColumnDropdown.getSelected model.columnModel
data =
model.data
data_ =
{ data | columns = selection }
in
{ model = { model | columnModel = cm, data = data_ }
, cmd = Cmd.map ColumnMsg cc
, sub = Sub.none
, data = data_
}
ToggleColumnHeaders ->
let
data =
model.data
data_ =
{ data | showHeaders = not data.showHeaders }
in
{ model = { model | data = data_ }
, cmd = Cmd.none
, sub = Sub.none
, data = data_
}
unit : Model -> UpdateResult
unit model =
{ model = model
, cmd = Cmd.none
, sub = Sub.none
, data = model.data
}
withData : (QueryData -> QueryData) -> Model -> Model
withData modify model =
{ model | data = modify model.data }
--- View
view : Texts -> UiSettings -> Model -> Html Msg
view texts settings model =
let
limitSettings =
{ label = "Limit"
, info = "Show this many results."
, number = model.limitValue
, classes = ""
}
in
div []
[ Html.map SearchQueryMsg
(Comp.BoxSearchQueryInput.view texts.searchQuery settings model.searchQueryModel)
, div [ class "mt-2" ]
[ Html.map LimitMsg
(Comp.IntField.view limitSettings model.limitModel)
]
, div [ class "mt-2" ]
[ label [ class S.inputLabel ]
[ text "Columns"
]
, Html.map ColumnMsg
(Comp.ItemColumnDropdown.view texts.columnDropdown settings model.columnModel)
]
, div [ class "mt-2" ]
[ MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> ToggleColumnHeaders
, label = texts.showColumnHeaders
, value = model.data.showHeaders
, id = ""
}
]
]

View File

@ -5,11 +5,13 @@ import Api.Model.ItemLight exposing (ItemLight)
import Api.Model.ItemLightList exposing (ItemLightList)
import Api.Model.ItemQuery exposing (ItemQuery)
import Comp.Basic
import Comp.ItemColumnView
import Data.BoxContent exposing (QueryData, SearchQuery(..))
import Data.Flags exposing (Flags)
import Data.ItemTemplate as IT
import Data.ItemColumn as IC exposing (ItemColumn)
import Data.Items
import Data.SearchMode
import Data.UiSettings exposing (UiSettings)
import Html exposing (Html, a, div, i, table, tbody, td, text, th, thead, tr)
import Html.Attributes exposing (class, classList)
import Http
@ -70,8 +72,8 @@ update flags msg model =
--- View
view : Texts -> Model -> Html Msg
view texts model =
view : Texts -> UiSettings -> Model -> Html Msg
view texts settings model =
case model.results of
Loading ->
div [ class "h-24 " ]
@ -96,41 +98,42 @@ view texts model =
viewEmpty texts
else
viewItems texts model.meta list
viewItems texts settings model.meta list
viewItems : Texts -> QueryData -> ItemLightList -> Html Msg
viewItems texts meta list =
viewItems : Texts -> UiSettings -> QueryData -> ItemLightList -> Html Msg
viewItems texts settings 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 texts meta ++ [ tbody [] <| List.map (viewItemRow texts settings meta) items ])
viewItemHead : QueryData -> List (Html Msg)
viewItemHead meta =
case meta.header of
[] ->
[]
viewItemHead : Texts -> QueryData -> List (Html Msg)
viewItemHead texts meta =
if not meta.showHeaders || meta.columns == [] then
[]
labels ->
[ thead []
[ tr []
(List.map (\n -> th [ class "text-left text-sm" ] [ text n ]) labels)
]
else
[ thead []
[ tr []
(List.map texts.itemColumn.header meta.columns
|> List.map (\n -> th [ class "text-left text-sm" ] [ text n ])
)
]
]
viewItemRow : Texts -> QueryData -> ItemLight -> Html Msg
viewItemRow texts meta item =
viewItemRow : Texts -> UiSettings -> QueryData -> ItemLight -> Html Msg
viewItemRow texts settings meta item =
let
( col1, cols ) =
getColumns meta
render tpl =
IT.render tpl texts.templateCtx item
render col =
Comp.ItemColumnView.renderDiv texts.templateCtx settings col [ class "flex flex-row space-x-1" ] item
td1 =
td [ class "py-2 px-1" ]
@ -138,7 +141,7 @@ viewItemRow texts meta item =
[ class Styles.link
, Page.href (ItemDetailPage item.id)
]
[ text (render col1)
[ render col1
]
]
@ -147,7 +150,7 @@ viewItemRow texts meta item =
[ class "py-2 px-1"
, classList [ ( "hidden md:table-cell", index > 1 ) ]
]
[ text (render col)
[ render col
]
in
tr []
@ -168,14 +171,14 @@ viewEmpty texts =
--- Helpers
getColumns : QueryData -> ( IT.ItemTemplate, List IT.ItemTemplate )
getColumns : QueryData -> ( ItemColumn, List ItemColumn )
getColumns meta =
case meta.columns of
x :: xs ->
( x, xs )
[] ->
( IT.name, [ IT.correspondent, IT.dateShort ] )
( IC.Name, [ IC.Correspondent, IC.DateShort ] )
mkQuery : String -> QueryData -> ItemQuery

View File

@ -0,0 +1,292 @@
module Comp.BoxSearchQueryInput exposing
( Model
, Msg
, UpdateResult
, init
, switchToBookmark
, switchToQuery
, toSearchQuery
, update
, view
)
import Api
import Comp.BookmarkDropdown
import Comp.PowerSearchInput
import Data.Bookmarks exposing (AllBookmarks)
import Data.BoxContent exposing (SearchQuery(..))
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Html exposing (Html, div, input, label, span, text)
import Html.Attributes exposing (checked, class, type_)
import Html.Events exposing (onCheck)
import Http
import Messages.Comp.BoxSearchQueryInput exposing (Texts)
import Styles as S
type alias Model =
{ queryModel : QueryModel
, allBookmarks : AllBookmarks
}
type QueryModel
= Search Comp.PowerSearchInput.Model
| Bookmark Comp.BookmarkDropdown.Model
toSearchQuery : Model -> Maybe SearchQuery
toSearchQuery model =
case model.queryModel of
Search pm ->
let
qstr =
Maybe.withDefault "" pm.input
in
if qstr == "" || Comp.PowerSearchInput.isValid pm then
Just (SearchQueryString qstr)
else
Nothing
Bookmark bm ->
Comp.BookmarkDropdown.getSelectedId bm
|> Maybe.map SearchQueryBookmark
type Msg
= GetBookmarksResp (Result Http.Error AllBookmarks)
| BookmarkMsg Comp.BookmarkDropdown.Msg
| PowerSearchMsg Comp.PowerSearchInput.Msg
| SwitchQueryBookmark
| SwitchQuerySearch
switchToBookmark : Msg
switchToBookmark =
SwitchQueryBookmark
switchToQuery : Msg
switchToQuery =
SwitchQuerySearch
init : Flags -> SearchQuery -> AllBookmarks -> ( Model, Cmd Msg, Sub Msg )
init flags query bookmarks =
let
emptyModel =
{ queryModel = Search Comp.PowerSearchInput.init
, allBookmarks = bookmarks
}
in
case query of
SearchQueryBookmark id ->
initQueryBookmark flags emptyModel (Just id)
SearchQueryString qstr ->
initQuerySearch emptyModel qstr
initQueryBookmark : Flags -> Model -> Maybe String -> ( Model, Cmd Msg, Sub Msg )
initQueryBookmark flags model bookmarkId =
( { model
| queryModel =
Bookmark
(Comp.BookmarkDropdown.initWith model.allBookmarks bookmarkId)
}
, if model.allBookmarks == Data.Bookmarks.empty then
Api.getBookmarks flags GetBookmarksResp
else
Cmd.none
, Sub.none
)
initQuerySearch : Model -> String -> ( Model, Cmd Msg, Sub Msg )
initQuerySearch model qstr =
let
( qm, qc, qs ) =
Comp.PowerSearchInput.initWith qstr
in
( { model | queryModel = Search qm }
, Cmd.map PowerSearchMsg qc
, Sub.map PowerSearchMsg qs
)
--- Update
type alias UpdateResult =
{ model : Model
, cmd : Cmd Msg
, sub : Sub Msg
, query : Maybe SearchQuery
}
update : Flags -> Msg -> Model -> UpdateResult
update flags msg model =
case msg of
GetBookmarksResp (Ok list) ->
let
bmId =
case model.queryModel of
Bookmark bm ->
Comp.BookmarkDropdown.getSelectedId bm
Search _ ->
Nothing
nm =
{ model | allBookmarks = list }
in
case model.queryModel of
Bookmark _ ->
update flags
SwitchQueryBookmark
{ nm
| queryModel =
Bookmark (Comp.BookmarkDropdown.initWith model.allBookmarks bmId)
}
Search _ ->
unit nm
GetBookmarksResp (Err _) ->
unit model
BookmarkMsg lm ->
case model.queryModel of
Bookmark m ->
let
( bm, bc ) =
Comp.BookmarkDropdown.update lm m
nextModel =
{ model | queryModel = Bookmark bm }
in
{ model = nextModel
, cmd = Cmd.map BookmarkMsg bc
, sub = Sub.none
, query = toSearchQuery nextModel
}
_ ->
unit model
PowerSearchMsg lm ->
case model.queryModel of
Search m ->
let
result =
Comp.PowerSearchInput.update lm m
nextModel =
{ model | queryModel = Search result.model }
in
{ model = nextModel
, cmd = Cmd.map PowerSearchMsg result.cmd
, sub = Sub.map PowerSearchMsg result.subs
, query = toSearchQuery nextModel
}
_ ->
unit model
SwitchQueryBookmark ->
let
selected =
case toSearchQuery model of
Just (SearchQueryBookmark id) ->
Just id
_ ->
Nothing
( m, c, s ) =
initQueryBookmark flags model selected
in
UpdateResult m c s (toSearchQuery m)
SwitchQuerySearch ->
let
qstr =
case toSearchQuery model of
Just (SearchQueryString q) ->
q
_ ->
""
( m, c, s ) =
initQuerySearch model qstr
in
UpdateResult m c s (toSearchQuery m)
unit : Model -> UpdateResult
unit model =
UpdateResult model Cmd.none Sub.none Nothing
--- View
view : Texts -> UiSettings -> Model -> Html Msg
view texts settings model =
let
( isBookmark, isQuery ) =
case model.queryModel of
Bookmark _ ->
( True, False )
Search _ ->
( False, True )
searchSettings =
{ placeholder = texts.searchPlaceholder
, extraAttrs = []
}
in
div [ class "flex flex-col" ]
[ div [ class "flex flex-row space-x-4" ]
[ label [ class "inline-flex items-center" ]
[ input
[ type_ "radio"
, checked isBookmark
, onCheck (\_ -> SwitchQueryBookmark)
, class S.radioInput
]
[]
, span [ class "ml-2" ] [ text texts.switchToBookmark ]
]
, label [ class "inline-flex items-center" ]
[ input
[ type_ "radio"
, checked isQuery
, onCheck (\_ -> SwitchQuerySearch)
, class S.radioInput
]
[]
, span [ class "ml-2" ] [ text texts.switchToQuery ]
]
]
, case model.queryModel of
Bookmark m ->
Html.map BookmarkMsg
(Comp.BookmarkDropdown.view texts.bookmarkDropdown settings m)
Search m ->
div [ class "relative" ]
[ Html.map PowerSearchMsg
(Comp.PowerSearchInput.viewInput searchSettings m)
, Html.map PowerSearchMsg
(Comp.PowerSearchInput.viewResult [] m)
]
]

View File

@ -0,0 +1,195 @@
module Comp.BoxStatsEdit exposing (..)
import Comp.BoxSearchQueryInput
import Comp.FixedDropdown
import Comp.MenuBar as MB
import Data.Bookmarks
import Data.BoxContent exposing (QueryData, SearchQuery(..), StatsData, SummaryShow(..))
import Data.DropdownStyle as DS
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Html exposing (Html, div, label, span, text)
import Html.Attributes exposing (class)
import Messages.Comp.BoxStatsEdit exposing (Texts)
import Styles as S
type alias Model =
{ data : StatsData
, searchQueryModel : Comp.BoxSearchQueryInput.Model
, showModel : Comp.FixedDropdown.Model SummaryShowLabel
, summaryShow : SummaryShow
}
type Msg
= SearchQueryMsg Comp.BoxSearchQueryInput.Msg
| ShowMsg (Comp.FixedDropdown.Msg SummaryShowLabel)
| ToggleItemCountVisible
type SummaryShowLabel
= ShowFields
| ShowGeneric
init : Flags -> StatsData -> ( Model, Cmd Msg, Sub Msg )
init flags data =
let
( qm, qc, qs ) =
Comp.BoxSearchQueryInput.init flags data.query Data.Bookmarks.empty
emptyModel =
{ data = data
, searchQueryModel = qm
, showModel =
Comp.FixedDropdown.init
[ ShowFields, ShowGeneric ]
, summaryShow = data.show
}
in
( emptyModel, Cmd.map SearchQueryMsg qc, Sub.map SearchQueryMsg qs )
--- Update
type alias UpdateResult =
{ model : Model
, cmd : Cmd Msg
, sub : Sub Msg
, data : StatsData
}
update : Flags -> Msg -> Model -> UpdateResult
update flags msg model =
case msg of
SearchQueryMsg lm ->
let
result =
Comp.BoxSearchQueryInput.update flags lm model.searchQueryModel
setData data =
{ data | query = Maybe.withDefault data.query result.query }
nextModel =
withData setData { model | searchQueryModel = result.model }
in
{ model = nextModel
, cmd = Cmd.map SearchQueryMsg result.cmd
, sub = Sub.map SearchQueryMsg result.sub
, data = nextModel.data
}
ShowMsg lm ->
let
( mm, sel ) =
Comp.FixedDropdown.update lm model.showModel
nextShow =
case ( model.summaryShow, sel ) of
( SummaryShowFields _, Just ShowGeneric ) ->
SummaryShowGeneral
( SummaryShowGeneral, Just ShowFields ) ->
SummaryShowFields False
_ ->
model.summaryShow
data =
model.data
data_ =
{ data | show = nextShow }
in
unit { model | showModel = mm, summaryShow = nextShow, data = data_ }
ToggleItemCountVisible ->
let
nextShow =
case model.summaryShow of
SummaryShowFields flag ->
SummaryShowFields (not flag)
_ ->
model.summaryShow
data =
model.data
data_ =
{ data | show = nextShow }
in
unit { model | summaryShow = nextShow, data = data_ }
unit : Model -> UpdateResult
unit model =
{ model = model
, cmd = Cmd.none
, sub = Sub.none
, data = model.data
}
withData : (StatsData -> StatsData) -> Model -> Model
withData modify model =
{ model | data = modify model.data }
--- View
view : Texts -> UiSettings -> Model -> Html Msg
view texts settings model =
let
showSettings =
{ display =
\a ->
case a of
ShowFields ->
texts.fieldStatistics
ShowGeneric ->
texts.basicNumbers
, icon = \_ -> Nothing
, selectPlaceholder = ""
, style = DS.mainStyle
}
showLabel =
case model.summaryShow of
SummaryShowFields _ ->
ShowFields
SummaryShowGeneral ->
ShowGeneric
in
div []
[ Html.map SearchQueryMsg
(Comp.BoxSearchQueryInput.view texts.searchQuery settings model.searchQueryModel)
, div [ class "mt-2" ]
[ label [ class S.inputLabel ]
[ text texts.showLabel ]
, Html.map ShowMsg
(Comp.FixedDropdown.viewStyled2 showSettings False (Just showLabel) model.showModel)
]
, div [ class "mt-2" ]
[ case model.summaryShow of
SummaryShowGeneral ->
span [ class "hidden" ] []
SummaryShowFields itemCountVisible ->
MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> ToggleItemCountVisible
, label = texts.showItemCount
, id = ""
, value = itemCountVisible
}
]
]

View File

@ -1,23 +1,23 @@
module Comp.BoxSummaryView exposing (Model, Msg, init, reloadData, update, view)
module Comp.BoxStatsView exposing (Model, Msg, init, reloadData, update, view)
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.BoxContent exposing (SearchQuery(..), StatsData, 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 Messages.Comp.BoxStatsView exposing (Texts)
import Styles
import Util.List
type alias Model =
{ results : ViewResult
, meta : SummaryData
, meta : StatsData
}
@ -32,7 +32,7 @@ type Msg
| ReloadData
init : Flags -> SummaryData -> ( Model, Cmd Msg )
init : Flags -> StatsData -> ( Model, Cmd Msg )
init flags data =
( { results = Loading
, meta = data
@ -169,7 +169,7 @@ mkQuery query =
}
dataCmd : Flags -> SummaryData -> Cmd Msg
dataCmd : Flags -> StatsData -> Cmd Msg
dataCmd flags data =
case data.query of
SearchQueryString q ->

View File

@ -0,0 +1,106 @@
module Comp.BoxUploadEdit exposing (..)
import Api
import Api.Model.Source exposing (Source)
import Api.Model.SourceList exposing (SourceList)
import Comp.BoxUploadView exposing (Msg)
import Comp.FixedDropdown
import Data.BoxContent exposing (UploadData)
import Data.DropdownStyle as DS
import Data.Flags exposing (Flags)
import Html exposing (Html, div, label, text)
import Html.Attributes exposing (class)
import Http
import Messages.Comp.BoxUploadEdit exposing (Texts)
import Styles as S
type alias Model =
{ data : UploadData
, allSources : List Source
, sourceModel : Comp.FixedDropdown.Model Source
}
type Msg
= GetSourcesResp (Result Http.Error SourceList)
| SourceMsg (Comp.FixedDropdown.Msg Source)
init : Flags -> UploadData -> ( Model, Cmd Msg )
init flags data =
( { data = data
, allSources = []
, sourceModel = Comp.FixedDropdown.init []
}
, Api.getSources flags GetSourcesResp
)
--- Update
update : Msg -> Model -> ( Model, UploadData )
update msg model =
case msg of
GetSourcesResp (Ok list) ->
let
all =
List.map .source list.items
|> List.filter .enabled
dm =
Comp.FixedDropdown.init all
in
( { model | allSources = all, sourceModel = dm }
, model.data
)
GetSourcesResp (Err _) ->
( model, model.data )
SourceMsg lm ->
let
( dm, sel ) =
Comp.FixedDropdown.update lm model.sourceModel
ud =
model.data
ud_ =
{ ud | sourceId = Maybe.map .id sel }
in
( { model | sourceModel = dm, data = ud_ }, ud_ )
--- View
view : Texts -> Model -> Html Msg
view texts model =
let
cfg =
{ display = \s -> s.abbrev
, icon = \_ -> Nothing
, selectPlaceholder = texts.sourcePlaceholder
, style = DS.mainStyle
}
selected =
List.filter (\e -> Just e.id == model.data.sourceId) model.allSources
|> List.head
in
div []
[ div []
[ label [ class S.inputLabel ]
[ text texts.sourceLabel
]
, Html.map SourceMsg
(Comp.FixedDropdown.viewStyled2 cfg False selected model.sourceModel)
]
, div [ class "mt-1 opacity-75 text-sm" ]
[ text texts.infoText
]
]

View File

@ -1,6 +1,7 @@
module Comp.BoxUploadView exposing (..)
import Comp.UploadForm
import Data.BoxContent exposing (UploadData)
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Html exposing (Html, div)
@ -18,10 +19,10 @@ type Msg
= UploadMsg Comp.UploadForm.Msg
init : Maybe String -> Model
init sourceId =
init : UploadData -> Model
init data =
{ uploadForm = Comp.UploadForm.init
, sourceId = sourceId
, sourceId = data.sourceId
}

View File

@ -1,7 +1,7 @@
module Comp.BoxView exposing (..)
import Comp.BoxQueryView
import Comp.BoxSummaryView
import Comp.BoxStatsView
import Comp.BoxUploadView
import Data.Box exposing (Box)
import Data.BoxContent exposing (BoxContent(..), MessageData)
@ -25,12 +25,12 @@ type ContentModel
= ContentMessage Data.BoxContent.MessageData
| ContentUpload Comp.BoxUploadView.Model
| ContentQuery Comp.BoxQueryView.Model
| ContentSummary Comp.BoxSummaryView.Model
| ContentStats Comp.BoxStatsView.Model
type Msg
= QueryMsg Comp.BoxQueryView.Msg
| SummaryMsg Comp.BoxSummaryView.Msg
| StatsMsg Comp.BoxStatsView.Msg
| UploadMsg Comp.BoxUploadView.Msg
| ReloadData
@ -60,10 +60,10 @@ contentInit flags content =
BoxMessage data ->
( ContentMessage data, Cmd.none )
BoxUpload source ->
BoxUpload data ->
let
qm =
Comp.BoxUploadView.init source
Comp.BoxUploadView.init data
in
( ContentUpload qm, Cmd.none )
@ -74,12 +74,12 @@ contentInit flags content =
in
( ContentQuery qm, Cmd.map QueryMsg qc )
BoxSummary data ->
BoxStats data ->
let
( sm, sc ) =
Comp.BoxSummaryView.init flags data
Comp.BoxStatsView.init flags data
in
( ContentSummary sm, Cmd.map SummaryMsg sc )
( ContentStats sm, Cmd.map StatsMsg sc )
@ -104,15 +104,15 @@ update flags msg model =
_ ->
unit model
SummaryMsg lm ->
StatsMsg lm ->
case model.content of
ContentSummary qm ->
ContentStats qm ->
let
( cm, cc, reloading ) =
Comp.BoxSummaryView.update flags lm qm
Comp.BoxStatsView.update flags lm qm
in
( { model | content = ContentSummary cm, reloading = reloading }
, Cmd.map SummaryMsg cc
( { model | content = ContentStats cm, reloading = reloading }
, Cmd.map StatsMsg cc
, Sub.none
)
@ -139,8 +139,8 @@ update flags msg model =
ContentQuery _ ->
update flags (QueryMsg Comp.BoxQueryView.reloadData) model
ContentSummary _ ->
update flags (SummaryMsg Comp.BoxSummaryView.reloadData) model
ContentStats _ ->
update flags (StatsMsg Comp.BoxStatsView.reloadData) model
_ ->
unit model
@ -206,11 +206,11 @@ boxContent texts flags settings model =
ContentQuery qm ->
Html.map QueryMsg
(Comp.BoxQueryView.view texts.queryView qm)
(Comp.BoxQueryView.view texts.queryView settings qm)
ContentSummary qm ->
Html.map SummaryMsg
(Comp.BoxSummaryView.view texts.summaryView qm)
ContentStats qm ->
Html.map StatsMsg
(Comp.BoxStatsView.view texts.statsView qm)
spanStyle : Box -> String

View File

@ -0,0 +1,458 @@
module Comp.DashboardEdit exposing (Model, Msg, SubmitAction(..), init, update, view, viewBox)
import Comp.BoxEdit
import Comp.FixedDropdown
import Comp.MenuBar as MB
import Data.Box exposing (Box)
import Data.Dashboard exposing (Dashboard)
import Data.DropdownStyle as DS
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Dict exposing (Dict)
import Html exposing (Html, div, i, input, label, text)
import Html.Attributes exposing (class, classList, href, placeholder, type_, value)
import Html.Events exposing (onClick, onInput)
import Html5.DragDrop as DD
import Messages.Comp.DashboardEdit exposing (Texts)
import Styles as S
import Util.Maybe
type alias Model =
{ dashboard : Dashboard
, originalName : String
, boxModels : Dict Int Comp.BoxEdit.Model
, nameValue : Maybe String
, columnsModel : Comp.FixedDropdown.Model Int
, columnsValue : Maybe Int
, newBoxMenuOpen : Bool
, boxDragDrop : DD.Model Int Int
}
type Msg
= BoxMsg Int Comp.BoxEdit.Msg
| SaveDashboard
| Cancel
| RequestDelete
| SetName String
| ColumnsMsg (Comp.FixedDropdown.Msg Int)
| ToggleNewBoxMenu
| PrependNew Box
| DragDropMsg (DD.Msg Int Int)
type SubmitAction
= SubmitSave Dashboard
| SubmitCancel
| SubmitDelete String
| SubmitNone
init : Flags -> Dashboard -> ( Model, Cmd Msg, Sub Msg )
init flags db =
let
( boxModels, cmdsAndSubs ) =
List.map (Comp.BoxEdit.init flags) db.boxes
|> List.indexedMap
(\a ->
\( bm, bc, bs ) ->
( bm, ( Cmd.map (BoxMsg a) bc, Sub.map (BoxMsg a) bs ) )
)
|> List.unzip
( cmds, subs ) =
List.unzip cmdsAndSubs
in
( { dashboard = db
, originalName = db.name
, nameValue = Just db.name
, columnsModel = Comp.FixedDropdown.init [ 1, 2, 3, 4, 5 ]
, columnsValue = Just db.columns
, newBoxMenuOpen = False
, boxModels =
List.indexedMap Tuple.pair boxModels
|> Dict.fromList
, boxDragDrop = DD.init
}
, Cmd.batch cmds
, Sub.batch subs
)
--- Update
type alias UpdateResult =
{ model : Model
, cmd : Cmd Msg
, sub : Sub Msg
, action : SubmitAction
}
update : Flags -> Msg -> Model -> UpdateResult
update flags msg model =
case msg of
BoxMsg index lm ->
case Dict.get index model.boxModels of
Just bm ->
let
result =
Comp.BoxEdit.update flags lm bm
newBoxes =
applyBoxAction index result.action <|
Dict.insert index result.model model.boxModels
db =
model.dashboard
db_ =
{ db | boxes = List.map .box (Dict.values newBoxes) }
in
{ model = { model | boxModels = newBoxes, dashboard = db_ }
, cmd = Cmd.map (BoxMsg index) result.cmd
, sub = Sub.map (BoxMsg index) result.sub
, action = SubmitNone
}
Nothing ->
unit model
SetName str ->
case Util.Maybe.fromString str of
Just s ->
let
db =
model.dashboard
db_ =
{ db | name = s }
in
unit { model | dashboard = db_, nameValue = Just s }
Nothing ->
unit { model | nameValue = Nothing }
ColumnsMsg lm ->
let
( cm, value ) =
Comp.FixedDropdown.update lm model.columnsModel
db =
model.dashboard
db_ =
{ db | columns = Maybe.withDefault db.columns value }
in
unit { model | columnsValue = value, columnsModel = cm, dashboard = db_ }
SaveDashboard ->
UpdateResult model Cmd.none Sub.none (SubmitSave model.dashboard)
Cancel ->
UpdateResult model Cmd.none Sub.none SubmitCancel
RequestDelete ->
UpdateResult model Cmd.none Sub.none (SubmitDelete model.originalName)
ToggleNewBoxMenu ->
unit { model | newBoxMenuOpen = not model.newBoxMenuOpen }
PrependNew box ->
let
min =
Dict.keys model.boxModels
|> List.minimum
|> Maybe.withDefault 1
index =
min - 1
db =
model.dashboard
db_ =
{ db | boxes = box :: db.boxes }
( bm, bc, bs ) =
Comp.BoxEdit.init flags box
newBoxes =
Dict.insert index bm model.boxModels
in
{ model = { model | boxModels = newBoxes, dashboard = db_, newBoxMenuOpen = False }
, cmd = Cmd.map (BoxMsg index) bc
, sub = Sub.map (BoxMsg index) bs
, action = SubmitNone
}
DragDropMsg lm ->
let
( dm, dropped ) =
DD.update lm model.boxDragDrop
m_ =
{ model | boxDragDrop = dm }
nextModel =
case dropped of
Just ( dragId, dropId, _ ) ->
applyDrop dragId dropId m_
Nothing ->
m_
in
unit nextModel
unit : Model -> UpdateResult
unit model =
UpdateResult model Cmd.none Sub.none SubmitNone
applyBoxAction :
Int
-> Comp.BoxEdit.BoxAction
-> Dict Int Comp.BoxEdit.Model
-> Dict Int Comp.BoxEdit.Model
applyBoxAction index action boxes =
let
swap n1 n2 =
Maybe.map2
(\e1 -> \e2 -> Dict.insert n2 e1 boxes |> Dict.insert n1 e2)
(Dict.get n1 boxes)
(Dict.get n2 boxes)
|> Maybe.withDefault boxes
in
case action of
Comp.BoxEdit.BoxNoAction ->
boxes
Comp.BoxEdit.BoxDelete ->
Dict.remove index boxes
Comp.BoxEdit.BoxMoveLeft ->
swap (index - 1) index
Comp.BoxEdit.BoxMoveRight ->
swap index (index + 1)
applyDrop : Int -> Int -> Model -> Model
applyDrop dragId dropId model =
let
dragEl =
Dict.get dragId model.boxModels
in
if dragId == dropId then
model
else
case dragEl of
Just box ->
let
withoutDragged =
Dict.remove dragId model.boxModels
( begin, end ) =
Dict.partition (\k -> \_ -> k < dropId) withoutDragged
incKeys =
Dict.toList end
|> List.map (\( k, v ) -> ( k + 1, v ))
|> Dict.fromList
newBoxes =
Dict.insert dropId box (Dict.union begin incKeys)
db =
model.dashboard
db_ =
{ db | boxes = List.map .box (Dict.values newBoxes) }
in
{ model | boxModels = newBoxes, dashboard = db_ }
Nothing ->
model
--- View
view : Texts -> Flags -> UiSettings -> Model -> Html Msg
view texts flags settings model =
let
boxMenuItem box =
{ icon = i [ class (Data.Box.boxIcon box) ] []
, label = texts.boxContent.forContent box.content
, disabled = False
, attrs =
[ href "#"
, onClick (PrependNew box)
]
}
in
div []
[ viewMain texts flags settings model
, div [ class S.formHeader ]
[ text texts.dashboardBoxes
]
, MB.view
{ start = []
, end =
[ MB.Dropdown
{ linkIcon = "fa fa-plus"
, label = texts.newBox
, linkClass =
[ ( S.secondaryBasicButton, True )
]
, toggleMenu = ToggleNewBoxMenu
, menuOpen = model.newBoxMenuOpen
, items =
[ boxMenuItem Data.Box.queryBox
, boxMenuItem Data.Box.statsBox
, boxMenuItem Data.Box.messageBox
, boxMenuItem Data.Box.uploadBox
]
}
]
, rootClasses = "mb-2"
}
, div
[ class (gridStyle model.dashboard)
]
(List.map
(viewBox texts flags settings model)
(Dict.toList model.boxModels)
)
]
viewBox : Texts -> Flags -> UiSettings -> Model -> ( Int, Comp.BoxEdit.Model ) -> Html Msg
viewBox texts flags settings model ( index, box ) =
let
dropId =
DD.getDropId model.boxDragDrop
dragId =
DD.getDragId model.boxDragDrop
styles =
[ classList [ ( "opacity-40", dropId == Just index && dropId /= dragId ) ]
, class (spanStyle box.box)
]
in
div
(DD.draggable DragDropMsg index ++ DD.droppable DragDropMsg index ++ styles)
[ Html.map (BoxMsg index)
(Comp.BoxEdit.view texts.boxView flags settings box)
]
viewMain : Texts -> Flags -> UiSettings -> Model -> Html Msg
viewMain texts _ _ model =
let
columnsSettings =
{ display = String.fromInt
, icon = \_ -> Nothing
, selectPlaceholder = ""
, style = DS.mainStyle
}
in
div [ class "my-2 " ]
[ MB.view
{ start =
[ MB.PrimaryButton
{ tagger = SaveDashboard
, title = texts.basics.submitThisForm
, icon = Just "fa fa-save"
, label = texts.basics.submit
}
, MB.SecondaryButton
{ tagger = Cancel
, title = texts.basics.cancel
, icon = Just "fa fa-times"
, label = texts.basics.cancel
}
]
, end = []
, rootClasses = ""
}
, div [ class "flex flex-col" ]
[ div [ class "mt-2" ]
[ label [ class S.inputLabel ]
[ text texts.basics.name
]
, input
[ type_ "text"
, placeholder texts.namePlaceholder
, class S.textInput
, value (Maybe.withDefault "" model.nameValue)
, onInput SetName
]
[]
]
, div [ class "mt-2" ]
[ label [ class S.inputLabel ]
[ text texts.columns
]
]
, Html.map ColumnsMsg
(Comp.FixedDropdown.viewStyled2 columnsSettings
False
model.columnsValue
model.columnsModel
)
]
]
--- Helpers
gridStyle : Dashboard -> String
gridStyle db =
let
colStyle =
case db.columns of
1 ->
""
2 ->
"md:grid-cols-2"
3 ->
"md:grid-cols-3"
4 ->
"md:grid-cols-4"
_ ->
"md:grid-cols-5"
in
"grid gap-4 grid-cols-1 " ++ colStyle
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"

View File

@ -1,7 +1,6 @@
module Comp.DashboardView exposing (Model, Msg, init, reloadData, update, view, viewBox)
import Comp.BoxView
import Data.Box exposing (Box)
import Data.Dashboard exposing (Dashboard)
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)

View File

@ -0,0 +1,86 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Comp.ItemColumnDropdown exposing (Model, Msg, getSelected, init, update, view)
import Comp.Dropdown exposing (Option)
import Data.DropdownStyle
import Data.ItemColumn exposing (ItemColumn(..))
import Data.UiSettings exposing (UiSettings)
import Html exposing (Html)
import Messages.Comp.ItemColumnDropdown exposing (Texts)
type Model
= Model (Comp.Dropdown.Model ItemColumn)
type Msg
= DropdownMsg (Comp.Dropdown.Msg ItemColumn)
init : List ItemColumn -> Model
init selected =
Model <|
Comp.Dropdown.makeMultipleList
{ options = Data.ItemColumn.all, selected = selected }
getSelected : Model -> List ItemColumn
getSelected (Model dm) =
Comp.Dropdown.getSelected dm
--- Update
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
let
dmodel =
case model of
Model a ->
a
in
case msg of
DropdownMsg lm ->
let
( dm, dc ) =
Comp.Dropdown.update lm dmodel
in
( Model dm, Cmd.map DropdownMsg dc )
--- View
itemOption : Texts -> ItemColumn -> Option
itemOption texts item =
{ text = texts.column.label item
, additional = ""
}
view : Texts -> UiSettings -> Model -> Html Msg
view texts settings model =
let
viewSettings =
{ makeOption = itemOption texts
, placeholder = texts.placeholder
, labelColor = \_ -> \_ -> ""
, style = Data.DropdownStyle.mainStyle
}
dm =
case model of
Model a ->
a
in
Html.map DropdownMsg
(Comp.Dropdown.view2 viewSettings settings dm)

View File

@ -0,0 +1,36 @@
module Comp.ItemColumnView exposing (..)
import Api.Model.ItemLight exposing (ItemLight)
import Data.ItemColumn exposing (ItemColumn(..))
import Data.ItemTemplate exposing (TemplateContext)
import Data.UiSettings exposing (UiSettings)
import Html exposing (Attribute, Html, div, text)
import Html.Attributes exposing (class)
renderDiv :
TemplateContext
-> UiSettings
-> ItemColumn
-> List (Attribute msg)
-> ItemLight
-> Html msg
renderDiv ctx settings col attr item =
case col of
Tags ->
div attr
(List.map
(\t ->
div
[ class "label text-sm"
, class <| Data.UiSettings.tagColorString2 t settings
]
[ text t.name ]
)
item.tags
)
_ ->
div attr
[ text (Data.ItemColumn.renderString ctx col item)
]

View File

@ -308,18 +308,27 @@ makeButton btnType model =
makeCheckbox : CheckboxData msg -> Html msg
makeCheckbox model =
let
withId list =
if model.id == "" then
list
else
id model.id :: list
in
div [ class "" ]
[ label
[ class "inline-flex space-x-2 items-center"
, for model.id
]
[ input
[ type_ "checkbox"
, onCheck model.tagger
, checked model.value
, class S.checkboxInput
, id model.id
]
(withId
[ type_ "checkbox"
, onCheck model.tagger
, checked model.value
, class S.checkboxInput
]
)
[]
, span [ class "truncate" ]
[ text model.label

View File

@ -11,6 +11,7 @@ module Comp.PowerSearchInput exposing
, Msg
, ViewSettings
, init
, initWith
, isValid
, setSearchString
, update
@ -45,6 +46,15 @@ init =
}
initWith : String -> ( Model, Cmd Msg, Sub Msg )
initWith qstr =
let
result =
update (setSearchString qstr) init
in
( result.model, result.cmd, result.subs )
isValid : Model -> Bool
isValid model =
model.input /= Nothing && model.result.success