Bookmark queries scoped to user or collective

This commit is contained in:
eikek
2022-01-08 19:31:26 +01:00
parent f914aa723e
commit a50a0a9a1a
14 changed files with 767 additions and 7 deletions

View File

@ -2,7 +2,7 @@ version = "3.3.1"
preset = default
align.preset = some
runner.dialect = scala213
runner.dialect = scala213source3
maxColumn = 90

View File

@ -27,7 +27,10 @@ trait OClientSettings[F[_]] {
def deleteCollective(clientId: Ident, account: AccountId): F[Boolean]
def saveCollective(clientId: Ident, account: AccountId, data: Json): F[Unit]
def loadCollective(clientId: Ident, account: AccountId): F[Option[RClientSettingsCollective]]
def loadCollective(
clientId: Ident,
account: AccountId
): F[Option[RClientSettingsCollective]]
}

View File

@ -1923,6 +1923,9 @@ paths:
an identifier to a client application. It returns a JSON
structure. The server doesn't care about the actual data,
since it is meant to be interpreted by clients.
If there is nothing stored for the given `clientId` an empty
JSON object (`{}`) is returned!
security:
- authTokenHeader: []
responses:
@ -1994,6 +1997,9 @@ paths:
`clientId` is an identifier to a client application. It
returns a JSON structure. The server doesn't care about the
actual data, since it is meant to be interpreted by clients.
If there is nothing stored for the given `clientId` an empty
JSON object (`{}`) is returned!
security:
- authTokenHeader: []
responses:

View File

@ -53,7 +53,7 @@ object ClientSettingsRoutes {
data <- backend.clientSettings.loadUser(clientId, user.account)
res <- data match {
case Some(d) => Ok(d.settingsData)
case None => NotFound()
case None => Ok(Map.empty[String, String])
}
} yield res
@ -80,7 +80,7 @@ object ClientSettingsRoutes {
data <- backend.clientSettings.loadCollective(clientId, user.account)
res <- data match {
case Some(d) => Ok(d.settingsData)
case None => NotFound()
case None => Ok(Map.empty[String, String])
}
} yield res

View File

@ -6,7 +6,8 @@
module Api exposing
( addConcEquip
( addBookmark
, addConcEquip
, addConcPerson
, addCorrOrg
, addCorrPerson
@ -52,6 +53,7 @@ module Api exposing
, disableOtp
, fileURL
, getAttachmentMeta
, getBookmarks
, getClientSettings
, getCollective
, getCollectiveSettings
@ -120,6 +122,7 @@ module Api exposing
, restoreAllItems
, restoreItem
, sampleEvent
, saveBookmarks
, saveClientSettings
, searchShare
, searchShareStats
@ -260,6 +263,7 @@ import Api.Model.User exposing (User)
import Api.Model.UserList exposing (UserList)
import Api.Model.UserPass exposing (UserPass)
import Api.Model.VersionInfo exposing (VersionInfo)
import Data.BookmarkedQuery exposing (AllBookmarks, BookmarkedQuery, BookmarkedQueryDef, Bookmarks)
import Data.ContactType exposing (ContactType)
import Data.CustomFieldOrder exposing (CustomFieldOrder)
import Data.EquipmentOrder exposing (EquipmentOrder)
@ -2285,6 +2289,89 @@ saveClientSettings flags settings receive =
--- Query Bookmarks
type alias BookmarkLocation =
Data.BookmarkedQuery.Location
bookmarkLocationUri : Flags -> BookmarkLocation -> String
bookmarkLocationUri flags loc =
case loc of
Data.BookmarkedQuery.User ->
flags.config.baseUrl ++ "/api/v1/sec/clientSettings/user/webClientBookmarks"
Data.BookmarkedQuery.Collective ->
flags.config.baseUrl ++ "/api/v1/sec/clientSettings/collective/webClientBookmarks"
getBookmarksTask : Flags -> BookmarkLocation -> Task.Task Http.Error Bookmarks
getBookmarksTask flags loc =
Http2.authTask
{ method = "GET"
, url = bookmarkLocationUri flags loc
, account = getAccount flags
, body = Http.emptyBody
, resolver = Http2.jsonResolver Data.BookmarkedQuery.bookmarksDecoder
, headers = []
, timeout = Nothing
}
getBookmarksFor : Flags -> BookmarkLocation -> (Result Http.Error Bookmarks -> msg) -> Cmd msg
getBookmarksFor flags loc receive =
Task.attempt receive (getBookmarksTask flags loc)
getBookmarks : Flags -> (Result Http.Error AllBookmarks -> msg) -> Cmd msg
getBookmarks flags receive =
let
coll =
getBookmarksTask flags Data.BookmarkedQuery.Collective
user =
getBookmarksTask flags Data.BookmarkedQuery.User
combine bc bu =
AllBookmarks bc bu
in
Task.map2 combine coll user
|> Task.attempt receive
saveBookmarksTask : Flags -> BookmarkLocation -> Bookmarks -> Task.Task Http.Error BasicResult
saveBookmarksTask flags loc bookmarks =
Http2.authTask
{ method = "PUT"
, url = bookmarkLocationUri flags loc
, account = getAccount flags
, body = Http.jsonBody (Data.BookmarkedQuery.bookmarksEncode bookmarks)
, resolver = Http2.jsonResolver Api.Model.BasicResult.decoder
, headers = []
, timeout = Nothing
}
saveBookmarks : Flags -> Bookmarks -> BookmarkLocation -> (Result Http.Error BasicResult -> msg) -> Cmd msg
saveBookmarks flags bookmarks loc receive =
Task.attempt receive (saveBookmarksTask flags loc bookmarks)
addBookmark : Flags -> BookmarkedQueryDef -> (Result Http.Error BasicResult -> msg) -> Cmd msg
addBookmark flags model receive =
let
load =
getBookmarksTask flags model.location
add current =
Data.BookmarkedQuery.add model.query current
|> saveBookmarksTask flags model.location
in
Task.andThen add load |> Task.attempt receive
--- OTP

View File

@ -0,0 +1,179 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Comp.BookmarkQueryForm exposing (Model, Msg, get, init, initQuery, update, view)
import Comp.Basic as B
import Comp.PowerSearchInput
import Data.BookmarkedQuery exposing (BookmarkedQueryDef, Location(..))
import Data.Flags exposing (Flags)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onCheck, onInput)
import Messages.Comp.BookmarkQueryForm exposing (Texts)
import Styles as S
import Util.Maybe
type alias Model =
{ name : Maybe String
, queryModel : Comp.PowerSearchInput.Model
, location : Location
}
initQuery : String -> ( Model, Cmd Msg )
initQuery q =
let
res =
Comp.PowerSearchInput.update
(Comp.PowerSearchInput.setSearchString q)
Comp.PowerSearchInput.init
in
( { name = Nothing
, queryModel = res.model
, location = User
}
, Cmd.batch
[ Cmd.map QueryMsg res.cmd
]
)
init : ( Model, Cmd Msg )
init =
initQuery ""
isValid : Model -> Bool
isValid model =
Comp.PowerSearchInput.isValid model.queryModel
&& model.name
/= Nothing
get : Model -> Maybe BookmarkedQueryDef
get model =
let
qStr =
Maybe.withDefault "" model.queryModel.input
in
if isValid model then
Just
{ query =
{ query = qStr
, name = Maybe.withDefault "" model.name
}
, location = model.location
}
else
Nothing
type Msg
= SetName String
| QueryMsg Comp.PowerSearchInput.Msg
| SetLocation Location
update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
update _ msg model =
case msg of
SetName n ->
( { model | name = Util.Maybe.fromString n }, Cmd.none, Sub.none )
SetLocation loc ->
( { model | location = loc }, Cmd.none, Sub.none )
QueryMsg lm ->
let
res =
Comp.PowerSearchInput.update lm model.queryModel
in
( { model | queryModel = res.model }
, Cmd.map QueryMsg res.cmd
, Sub.map QueryMsg res.subs
)
--- View
view : Texts -> Model -> Html Msg
view texts model =
let
queryInput =
div
[ class "relative flex flex-grow flex-row" ]
[ Html.map QueryMsg
(Comp.PowerSearchInput.viewInput
{ placeholder = texts.queryLabel
, extraAttrs = []
}
model.queryModel
)
, Html.map QueryMsg
(Comp.PowerSearchInput.viewResult [] model.queryModel)
]
in
div
[ class "flex flex-col" ]
[ div [ class "mb-4" ]
[ label
[ for "sharename"
, class S.inputLabel
]
[ text texts.basics.name
, B.inputRequired
]
, input
[ type_ "text"
, onInput SetName
, placeholder texts.basics.name
, value <| Maybe.withDefault "" model.name
, id "sharename"
, class S.textInput
]
[]
]
, div [ class "flex flex-col mb-4 " ]
[ label [ class "inline-flex items-center" ]
[ input
[ type_ "radio"
, checked (model.location == User)
, onCheck (\_ -> SetLocation User)
, class S.radioInput
]
[]
, span [ class "ml-2" ] [ text texts.userLocation ]
, span [ class "ml-3 opacity-75 text-sm" ] [ text texts.userLocationText ]
]
, label [ class "inline-flex items-center" ]
[ input
[ type_ "radio"
, checked (model.location == Collective)
, class S.radioInput
, onCheck (\_ -> SetLocation Collective)
]
[]
, span [ class "ml-2" ] [ text texts.collectiveLocation ]
, span [ class "ml-3 opacity-75 text-sm" ] [ text texts.collectiveLocationText ]
]
]
, div [ class "mb-4" ]
[ label
[ for "sharequery"
, class S.inputLabel
]
[ text texts.queryLabel
, B.inputRequired
]
, queryInput
]
]

View File

@ -0,0 +1,173 @@
module Comp.BookmarkQueryManage exposing (..)
import Api
import Api.Model.BasicResult exposing (BasicResult)
import Comp.Basic as B
import Comp.BookmarkQueryForm
import Data.BookmarkedQuery exposing (BookmarkedQueryDef)
import Data.Flags exposing (Flags)
import Html exposing (Html, div, text)
import Html.Attributes exposing (class, classList, href)
import Html.Events exposing (onClick)
import Http
import Messages.Comp.BookmarkQueryManage exposing (Texts)
import Styles as S
type alias Model =
{ formModel : Comp.BookmarkQueryForm.Model
, loading : Bool
, formState : FormState
}
type FormState
= FormStateNone
| FormStateError Http.Error
| FormStateSaveError String
| FormStateInvalid
| FormStateSaved
init : String -> ( Model, Cmd Msg )
init query =
let
( fm, fc ) =
Comp.BookmarkQueryForm.initQuery query
in
( { formModel = fm
, loading = False
, formState = FormStateNone
}
, Cmd.map FormMsg fc
)
type Msg
= Submit
| Cancel
| FormMsg Comp.BookmarkQueryForm.Msg
| SaveResp (Result Http.Error BasicResult)
--- Update
type FormResult
= Submitted BookmarkedQueryDef
| Cancelled
| Done
| None
type alias UpdateResult =
{ model : Model
, cmd : Cmd Msg
, sub : Sub Msg
, outcome : FormResult
}
update : Flags -> Msg -> Model -> UpdateResult
update flags msg model =
let
empty =
{ model = model
, cmd = Cmd.none
, sub = Sub.none
, outcome = None
}
in
case msg of
FormMsg lm ->
let
( fm, fc, fs ) =
Comp.BookmarkQueryForm.update flags lm model.formModel
in
{ model = { model | formModel = fm }
, cmd = Cmd.map FormMsg fc
, sub = Sub.map FormMsg fs
, outcome = None
}
Submit ->
case Comp.BookmarkQueryForm.get model.formModel of
Just data ->
{ empty | cmd = save flags data, outcome = Submitted data, model = { model | loading = True } }
Nothing ->
{ empty | model = { model | formState = FormStateInvalid } }
Cancel ->
{ model = model
, cmd = Cmd.none
, sub = Sub.none
, outcome = Cancelled
}
SaveResp (Ok res) ->
if res.success then
{ empty | model = { model | loading = False, formState = FormStateSaved }, outcome = Done }
else
{ empty | model = { model | loading = False, formState = FormStateSaveError res.message } }
SaveResp (Err err) ->
{ empty | model = { model | loading = False, formState = FormStateError err } }
save : Flags -> BookmarkedQueryDef -> Cmd Msg
save flags model =
Api.addBookmark flags model SaveResp
--- View
view : Texts -> Model -> Html Msg
view texts model =
div [ class "relative" ]
[ B.loadingDimmer { label = "", active = model.loading }
, Html.map FormMsg (Comp.BookmarkQueryForm.view texts.form model.formModel)
, case model.formState of
FormStateNone ->
div [ class "hidden" ] []
FormStateError err ->
div [ class S.errorMessage ]
[ text <| texts.httpError err
]
FormStateInvalid ->
div [ class S.errorMessage ]
[ text texts.formInvalid
]
FormStateSaveError m ->
div [ class S.errorMessage ]
[ text m
]
FormStateSaved ->
div [ class S.successMessage ]
[ text texts.saved
]
, div [ class "flex flex-row space-x-2 py-2" ]
[ B.primaryButton
{ label = texts.basics.submit
, icon = "fa fa-save"
, disabled = False
, handler = onClick Submit
, attrs = [ href "#" ]
}
, B.secondaryButton
{ label = texts.basics.cancel
, icon = "fa fa-times"
, disabled = False
, handler = onClick Cancel
, attrs = [ href "#" ]
}
]
]

View File

@ -0,0 +1,114 @@
module Data.BookmarkedQuery exposing
( AllBookmarks
, BookmarkedQuery
, BookmarkedQueryDef
, Bookmarks
, Location(..)
, add
, bookmarksDecoder
, bookmarksEncode
, emptyBookmarks
, exists
, remove
)
import Json.Decode as D
import Json.Encode as E
type Location
= User
| Collective
type alias BookmarkedQuery =
{ name : String
, query : String
}
bookmarkedQueryDecoder : D.Decoder BookmarkedQuery
bookmarkedQueryDecoder =
D.map2 BookmarkedQuery
(D.field "name" D.string)
(D.field "query" D.string)
bookmarkedQueryEncode : BookmarkedQuery -> E.Value
bookmarkedQueryEncode bq =
E.object
[ ( "name", E.string bq.name )
, ( "query", E.string bq.query )
]
type alias BookmarkedQueryDef =
{ query : BookmarkedQuery
, location : Location
}
type Bookmarks
= Bookmarks (List BookmarkedQuery)
emptyBookmarks : Bookmarks
emptyBookmarks =
Bookmarks []
type alias AllBookmarks =
{ collective : Bookmarks
, user : Bookmarks
}
{-| Checks wether a bookmark of this name already exists.
-}
exists : String -> Bookmarks -> Bool
exists name bookmarks =
case bookmarks of
Bookmarks list ->
List.any (\b -> b.name == name) list
remove : String -> Bookmarks -> Bookmarks
remove name bookmarks =
case bookmarks of
Bookmarks list ->
Bookmarks <| List.filter (\b -> b.name /= name) list
sortByName : Bookmarks -> Bookmarks
sortByName bm =
case bm of
Bookmarks all ->
Bookmarks <| List.sortBy .name all
add : BookmarkedQuery -> Bookmarks -> Bookmarks
add query bookmarks =
case remove query.name bookmarks of
Bookmarks all ->
sortByName (Bookmarks (query :: all))
bookmarksDecoder : D.Decoder Bookmarks
bookmarksDecoder =
D.maybe
(D.field "bookmarks"
(D.list bookmarkedQueryDecoder
|> D.map Bookmarks
|> D.map sortByName
)
)
|> D.map (Maybe.withDefault emptyBookmarks)
bookmarksEncode : Bookmarks -> E.Value
bookmarksEncode bookmarks =
case bookmarks of
Bookmarks all ->
E.object
[ ( "bookmarks", E.list bookmarkedQueryEncode all )
]

View File

@ -0,0 +1,46 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Messages.Comp.BookmarkQueryForm exposing
( Texts
, de
, gb
)
import Messages.Basics
type alias Texts =
{ basics : Messages.Basics.Texts
, queryLabel : String
, userLocation : String
, userLocationText : String
, collectiveLocation : String
, collectiveLocationText : String
}
gb : Texts
gb =
{ basics = Messages.Basics.gb
, queryLabel = "Query"
, userLocation = "User scope"
, userLocationText = "The bookmarked query is just for you"
, collectiveLocation = "Collective scope"
, collectiveLocationText = "The bookmarked query can be used and edited by all users"
}
de : Texts
de =
{ basics = Messages.Basics.de
, queryLabel = "Abfrage"
, userLocation = "Persönliches Bookmark"
, userLocationText = "Der Bookmark ist nur für dich"
, collectiveLocation = "Kollektiv-Bookmark"
, collectiveLocationText = "Der Bookmark kann von allen Benutzer verwendet werden"
}

View File

@ -0,0 +1,46 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Messages.Comp.BookmarkQueryManage exposing
( Texts
, de
, gb
)
import Http
import Messages.Basics
import Messages.Comp.BookmarkQueryForm
import Messages.Comp.HttpError
type alias Texts =
{ basics : Messages.Basics.Texts
, form : Messages.Comp.BookmarkQueryForm.Texts
, httpError : Http.Error -> String
, formInvalid : String
, saved : String
}
gb : Texts
gb =
{ basics = Messages.Basics.gb
, form = Messages.Comp.BookmarkQueryForm.gb
, httpError = Messages.Comp.HttpError.gb
, formInvalid = "Please correct errors in the form"
, saved = "Bookmark saved"
}
de : Texts
de =
{ basics = Messages.Basics.de
, form = Messages.Comp.BookmarkQueryForm.de
, httpError = Messages.Comp.HttpError.de
, formInvalid = "Bitte korrigiere das Formular"
, saved = "Bookmark gespeichert"
}

View File

@ -12,6 +12,7 @@ module Messages.Page.Home exposing
)
import Messages.Basics
import Messages.Comp.BookmarkQueryManage
import Messages.Comp.ItemCardList
import Messages.Comp.ItemMerge
import Messages.Comp.PublishItems
@ -26,6 +27,7 @@ type alias Texts =
, sideMenu : Messages.Page.HomeSideMenu.Texts
, itemMerge : Messages.Comp.ItemMerge.Texts
, publishItems : Messages.Comp.PublishItems.Texts
, bookmarkManage : Messages.Comp.BookmarkQueryManage.Texts
, contentSearch : String
, searchInNames : String
, selectModeTitle : String
@ -46,6 +48,7 @@ type alias Texts =
, mergeItemsTitle : Int -> String
, publishItemsTitle : Int -> String
, publishCurrentQueryTitle : String
, shareResults : String
, nothingSelectedToShare : String
, loadMore : String
, thatsAll : String
@ -53,6 +56,8 @@ type alias Texts =
, listView : String
, tileView : String
, expandCollapseRows : String
, bookmarkQuery : String
, nothingToBookmark : String
}
@ -64,6 +69,7 @@ gb =
, sideMenu = Messages.Page.HomeSideMenu.gb
, itemMerge = Messages.Comp.ItemMerge.gb
, publishItems = Messages.Comp.PublishItems.gb
, bookmarkManage = Messages.Comp.BookmarkQueryManage.gb
, contentSearch = "Content search"
, searchInNames = "Search in names"
, selectModeTitle = "Select Mode"
@ -84,6 +90,7 @@ gb =
, mergeItemsTitle = \n -> "Merge " ++ String.fromInt n ++ " selected items"
, publishItemsTitle = \n -> "Publish " ++ String.fromInt n ++ " selected items"
, publishCurrentQueryTitle = "Publish current results"
, shareResults = "Share Results"
, nothingSelectedToShare = "Sharing everything doesn't work. You need to apply some criteria."
, loadMore = "Load more"
, thatsAll = "That's all"
@ -91,6 +98,8 @@ gb =
, listView = "List view"
, tileView = "Tile view"
, expandCollapseRows = "Expand/Collapse all"
, bookmarkQuery = "Bookmark query"
, nothingToBookmark = "Nothing selected to bookmark"
}
@ -102,6 +111,7 @@ de =
, sideMenu = Messages.Page.HomeSideMenu.de
, itemMerge = Messages.Comp.ItemMerge.de
, publishItems = Messages.Comp.PublishItems.de
, bookmarkManage = Messages.Comp.BookmarkQueryManage.de
, contentSearch = "Volltextsuche"
, searchInNames = "Suche in Namen"
, selectModeTitle = "Auswahlmodus"
@ -122,6 +132,7 @@ de =
, mergeItemsTitle = \n -> String.fromInt n ++ " gewählte Dokumente zusammenführen"
, publishItemsTitle = \n -> String.fromInt n ++ " gewählte Dokumente publizieren"
, publishCurrentQueryTitle = "Aktuelle Ansicht publizieren"
, shareResults = "Ergebnisse teilen"
, nothingSelectedToShare = "Alles kann nicht geteilt werden; es muss etwas gesucht werden."
, loadMore = "Mehr laden"
, thatsAll = "Mehr gibt es nicht"
@ -129,4 +140,6 @@ de =
, listView = "Listenansicht"
, tileView = "Kachelansicht"
, expandCollapseRows = "Alle ein-/ausklappen"
, bookmarkQuery = "Abfrage merken"
, nothingToBookmark = "Keine Abfrage vorhanden"
}

View File

@ -13,6 +13,7 @@ module Page.Home.Data exposing
, SearchType(..)
, SelectActionMode(..)
, SelectViewModel
, TopWidgetModel(..)
, ViewMode(..)
, createQuery
, doSearchCmd
@ -30,6 +31,7 @@ import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.ItemLightList exposing (ItemLightList)
import Api.Model.SearchStats exposing (SearchStats)
import Browser.Dom as Dom
import Comp.BookmarkQueryManage
import Comp.ItemCardList
import Comp.ItemDetail.FormChange exposing (FormChange)
import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..))
@ -68,9 +70,15 @@ type alias Model =
, powerSearchInput : Comp.PowerSearchInput.Model
, viewMenuOpen : Bool
, itemRowsOpen : Set String
, topWidgetModel : TopWidgetModel
}
type TopWidgetModel
= TopWidgetHidden
| BookmarkQuery Comp.BookmarkQueryManage.Model
type ConfirmModalValue
= ConfirmReprocessItems
| ConfirmDelete
@ -137,6 +145,7 @@ init flags viewMode =
, powerSearchInput = Comp.PowerSearchInput.init
, viewMenuOpen = False
, itemRowsOpen = Set.empty
, topWidgetModel = TopWidgetHidden
}
@ -238,6 +247,8 @@ type Msg
| ToggleShowGroups
| ToggleArrange ItemArrange
| ToggleExpandCollapseRows
| ToggleBookmarkCurrentQueryView
| BookmarkQueryMsg Comp.BookmarkQueryManage.Msg
type SearchType

View File

@ -13,6 +13,7 @@ module Page.Home.Update exposing
import Api
import Api.Model.ItemLightList exposing (ItemLightList)
import Browser.Navigation as Nav
import Comp.BookmarkQueryManage
import Comp.ItemCardList
import Comp.ItemDetail.FormChange exposing (FormChange(..))
import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..))
@ -927,6 +928,54 @@ update mId key flags texts settings msg model =
Nothing ->
noSub ( model, Cmd.none )
ToggleBookmarkCurrentQueryView ->
case createQuery model of
Just q ->
case model.topWidgetModel of
BookmarkQuery _ ->
noSub ( { model | topWidgetModel = TopWidgetHidden, viewMenuOpen = False }, Cmd.none )
TopWidgetHidden ->
let
( qm, qc ) =
Comp.BookmarkQueryManage.init (Q.render q)
in
noSub
( { model | topWidgetModel = BookmarkQuery qm, viewMenuOpen = False }
, Cmd.map BookmarkQueryMsg qc
)
Nothing ->
noSub ( model, Cmd.none )
BookmarkQueryMsg lm ->
case model.topWidgetModel of
BookmarkQuery bm ->
let
res =
Comp.BookmarkQueryManage.update flags lm bm
nextModel =
if
res.outcome
== Comp.BookmarkQueryManage.Cancelled
|| res.outcome
== Comp.BookmarkQueryManage.Done
then
TopWidgetHidden
else
BookmarkQuery res.model
in
makeResult
( { model | topWidgetModel = nextModel }
, Cmd.map BookmarkQueryMsg res.cmd
, Sub.map BookmarkQueryMsg res.sub
)
TopWidgetHidden ->
noSub ( model, Cmd.none )
PublishViewMsg lmsg ->
case model.viewMode of
PublishView inPM ->

View File

@ -9,6 +9,7 @@ module Page.Home.View2 exposing (viewContent, viewSidebar)
import Api
import Comp.Basic as B
import Comp.BookmarkQueryManage
import Comp.ConfirmModal
import Comp.ItemCardList
import Comp.ItemMerge
@ -103,7 +104,21 @@ mainView texts flags settings model =
body
Nothing ->
itemCardList texts flags settings model
bookmarkQueryWidget texts settings flags model
++ itemCardList texts flags settings model
bookmarkQueryWidget : Texts -> UiSettings -> Flags -> Model -> List (Html Msg)
bookmarkQueryWidget texts settings flags model =
case model.topWidgetModel of
BookmarkQuery m ->
[ div [ class "px-2 mb-4 border-l border-r border-b dark:border-slate-600" ]
[ Html.map BookmarkQueryMsg (Comp.BookmarkQueryManage.view texts.bookmarkManage m)
]
]
TopWidgetHidden ->
[]
itemPublishView : Texts -> UiSettings -> Flags -> SelectViewModel -> List (Html Msg)
@ -354,7 +369,7 @@ defaultMenuBar texts flags settings model =
]
}
, menuSep
, { label = "Share Results"
, { label = texts.shareResults
, icon = Icons.shareIcon ""
, disabled = createQuery model == Nothing
, attrs =
@ -372,6 +387,24 @@ defaultMenuBar texts flags settings model =
onClick TogglePublishCurrentQueryView
]
}
, { label = texts.bookmarkQuery
, icon = i [ class "fa fa-bookmark" ] []
, disabled = createQuery model == Nothing
, attrs =
[ title <|
if createQuery model == Nothing then
texts.nothingToBookmark
else
texts.bookmarkQuery
, href "#"
, if createQuery model == Nothing then
class ""
else
onClick ToggleBookmarkCurrentQueryView
]
}
, { label =
if settings.cardPreviewFullWidth then
texts.fullHeightPreviewTitle