Select bookmarks in search menu

This commit is contained in:
eikek 2022-01-09 00:43:41 +01:00
parent 04b258689f
commit a5b70962d8
8 changed files with 413 additions and 58 deletions

View File

@ -2334,10 +2334,16 @@ getBookmarks flags receive =
user =
getBookmarksTask flags Data.BookmarkedQuery.User
combine bc bu =
AllBookmarks bc bu
shares =
getSharesTask flags "" False
activeShare s =
s.enabled && s.name /= Nothing
combine bc bu bs =
AllBookmarks bc bu (List.filter activeShare bs.items)
in
Task.map2 combine coll user
Task.map3 combine coll user shares
|> Task.attempt receive
@ -2436,10 +2442,12 @@ disableOtp flags otp receive =
--- Share
getShares : Flags -> String -> Bool -> (Result Http.Error ShareList -> msg) -> Cmd msg
getShares flags query owning receive =
Http2.authGet
{ url =
getSharesTask : Flags -> String -> Bool -> Task.Task Http.Error ShareList
getSharesTask flags query owning =
Http2.authTask
{ method =
"GET"
, url =
flags.config.baseUrl
++ "/api/v1/sec/share?q="
++ Url.percentEncode query
@ -2450,10 +2458,18 @@ getShares flags query owning receive =
""
)
, account = getAccount flags
, expect = Http.expectJson receive Api.Model.ShareList.decoder
, body = Http.emptyBody
, resolver = Http2.jsonResolver Api.Model.ShareList.decoder
, headers = []
, timeout = Nothing
}
getShares : Flags -> String -> Bool -> (Result Http.Error ShareList -> msg) -> Cmd msg
getShares flags query owning receive =
getSharesTask flags query owning |> Task.attempt receive
getShare : Flags -> String -> (Result Http.Error ShareDetail -> msg) -> Cmd msg
getShare flags id receive =
Http2.authGet

View File

@ -0,0 +1,202 @@
module Comp.BookmarkChooser exposing
( Model
, Msg
, Selection
, emptySelection
, getQueries
, init
, isEmpty
, isEmptySelection
, update
, view
)
import Api.Model.ShareDetail exposing (ShareDetail)
import Data.BookmarkedQuery exposing (AllBookmarks, BookmarkedQuery)
import Data.Icons as Icons
import Html exposing (Html, a, div, i, span, text)
import Html.Attributes exposing (class, classList, href)
import Html.Events exposing (onClick)
import Messages.Comp.BookmarkChooser exposing (Texts)
import Set exposing (Set)
type alias Model =
{ all : AllBookmarks
}
init : AllBookmarks -> Model
init all =
{ all = all
}
isEmpty : Model -> Bool
isEmpty model =
model.all == Data.BookmarkedQuery.allBookmarksEmpty
type alias Selection =
{ user : Set String
, collective : Set String
, shares : Set String
}
emptySelection : Selection
emptySelection =
{ user = Set.empty, collective = Set.empty, shares = Set.empty }
isEmptySelection : Selection -> Bool
isEmptySelection sel =
sel == emptySelection
type Kind
= User
| Collective
| Share
type Msg
= Toggle Kind String
getQueries : Model -> Selection -> List BookmarkedQuery
getQueries model sel =
let
member set bm =
Set.member bm.name set
filterBookmarks f bms =
Data.BookmarkedQuery.filter f bms |> Data.BookmarkedQuery.map identity
in
List.concat
[ filterBookmarks (member sel.user) model.all.user
, filterBookmarks (member sel.collective) model.all.collective
, List.map shareToBookmark model.all.shares
|> List.filter (member sel.shares)
]
--- Update
update : Msg -> Model -> Selection -> ( Model, Selection )
update msg model current =
let
toggle name set =
if Set.member name set then
Set.remove name set
else
Set.insert name set
in
case msg of
Toggle kind name ->
case kind of
User ->
( model, { current | user = toggle name current.user } )
Collective ->
( model, { current | collective = toggle name current.collective } )
Share ->
( model, { current | shares = toggle name current.shares } )
--- View
view : Texts -> Model -> Selection -> Html Msg
view texts model selection =
div [ class "flex flex-col" ]
[ userBookmarks texts model selection
, collBookmarks texts model selection
, shares texts model selection
]
userBookmarks : Texts -> Model -> Selection -> Html Msg
userBookmarks texts model sel =
div
[ class "mb-2"
, classList [ ( "hidden", Data.BookmarkedQuery.emptyBookmarks == model.all.user ) ]
]
[ div [ class " text-sm font-semibold py-0.5 " ]
[ text texts.userLabel
]
, div [ class "flex flex-col space-y-2 md:space-y-1" ]
(Data.BookmarkedQuery.map (mkItem "fa fa-bookmark" sel User) model.all.user)
]
collBookmarks : Texts -> Model -> Selection -> Html Msg
collBookmarks texts model sel =
div
[ class "mb-2"
, classList [ ( "hidden", Data.BookmarkedQuery.emptyBookmarks == model.all.collective ) ]
]
[ div [ class " text-sm font-semibold py-0.5 " ]
[ text texts.collectiveLabel
]
, div [ class "flex flex-col space-y-2 md:space-y-1" ]
(Data.BookmarkedQuery.map (mkItem "fa fa-bookmark font-light" sel Collective) model.all.collective)
]
shares : Texts -> Model -> Selection -> Html Msg
shares texts model sel =
let
bms =
List.map shareToBookmark model.all.shares
in
div
[ class ""
, classList [ ( "hidden", List.isEmpty bms ) ]
]
[ div [ class " text-sm font-semibold py-0.5 " ]
[ text texts.shareLabel
]
, div [ class "flex flex-col space-y-2 md:space-y-1" ]
(List.map (mkItem Icons.share sel Share) bms)
]
mkItem : String -> Selection -> Kind -> BookmarkedQuery -> Html Msg
mkItem icon sel kind bm =
a
[ class "flex flex-row items-center rounded px-1 py-1 hover:bg-blue-100 dark:hover:bg-slate-600"
, href "#"
, onClick (Toggle kind bm.name)
]
[ if isSelected sel kind bm.name then
i [ class "fa fa-check" ] []
else
i [ class icon ] []
, span [ class "ml-2" ] [ text bm.name ]
]
isSelected : Selection -> Kind -> String -> Bool
isSelected sel kind name =
Set.member name <|
case kind of
User ->
sel.user
Collective ->
sel.collective
Share ->
sel.shares
shareToBookmark : ShareDetail -> BookmarkedQuery
shareToBookmark share =
BookmarkedQuery (Maybe.withDefault "-" share.name) share.query

View File

@ -16,6 +16,7 @@ module Comp.SearchMenu exposing
, isFulltextSearch
, isNamesSearch
, linkTargetMsg
, refreshBookmarks
, setFromStats
, textSearchString
, update
@ -33,6 +34,7 @@ import Api.Model.ItemQuery exposing (ItemQuery)
import Api.Model.PersonList exposing (PersonList)
import Api.Model.ReferenceList exposing (ReferenceList)
import Api.Model.SearchStats exposing (SearchStats)
import Comp.BookmarkChooser
import Comp.CustomFieldMultiInput
import Comp.DatePicker
import Comp.Dropdown exposing (isDropdownChangeMsg)
@ -41,6 +43,7 @@ import Comp.LinkTarget exposing (LinkTarget)
import Comp.MenuBar as MB
import Comp.Tabs
import Comp.TagSelect
import Data.BookmarkedQuery exposing (AllBookmarks)
import Data.CustomFieldChange exposing (CustomFieldValueCollect)
import Data.Direction exposing (Direction)
import Data.DropdownStyle as DS
@ -96,6 +99,8 @@ type alias Model =
, customFieldModel : Comp.CustomFieldMultiInput.Model
, customValues : CustomFieldValueCollect
, sourceModel : Maybe String
, allBookmarks : Comp.BookmarkChooser.Model
, selectedBookmarks : Comp.BookmarkChooser.Selection
, openTabs : Set String
, searchMode : SearchMode
}
@ -141,6 +146,8 @@ init flags =
, customFieldModel = Comp.CustomFieldMultiInput.initWith []
, customValues = Data.CustomFieldChange.emptyCollect
, sourceModel = Nothing
, allBookmarks = Comp.BookmarkChooser.init Data.BookmarkedQuery.allBookmarksEmpty
, selectedBookmarks = Comp.BookmarkChooser.emptySelection
, openTabs = Set.fromList [ "Tags", "Inbox" ]
, searchMode = Data.SearchMode.Normal
}
@ -243,6 +250,10 @@ getItemQuery model =
textSearch =
textSearchValue model.textSearchModel
bookmarks =
List.map .query (Comp.BookmarkChooser.getQueries model.allBookmarks model.selectedBookmarks)
|> List.map Q.Fragment
in
Q.and
[ when model.inboxCheckbox (Q.Inbox True)
@ -289,6 +300,7 @@ getItemQuery model =
|> Maybe.map Q.Dir
, textSearch.fullText
|> Maybe.map Q.Contents
, whenNotEmpty bookmarks Q.And
]
@ -333,6 +345,7 @@ resetModel model =
model.customFieldModel
, customValues = Data.CustomFieldChange.emptyCollect
, sourceModel = Nothing
, selectedBookmarks = Comp.BookmarkChooser.emptySelection
, searchMode = Data.SearchMode.Normal
}
@ -380,6 +393,8 @@ type Msg
| GetAllTagsResp (Result Http.Error SearchStats)
| ToggleAkkordionTab String
| ToggleOpenAllAkkordionTabs
| AllBookmarksResp (Result Http.Error AllBookmarks)
| SelectBookmarkMsg Comp.BookmarkChooser.Msg
setFromStats : SearchStats -> Msg
@ -426,6 +441,11 @@ type alias NextState =
}
refreshBookmarks : Flags -> Cmd Msg
refreshBookmarks flags =
Api.getBookmarks flags AllBookmarksResp
update : Flags -> UiSettings -> Msg -> Model -> NextState
update =
updateDrop DD.init
@ -488,6 +508,7 @@ updateDrop ddm flags settings msg model =
, Api.getPersons flags "" Data.PersonOrder.NameAsc GetPersonResp
, Cmd.map CustomFieldMsg (Comp.CustomFieldMultiInput.initCmd flags)
, cdp
, Api.getBookmarks flags AllBookmarksResp
]
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
@ -1040,6 +1061,31 @@ updateDrop ddm flags settings msg model =
, dragDrop = DD.DragDropData ddm Nothing
}
AllBookmarksResp (Ok bm) ->
{ model = { model | allBookmarks = Comp.BookmarkChooser.init bm }
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
AllBookmarksResp (Err err) ->
{ model = model
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
SelectBookmarkMsg lm ->
let
( next, sel ) =
Comp.BookmarkChooser.update lm model.allBookmarks model.selectedBookmarks
in
{ model = { model | allBookmarks = next, selectedBookmarks = sel }
, cmd = Cmd.none
, stateChange = sel /= model.selectedBookmarks
, dragDrop = DD.DragDropData ddm Nothing
}
--- View2
@ -1064,6 +1110,7 @@ viewDrop2 texts ddd flags cfg settings model =
type SearchTab
= TabInbox
| TabBookmarks
| TabTags
| TabTagCategories
| TabFolder
@ -1080,6 +1127,7 @@ type SearchTab
allTabs : List SearchTab
allTabs =
[ TabInbox
, TabBookmarks
, TabTags
, TabTagCategories
, TabFolder
@ -1100,6 +1148,9 @@ tabName tab =
TabInbox ->
"inbox"
TabBookmarks ->
"bookmarks"
TabTags ->
"tags"
@ -1140,6 +1191,9 @@ findTab tab =
"inbox" ->
Just TabInbox
"bookmarks" ->
Just TabBookmarks
"tags" ->
Just TabTags
@ -1215,6 +1269,16 @@ tabLook settings model tab =
TabInbox ->
activeWhen model.inboxCheckbox
TabBookmarks ->
if Comp.BookmarkChooser.isEmpty model.allBookmarks then
Comp.Tabs.Hidden
else if not <| Comp.BookmarkChooser.isEmptySelection model.selectedBookmarks then
Comp.Tabs.Active
else
Comp.Tabs.Normal
TabTags ->
hiddenOr [ Data.Fields.Tag ]
(activeWhenNotEmpty model.tagSelection.includeTags model.tagSelection.excludeTags)
@ -1329,52 +1393,15 @@ searchTabs texts ddd flags settings model =
, label = texts.inbox
, tagger = \_ -> ToggleInbox
}
, div [ class "mt-2 hidden" ]
[ label [ class S.inputLabel ]
[ text
(case model.textSearchModel of
Fulltext _ ->
texts.fulltextSearch
Names _ ->
texts.searchInNames
)
, a
[ classList
[ ( "hidden", not flags.config.fullTextSearchEnabled )
]
, class "float-right"
, class S.link
, href "#"
, onClick SwapTextSearch
, title texts.switchSearchModes
]
[ i [ class "fa fa-exchange-alt" ] []
]
]
, input
[ type_ "text"
, onInput SetTextSearch
, Util.Html.onKeyUpCode KeyUpMsg
, textSearchString model.textSearchModel |> Maybe.withDefault "" |> value
, case model.textSearchModel of
Fulltext _ ->
placeholder texts.contentSearch
Names _ ->
placeholder texts.searchInNamesPlaceholder
, class S.textInputSidebar
]
[]
, span [ class "opacity-50 text-sm" ]
[ case model.textSearchModel of
Fulltext _ ->
text texts.fulltextSearchInfo
Names _ ->
text texts.nameSearchInfo
]
]
]
}
, { name = tabName TabBookmarks
, title = texts.bookmarks
, titleRight = []
, info = Nothing
, body =
[ Html.map SelectBookmarkMsg
(Comp.BookmarkChooser.view texts.bookmarkChooser model.allBookmarks model.selectedBookmarks)
]
}
, { name = tabName TabTags

View File

@ -5,13 +5,17 @@ module Data.BookmarkedQuery exposing
, Bookmarks
, Location(..)
, add
, allBookmarksEmpty
, bookmarksDecoder
, bookmarksEncode
, emptyBookmarks
, exists
, filter
, map
, remove
)
import Api.Model.ShareDetail exposing (ShareDetail)
import Json.Decode as D
import Json.Encode as E
@ -52,6 +56,20 @@ type Bookmarks
= Bookmarks (List BookmarkedQuery)
map : (BookmarkedQuery -> a) -> Bookmarks -> List a
map f bms =
case bms of
Bookmarks items ->
List.map f items
filter : (BookmarkedQuery -> Bool) -> Bookmarks -> Bookmarks
filter f bms =
case bms of
Bookmarks items ->
Bookmarks <| List.filter f items
emptyBookmarks : Bookmarks
emptyBookmarks =
Bookmarks []
@ -60,9 +78,15 @@ emptyBookmarks =
type alias AllBookmarks =
{ collective : Bookmarks
, user : Bookmarks
, shares : List ShareDetail
}
allBookmarksEmpty : AllBookmarks
allBookmarksEmpty =
AllBookmarks emptyBookmarks emptyBookmarks []
{-| Checks wether a bookmark of this name already exists.
-}
exists : String -> Bookmarks -> Bool

View File

@ -71,7 +71,7 @@ and list =
Nothing
es ->
Just (And es)
Just (unwrap (And es))
request : SearchMode -> Maybe ItemQuery -> RQ.ItemQuery
@ -90,6 +90,32 @@ renderMaybe mq =
|> Maybe.withDefault ""
unwrap : ItemQuery -> ItemQuery
unwrap query =
case query of
And inner ->
case inner of
first :: [] ->
unwrap first
_ ->
And (List.map unwrap inner)
Or inner ->
case inner of
first :: [] ->
unwrap first
_ ->
Or (List.map unwrap inner)
Not (Not inner) ->
unwrap inner
_ ->
query
render : ItemQuery -> String
render q =
let
@ -118,7 +144,7 @@ render q =
String.replace "\"" "\\\""
>> surround "\""
in
case q of
case unwrap q of
And inner ->
List.map render inner
|> String.join " "

View File

@ -0,0 +1,40 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Messages.Comp.BookmarkChooser exposing
( Texts
, de
, gb
)
import Messages.Basics
type alias Texts =
{ basics : Messages.Basics.Texts
, userLabel : String
, collectiveLabel : String
, shareLabel : String
}
gb : Texts
gb =
{ basics = Messages.Basics.gb
, userLabel = "Personal"
, collectiveLabel = "Collective"
, shareLabel = "Shares"
}
de : Texts
de =
{ basics = Messages.Basics.de
, userLabel = "Persönlich"
, collectiveLabel = "Kollektiv"
, shareLabel = "Freigaben"
}

View File

@ -13,6 +13,7 @@ module Messages.Comp.SearchMenu exposing
import Data.Direction exposing (Direction)
import Messages.Basics
import Messages.Comp.BookmarkChooser
import Messages.Comp.CustomFieldMultiInput
import Messages.Comp.FolderSelect
import Messages.Comp.TagSelect
@ -24,6 +25,7 @@ type alias Texts =
, customFieldMultiInput : Messages.Comp.CustomFieldMultiInput.Texts
, tagSelect : Messages.Comp.TagSelect.Texts
, folderSelect : Messages.Comp.FolderSelect.Texts
, bookmarkChooser : Messages.Comp.BookmarkChooser.Texts
, chooseDirection : String
, choosePerson : String
, chooseEquipment : String
@ -47,6 +49,7 @@ type alias Texts =
, searchInItemSource : String
, direction : Direction -> String
, trashcan : String
, bookmarks : String
}
@ -56,6 +59,7 @@ gb =
, customFieldMultiInput = Messages.Comp.CustomFieldMultiInput.gb
, tagSelect = Messages.Comp.TagSelect.gb
, folderSelect = Messages.Comp.FolderSelect.gb
, bookmarkChooser = Messages.Comp.BookmarkChooser.gb
, chooseDirection = "Choose a direction"
, choosePerson = "Choose a person"
, chooseEquipment = "Choose an equipment"
@ -79,6 +83,7 @@ gb =
, searchInItemSource = "Search in item source"
, direction = Messages.Data.Direction.gb
, trashcan = "Trash"
, bookmarks = "Bookmarks"
}
@ -88,6 +93,7 @@ de =
, customFieldMultiInput = Messages.Comp.CustomFieldMultiInput.de
, tagSelect = Messages.Comp.TagSelect.de
, folderSelect = Messages.Comp.FolderSelect.de
, bookmarkChooser = Messages.Comp.BookmarkChooser.de
, chooseDirection = "Wähle eine Richtung"
, choosePerson = "Wähle eine Person"
, chooseEquipment = "Wähle eine Ausstattung"
@ -111,4 +117,5 @@ de =
, searchInItemSource = "Suche in Dokumentquelle"
, direction = Messages.Data.Direction.de
, trashcan = "Papierkorb"
, bookmarks = "Bookmarks"
}

View File

@ -966,10 +966,20 @@ update mId key flags texts settings msg model =
else
BookmarkQuery res.model
refreshCmd =
if res.outcome == Comp.BookmarkQueryManage.Done then
Cmd.map SearchMenuMsg (Comp.SearchMenu.refreshBookmarks flags)
else
Cmd.none
in
makeResult
( { model | topWidgetModel = nextModel }
, Cmd.map BookmarkQueryMsg res.cmd
, Cmd.batch
[ Cmd.map BookmarkQueryMsg res.cmd
, refreshCmd
]
, Sub.map BookmarkQueryMsg res.sub
)
@ -991,7 +1001,10 @@ update mId key flags texts settings msg model =
)
Comp.PublishItems.OutcomeDone ->
noSub ( { model | viewMode = SearchView }, Cmd.none )
noSub
( { model | viewMode = SearchView }
, Cmd.map SearchMenuMsg (Comp.SearchMenu.refreshBookmarks flags)
)
_ ->
noSub ( model, Cmd.none )