mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-02-15 20:33:26 +00:00
Instead of client only, make bookmarks a server aware feature
Makes it much more useful
This commit is contained in:
parent
063ae56488
commit
9415f72ec0
@ -49,6 +49,7 @@ trait BackendApp[F[_]] {
|
||||
def pubSub: PubSubT[F]
|
||||
def events: EventExchange[F]
|
||||
def notification: ONotification[F]
|
||||
def bookmarks: OQueryBookmarks[F]
|
||||
}
|
||||
|
||||
object BackendApp {
|
||||
@ -89,6 +90,7 @@ object BackendApp {
|
||||
OShare(store, itemSearchImpl, simpleSearchImpl, javaEmil)
|
||||
)
|
||||
notifyImpl <- ONotification(store, notificationMod)
|
||||
bookmarksImpl <- OQueryBookmarks(store)
|
||||
} yield new BackendApp[F] {
|
||||
val pubSub = pubSubT
|
||||
val login = loginImpl
|
||||
@ -115,5 +117,6 @@ object BackendApp {
|
||||
val share = shareImpl
|
||||
val events = notificationMod
|
||||
val notification = notifyImpl
|
||||
val bookmarks = bookmarksImpl
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,83 @@
|
||||
package docspell.backend.ops
|
||||
|
||||
import docspell.common._
|
||||
import docspell.query.ItemQuery
|
||||
import cats.effect._
|
||||
import docspell.store.Store
|
||||
import docspell.store.records.RQueryBookmark
|
||||
import cats.implicits._
|
||||
import docspell.store.UpdateResult
|
||||
import docspell.store.AddResult
|
||||
|
||||
trait OQueryBookmarks[F[_]] {
|
||||
|
||||
def getAll(account: AccountId): F[Vector[OQueryBookmarks.Bookmark]]
|
||||
|
||||
def create(account: AccountId, bookmark: OQueryBookmarks.NewBookmark): F[AddResult]
|
||||
|
||||
def update(
|
||||
account: AccountId,
|
||||
id: Ident,
|
||||
bookmark: OQueryBookmarks.NewBookmark
|
||||
): F[UpdateResult]
|
||||
|
||||
def delete(account: AccountId, bookmark: Ident): F[Unit]
|
||||
}
|
||||
|
||||
object OQueryBookmarks {
|
||||
final case class NewBookmark(
|
||||
name: String,
|
||||
label: Option[String],
|
||||
query: ItemQuery,
|
||||
personal: Boolean
|
||||
)
|
||||
|
||||
final case class Bookmark(
|
||||
id: Ident,
|
||||
name: String,
|
||||
label: Option[String],
|
||||
query: ItemQuery,
|
||||
personal: Boolean,
|
||||
created: Timestamp
|
||||
)
|
||||
|
||||
def apply[F[_]: Sync](store: Store[F]): Resource[F, OQueryBookmarks[F]] =
|
||||
Resource.pure(new OQueryBookmarks[F] {
|
||||
def getAll(account: AccountId): F[Vector[Bookmark]] =
|
||||
store
|
||||
.transact(RQueryBookmark.allForUser(account))
|
||||
.map(
|
||||
_.map(r => Bookmark(r.id, r.name, r.label, r.query, r.isPersonal, r.created))
|
||||
)
|
||||
|
||||
def create(account: AccountId, b: NewBookmark): F[AddResult] =
|
||||
store
|
||||
.transact(for {
|
||||
r <- RQueryBookmark.createNew(account, b.name, b.label, b.query, b.personal)
|
||||
n <- RQueryBookmark.insert(r)
|
||||
} yield n)
|
||||
.attempt
|
||||
.map(AddResult.fromUpdate)
|
||||
|
||||
def update(account: AccountId, id: Ident, b: NewBookmark): F[UpdateResult] =
|
||||
UpdateResult.fromUpdate(
|
||||
store.transact(
|
||||
RQueryBookmark.update(
|
||||
RQueryBookmark(
|
||||
id,
|
||||
b.name,
|
||||
b.label,
|
||||
None, // userId and some other values are not used
|
||||
account.collective,
|
||||
b.query,
|
||||
Timestamp.Epoch
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def delete(account: AccountId, bookmark: Ident): F[Unit] =
|
||||
store.transact(RQueryBookmark.deleteById(account.collective, bookmark)).as(())
|
||||
|
||||
})
|
||||
}
|
@ -1880,6 +1880,98 @@ paths:
|
||||
application/json:
|
||||
schema: {}
|
||||
|
||||
/sec/querybookmark:
|
||||
get:
|
||||
operationId: "sec-querybookmark-get-all"
|
||||
tags: [Query Bookmarks]
|
||||
summary: Return all query bookmarks
|
||||
description: |
|
||||
Returns all query bookmarks of the current user.
|
||||
|
||||
Bookmarks can be "global", where they belong to the whole
|
||||
collective or personal, so they are only for the user. This
|
||||
returns both.
|
||||
security:
|
||||
- authTokenHeader: []
|
||||
responses:
|
||||
422:
|
||||
description: BadRequest
|
||||
200:
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/BookmarkedQuery"
|
||||
post:
|
||||
operationId: "sec-querybookmark-post"
|
||||
tags: [Query Bookmarks]
|
||||
summary: Create a new query bookmark
|
||||
description: |
|
||||
Creates a new query bookmark.
|
||||
|
||||
A bookmark must have a unique name (within both collective and
|
||||
personal scope). If a name already exists, a failure is
|
||||
returned - use PUT instead for changing existing bookmarks.
|
||||
security:
|
||||
- authTokenHeader: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BookmarkedQuery"
|
||||
responses:
|
||||
422:
|
||||
description: BadRequest
|
||||
200:
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BasicResult"
|
||||
put:
|
||||
operationId: "sec-querybookmark-put"
|
||||
tags: [Query Bookmarks]
|
||||
summary: Change a query bookmark
|
||||
description: |
|
||||
Changes an existing query bookmark.
|
||||
|
||||
A bookmark must have a unique name within the collective
|
||||
(considering collective and personal scope). The bookmark is
|
||||
identified by its id, which must exist.
|
||||
security:
|
||||
- authTokenHeader: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BookmarkedQuery"
|
||||
responses:
|
||||
422:
|
||||
description: BadRequest
|
||||
200:
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BasicResult"
|
||||
/sec/querybookmark/{bookmarkId}:
|
||||
delete:
|
||||
operationId: "sec-querybookmark-delete"
|
||||
tags: [Query Bookmark]
|
||||
summary: Delete a bookmark.
|
||||
description: |
|
||||
Deletes a bookmarks by its id.
|
||||
responses:
|
||||
422:
|
||||
description: BadRequest
|
||||
200:
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BasicResult"
|
||||
|
||||
/sec/clientSettings/{clientId}:
|
||||
parameters:
|
||||
@ -5314,6 +5406,32 @@ paths:
|
||||
|
||||
components:
|
||||
schemas:
|
||||
BookmarkedQuery:
|
||||
description: |
|
||||
A query bookmark.
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- query
|
||||
- personal
|
||||
- created
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: ident
|
||||
name:
|
||||
type: string
|
||||
label:
|
||||
type: string
|
||||
query:
|
||||
type: string
|
||||
format: itemquery
|
||||
personal:
|
||||
type: boolean
|
||||
created:
|
||||
type: integer
|
||||
format: date-time
|
||||
|
||||
StringValue:
|
||||
description: |
|
||||
A generic string value
|
||||
|
@ -172,7 +172,8 @@ object RestServer {
|
||||
"folder" -> FolderRoutes(restApp.backend, token),
|
||||
"customfield" -> CustomFieldRoutes(restApp.backend, token),
|
||||
"clientSettings" -> ClientSettingsRoutes(restApp.backend, token),
|
||||
"notification" -> NotificationRoutes(cfg, restApp.backend, token)
|
||||
"notification" -> NotificationRoutes(cfg, restApp.backend, token),
|
||||
"querybookmark" -> BookmarkRoutes(restApp.backend, token)
|
||||
)
|
||||
|
||||
def openRoutes[F[_]: Async](
|
||||
|
@ -0,0 +1,58 @@
|
||||
package docspell.restserver.routes
|
||||
|
||||
import docspell.backend.auth.AuthToken
|
||||
import org.http4s.HttpRoutes
|
||||
import org.http4s.circe.CirceEntityDecoder._
|
||||
import org.http4s.circe.CirceEntityEncoder._
|
||||
import org.http4s.dsl.Http4sDsl
|
||||
import cats.effect.Async
|
||||
import docspell.backend.ops.OQueryBookmarks
|
||||
import docspell.restapi.model.BookmarkedQuery
|
||||
import docspell.backend.BackendApp
|
||||
import cats.implicits._
|
||||
import docspell.restserver.conv.Conversions
|
||||
import docspell.common.Ident
|
||||
|
||||
object BookmarkRoutes {
|
||||
|
||||
def apply[F[_]: Async](backend: BackendApp[F], token: AuthToken): HttpRoutes[F] = {
|
||||
val dsl = new Http4sDsl[F] {}
|
||||
import dsl._
|
||||
|
||||
HttpRoutes.of {
|
||||
case GET -> Root =>
|
||||
for {
|
||||
all <- backend.bookmarks.getAll(token.account)
|
||||
resp <- Ok(all.map(convert.toApi))
|
||||
} yield resp
|
||||
|
||||
case req @ POST -> Root =>
|
||||
for {
|
||||
data <- req.as[BookmarkedQuery]
|
||||
res <- backend.bookmarks.create(token.account, convert.toModel(data))
|
||||
resp <- Ok(Conversions.basicResult(res, "Bookmark created"))
|
||||
} yield resp
|
||||
|
||||
case req @ PUT -> Root =>
|
||||
for {
|
||||
data <- req.as[BookmarkedQuery]
|
||||
res <- backend.bookmarks.update(token.account, data.id, convert.toModel(data))
|
||||
resp <- Ok(Conversions.basicResult(res, "Bookmark updated"))
|
||||
} yield resp
|
||||
|
||||
case DELETE -> Root / Ident(id) =>
|
||||
for {
|
||||
res <- backend.bookmarks.delete(token.account, id).attempt
|
||||
resp <- Ok(Conversions.basicResult(res, "Bookmark deleted"))
|
||||
} yield resp
|
||||
}
|
||||
}
|
||||
|
||||
object convert {
|
||||
def toApi(b: OQueryBookmarks.Bookmark): BookmarkedQuery =
|
||||
BookmarkedQuery(b.id, b.name, b.label, b.query, b.personal, b.created)
|
||||
|
||||
def toModel(b: BookmarkedQuery): OQueryBookmarks.NewBookmark =
|
||||
OQueryBookmarks.NewBookmark(b.name, b.label, b.query, b.personal)
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
CREATE TABLE "query_bookmark" (
|
||||
"id" varchar(254) not null primary key,
|
||||
"name" varchar(254) not null,
|
||||
"label" varchar(254),
|
||||
"user_id" varchar(254),
|
||||
"cid" varchar(254) not null,
|
||||
"query" varchar(2000) not null,
|
||||
"created" timestamp,
|
||||
foreign key ("user_id") references "user_"("uid") on delete cascade,
|
||||
foreign key ("cid") references "collective"("cid") on delete cascade,
|
||||
unique("cid", "user_id", "name")
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
CREATE TABLE `query_bookmark` (
|
||||
`id` varchar(254) not null primary key,
|
||||
`name` varchar(254) not null,
|
||||
`label` varchar(254),
|
||||
`user_id` varchar(254),
|
||||
`cid` varchar(254) not null,
|
||||
`query` varchar(2000) not null,
|
||||
`created` timestamp,
|
||||
foreign key (`user_id`) references `user_`(`uid`) on delete cascade,
|
||||
foreign key (`cid`) references `collective`(`cid`) on delete cascade,
|
||||
unique(`cid`, `user_id`, `name`)
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
CREATE TABLE "query_bookmark" (
|
||||
"id" varchar(254) not null primary key,
|
||||
"name" varchar(254) not null,
|
||||
"label" varchar(254),
|
||||
"user_id" varchar(254),
|
||||
"cid" varchar(254) not null,
|
||||
"query" varchar(2000) not null,
|
||||
"created" timestamp,
|
||||
foreign key ("user_id") references "user_"("uid") on delete cascade,
|
||||
foreign key ("cid") references "collective"("cid") on delete cascade,
|
||||
unique("cid", "user_id", "name")
|
||||
)
|
@ -0,0 +1,108 @@
|
||||
package docspell.store.records
|
||||
|
||||
import docspell.common._
|
||||
import docspell.query.ItemQuery
|
||||
import docspell.store.qb.DSL._
|
||||
import docspell.store.qb._
|
||||
|
||||
import doobie._
|
||||
import doobie.implicits._
|
||||
import cats.data.NonEmptyList
|
||||
import cats.syntax.option._
|
||||
|
||||
final case class RQueryBookmark(
|
||||
id: Ident,
|
||||
name: String,
|
||||
label: Option[String],
|
||||
userId: Option[Ident],
|
||||
cid: Ident,
|
||||
query: ItemQuery,
|
||||
created: Timestamp
|
||||
) {
|
||||
def isPersonal: Boolean =
|
||||
userId.isDefined
|
||||
|
||||
def asGlobal: RQueryBookmark =
|
||||
copy(userId = None)
|
||||
|
||||
def asPersonal(userId: Ident): RQueryBookmark =
|
||||
copy(userId = userId.some)
|
||||
}
|
||||
|
||||
object RQueryBookmark {
|
||||
final case class Table(alias: Option[String]) extends TableDef {
|
||||
val tableName = "query_bookmark";
|
||||
|
||||
val id = Column[Ident]("id", this)
|
||||
val name = Column[String]("name", this)
|
||||
val label = Column[String]("label", this)
|
||||
val userId = Column[Ident]("user_id", this)
|
||||
val cid = Column[Ident]("cid", this)
|
||||
val query = Column[ItemQuery]("query", this)
|
||||
val created = Column[Timestamp]("created", this)
|
||||
|
||||
val all: NonEmptyList[Column[_]] =
|
||||
NonEmptyList.of(id, name, label, userId, cid, query, created)
|
||||
}
|
||||
|
||||
val T: Table = Table(None)
|
||||
def as(alias: String): Table = Table(Some(alias))
|
||||
|
||||
def createNew(
|
||||
account: AccountId,
|
||||
name: String,
|
||||
label: Option[String],
|
||||
query: ItemQuery,
|
||||
personal: Boolean
|
||||
): ConnectionIO[RQueryBookmark] =
|
||||
for {
|
||||
userId <- RUser.getIdByAccount(account)
|
||||
curTime <- Timestamp.current[ConnectionIO]
|
||||
id <- Ident.randomId[ConnectionIO]
|
||||
} yield RQueryBookmark(
|
||||
id,
|
||||
name,
|
||||
label,
|
||||
if (personal) userId.some else None,
|
||||
account.collective,
|
||||
query,
|
||||
curTime
|
||||
)
|
||||
|
||||
def insert(r: RQueryBookmark): ConnectionIO[Int] =
|
||||
DML.insert(
|
||||
T,
|
||||
T.all,
|
||||
sql"${r.id},${r.name},${r.label},${r.userId},${r.cid},${r.query},${r.created}"
|
||||
)
|
||||
|
||||
def update(r: RQueryBookmark): ConnectionIO[Int] =
|
||||
DML.update(
|
||||
T,
|
||||
T.id === r.id,
|
||||
DML.set(
|
||||
T.name.setTo(r.name),
|
||||
T.label.setTo(r.label),
|
||||
T.query.setTo(r.query)
|
||||
)
|
||||
)
|
||||
|
||||
def deleteById(cid: Ident, id: Ident): ConnectionIO[Int] =
|
||||
DML.delete(T, T.id === id && T.cid === cid)
|
||||
|
||||
def allForUser(account: AccountId): ConnectionIO[Vector[RQueryBookmark]] = {
|
||||
val user = RUser.as("u")
|
||||
val bm = RQueryBookmark.as("bm")
|
||||
|
||||
val users = Select(
|
||||
user.uid.s,
|
||||
from(user),
|
||||
user.cid === account.collective && user.login === account.user
|
||||
)
|
||||
Select(
|
||||
select(bm.all),
|
||||
from(bm),
|
||||
bm.cid === account.collective && (bm.userId.isNull || bm.userId.in(users))
|
||||
).build.query[RQueryBookmark].to[Vector]
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ import docspell.store.qb._
|
||||
|
||||
import doobie._
|
||||
import doobie.implicits._
|
||||
import cats.data.OptionT
|
||||
import cats.effect.Sync
|
||||
|
||||
case class RUser(
|
||||
uid: Ident,
|
||||
@ -150,6 +152,13 @@ object RUser {
|
||||
.query[Ident]
|
||||
.option
|
||||
|
||||
def getIdByAccount(account: AccountId): ConnectionIO[Ident] =
|
||||
OptionT(findIdByAccount(account)).getOrElseF(
|
||||
Sync[ConnectionIO].raiseError(
|
||||
new Exception(s"No user found for: ${account.asString}")
|
||||
)
|
||||
)
|
||||
|
||||
def updateLogin(accountId: AccountId): ConnectionIO[Int] = {
|
||||
val t = Table(None)
|
||||
def stmt(now: Timestamp) =
|
||||
|
@ -124,7 +124,6 @@ module Api exposing
|
||||
, restoreAllItems
|
||||
, restoreItem
|
||||
, sampleEvent
|
||||
, saveBookmarks
|
||||
, saveClientSettings
|
||||
, searchShare
|
||||
, searchShareStats
|
||||
@ -188,6 +187,7 @@ module Api exposing
|
||||
import Api.Model.AttachmentMeta exposing (AttachmentMeta)
|
||||
import Api.Model.AuthResult exposing (AuthResult)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||
import Api.Model.CalEventCheck exposing (CalEventCheck)
|
||||
import Api.Model.CalEventCheckResult exposing (CalEventCheckResult)
|
||||
import Api.Model.Collective exposing (Collective)
|
||||
@ -266,7 +266,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.Bookmarks exposing (AllBookmarks, Bookmarks)
|
||||
import Data.ContactType exposing (ContactType)
|
||||
import Data.CustomFieldOrder exposing (CustomFieldOrder)
|
||||
import Data.EquipmentOrder exposing (EquipmentOrder)
|
||||
@ -2295,46 +2295,29 @@ saveClientSettings flags settings receive =
|
||||
--- Query Bookmarks
|
||||
|
||||
|
||||
type alias BookmarkLocation =
|
||||
Data.BookmarkedQuery.Location
|
||||
bookmarkUri : Flags -> String
|
||||
bookmarkUri flags =
|
||||
flags.config.baseUrl ++ "/api/v1/sec/querybookmark"
|
||||
|
||||
|
||||
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 =
|
||||
getBookmarksTask : Flags -> Task.Task Http.Error Bookmarks
|
||||
getBookmarksTask flags =
|
||||
Http2.authTask
|
||||
{ method = "GET"
|
||||
, url = bookmarkLocationUri flags loc
|
||||
, url = bookmarkUri flags
|
||||
, account = getAccount flags
|
||||
, body = Http.emptyBody
|
||||
, resolver = Http2.jsonResolver Data.BookmarkedQuery.bookmarksDecoder
|
||||
, resolver = Http2.jsonResolver Data.Bookmarks.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
|
||||
bms =
|
||||
getBookmarksTask flags
|
||||
|
||||
shares =
|
||||
getSharesTask flags "" False
|
||||
@ -2342,86 +2325,57 @@ getBookmarks flags receive =
|
||||
activeShare s =
|
||||
s.enabled && s.name /= Nothing
|
||||
|
||||
combine bc bu bs =
|
||||
AllBookmarks bc bu (List.filter activeShare bs.items)
|
||||
combine bm bs =
|
||||
AllBookmarks (Data.Bookmarks.sort bm) (List.filter activeShare bs.items)
|
||||
in
|
||||
Task.map3 combine coll user shares
|
||||
Task.map2 combine bms shares
|
||||
|> Task.attempt receive
|
||||
|
||||
|
||||
saveBookmarksTask : Flags -> BookmarkLocation -> Bookmarks -> Task.Task Http.Error BasicResult
|
||||
saveBookmarksTask flags loc bookmarks =
|
||||
Http2.authTask
|
||||
{ method = "PUT"
|
||||
, url = bookmarkLocationUri flags loc
|
||||
addBookmark : Flags -> BookmarkedQuery -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
addBookmark flags model receive =
|
||||
Http2.authPost
|
||||
{ url = bookmarkUri flags
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Data.BookmarkedQuery.bookmarksEncode bookmarks)
|
||||
, resolver = Http2.jsonResolver Api.Model.BasicResult.decoder
|
||||
, headers = []
|
||||
, timeout = Nothing
|
||||
, body = Http.jsonBody (Api.Model.BookmarkedQuery.encode model)
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
saveBookmarks : Flags -> Bookmarks -> BookmarkLocation -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
saveBookmarks flags bookmarks loc receive =
|
||||
Task.attempt receive (saveBookmarksTask flags loc bookmarks)
|
||||
updateBookmark : Flags -> BookmarkedQuery -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
updateBookmark flags model receive =
|
||||
Http2.authPut
|
||||
{ url = bookmarkUri flags
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Api.Model.BookmarkedQuery.encode model)
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
addBookmark : Flags -> BookmarkedQueryDef -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
addBookmark flags model receive =
|
||||
bookmarkNameExistsTask : Flags -> String -> Task.Task Http.Error Bool
|
||||
bookmarkNameExistsTask flags name =
|
||||
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
|
||||
|
||||
|
||||
updateBookmark : Flags -> String -> BookmarkedQueryDef -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
updateBookmark flags oldName model receive =
|
||||
let
|
||||
load =
|
||||
getBookmarksTask flags model.location
|
||||
|
||||
add current =
|
||||
Data.BookmarkedQuery.remove oldName current
|
||||
|> Data.BookmarkedQuery.add model.query
|
||||
|> saveBookmarksTask flags model.location
|
||||
in
|
||||
Task.andThen add load |> Task.attempt receive
|
||||
|
||||
|
||||
bookmarkNameExistsTask : Flags -> BookmarkLocation -> String -> Task.Task Http.Error Bool
|
||||
bookmarkNameExistsTask flags loc name =
|
||||
let
|
||||
load =
|
||||
getBookmarksTask flags loc
|
||||
getBookmarksTask flags
|
||||
|
||||
exists current =
|
||||
Data.BookmarkedQuery.exists name current
|
||||
Data.Bookmarks.exists name current
|
||||
in
|
||||
Task.map exists load
|
||||
|
||||
|
||||
bookmarkNameExists : Flags -> BookmarkLocation -> String -> (Result Http.Error Bool -> msg) -> Cmd msg
|
||||
bookmarkNameExists flags loc name receive =
|
||||
bookmarkNameExistsTask flags loc name |> Task.attempt receive
|
||||
bookmarkNameExists : Flags -> String -> (Result Http.Error Bool -> msg) -> Cmd msg
|
||||
bookmarkNameExists flags name receive =
|
||||
bookmarkNameExistsTask flags name |> Task.attempt receive
|
||||
|
||||
|
||||
deleteBookmark : Flags -> BookmarkLocation -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
deleteBookmark flags loc name receive =
|
||||
let
|
||||
load =
|
||||
getBookmarksTask flags loc
|
||||
|
||||
remove current =
|
||||
Data.BookmarkedQuery.remove name current
|
||||
|> saveBookmarksTask flags loc
|
||||
in
|
||||
Task.andThen remove load |> Task.attempt receive
|
||||
deleteBookmark : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||
deleteBookmark flags id receive =
|
||||
Http2.authDelete
|
||||
{ url = bookmarkUri flags ++ "/" ++ id
|
||||
, account = getAccount flags
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -11,8 +11,9 @@ module Comp.BookmarkChooser exposing
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
import Data.BookmarkedQuery exposing (AllBookmarks, BookmarkedQuery)
|
||||
import Data.Bookmarks exposing (AllBookmarks)
|
||||
import Data.Icons as Icons
|
||||
import Html exposing (Html, a, div, i, label, span, text)
|
||||
import Html.Attributes exposing (class, classList, href)
|
||||
@ -34,19 +35,18 @@ init all =
|
||||
|
||||
isEmpty : Model -> Bool
|
||||
isEmpty model =
|
||||
model.all == Data.BookmarkedQuery.allBookmarksEmpty
|
||||
model.all == Data.Bookmarks.empty
|
||||
|
||||
|
||||
type alias Selection =
|
||||
{ user : Set String
|
||||
, collective : Set String
|
||||
{ bookmarks : Set String
|
||||
, shares : Set String
|
||||
}
|
||||
|
||||
|
||||
emptySelection : Selection
|
||||
emptySelection =
|
||||
{ user = Set.empty, collective = Set.empty, shares = Set.empty }
|
||||
{ bookmarks = Set.empty, shares = Set.empty }
|
||||
|
||||
|
||||
isEmptySelection : Selection -> Bool
|
||||
@ -55,8 +55,7 @@ isEmptySelection sel =
|
||||
|
||||
|
||||
type Kind
|
||||
= User
|
||||
| Collective
|
||||
= Bookmark
|
||||
| Share
|
||||
|
||||
|
||||
@ -68,14 +67,13 @@ getQueries : Model -> Selection -> List BookmarkedQuery
|
||||
getQueries model sel =
|
||||
let
|
||||
member set bm =
|
||||
Set.member bm.name set
|
||||
Set.member bm.id set
|
||||
|
||||
filterBookmarks f bms =
|
||||
Data.BookmarkedQuery.filter f bms |> Data.BookmarkedQuery.map identity
|
||||
List.filter f bms |> List.map identity
|
||||
in
|
||||
List.concat
|
||||
[ filterBookmarks (member sel.user) model.all.user
|
||||
, filterBookmarks (member sel.collective) model.all.collective
|
||||
[ filterBookmarks (member sel.bookmarks) model.all.bookmarks
|
||||
, List.map shareToBookmark model.all.shares
|
||||
|> List.filter (member sel.shares)
|
||||
]
|
||||
@ -96,16 +94,13 @@ update msg model current =
|
||||
Set.insert name set
|
||||
in
|
||||
case msg of
|
||||
Toggle kind name ->
|
||||
Toggle kind id ->
|
||||
case kind of
|
||||
User ->
|
||||
( model, { current | user = toggle name current.user } )
|
||||
|
||||
Collective ->
|
||||
( model, { current | collective = toggle name current.collective } )
|
||||
Bookmark ->
|
||||
( model, { current | bookmarks = toggle id current.bookmarks } )
|
||||
|
||||
Share ->
|
||||
( model, { current | shares = toggle name current.shares } )
|
||||
( model, { current | shares = toggle id current.shares } )
|
||||
|
||||
|
||||
|
||||
@ -114,9 +109,13 @@ update msg model current =
|
||||
|
||||
view : Texts -> Model -> Selection -> Html Msg
|
||||
view texts model selection =
|
||||
let
|
||||
( user, coll ) =
|
||||
List.partition .personal model.all.bookmarks
|
||||
in
|
||||
div [ class "flex flex-col" ]
|
||||
[ userBookmarks texts model selection
|
||||
, collBookmarks texts model selection
|
||||
[ userBookmarks texts user selection
|
||||
, collBookmarks texts coll selection
|
||||
, shares texts model selection
|
||||
]
|
||||
|
||||
@ -130,27 +129,27 @@ titleDiv label =
|
||||
]
|
||||
|
||||
|
||||
userBookmarks : Texts -> Model -> Selection -> Html Msg
|
||||
userBookmarks : Texts -> List BookmarkedQuery -> Selection -> Html Msg
|
||||
userBookmarks texts model sel =
|
||||
div
|
||||
[ class "mb-2"
|
||||
, classList [ ( "hidden", Data.BookmarkedQuery.emptyBookmarks == model.all.user ) ]
|
||||
, classList [ ( "hidden", model == [] ) ]
|
||||
]
|
||||
[ titleDiv 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)
|
||||
(List.map (mkItem "fa fa-bookmark" sel Bookmark) model)
|
||||
]
|
||||
|
||||
|
||||
collBookmarks : Texts -> Model -> Selection -> Html Msg
|
||||
collBookmarks : Texts -> List BookmarkedQuery -> Selection -> Html Msg
|
||||
collBookmarks texts model sel =
|
||||
div
|
||||
[ class "mb-2"
|
||||
, classList [ ( "hidden", Data.BookmarkedQuery.emptyBookmarks == model.all.collective ) ]
|
||||
, classList [ ( "hidden", [] == model ) ]
|
||||
]
|
||||
[ titleDiv 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)
|
||||
(List.map (mkItem "fa fa-bookmark font-light" sel Bookmark) model)
|
||||
]
|
||||
|
||||
|
||||
@ -175,9 +174,9 @@ 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)
|
||||
, onClick (Toggle kind bm.id)
|
||||
]
|
||||
[ if isSelected sel kind bm.name then
|
||||
[ if isSelected sel kind bm.id then
|
||||
i [ class "fa fa-check" ] []
|
||||
|
||||
else
|
||||
@ -187,14 +186,11 @@ mkItem icon sel kind bm =
|
||||
|
||||
|
||||
isSelected : Selection -> Kind -> String -> Bool
|
||||
isSelected sel kind name =
|
||||
Set.member name <|
|
||||
isSelected sel kind id =
|
||||
Set.member id <|
|
||||
case kind of
|
||||
User ->
|
||||
sel.user
|
||||
|
||||
Collective ->
|
||||
sel.collective
|
||||
Bookmark ->
|
||||
sel.bookmarks
|
||||
|
||||
Share ->
|
||||
sel.shares
|
||||
@ -202,4 +198,4 @@ isSelected sel kind name =
|
||||
|
||||
shareToBookmark : ShareDetail -> BookmarkedQuery
|
||||
shareToBookmark share =
|
||||
BookmarkedQuery (Maybe.withDefault "-" share.name) share.query
|
||||
BookmarkedQuery share.id (Maybe.withDefault "-" share.name) share.name share.query False 0
|
||||
|
@ -14,7 +14,7 @@ import Comp.BookmarkQueryForm
|
||||
import Comp.BookmarkTable
|
||||
import Comp.ItemDetail.Model exposing (Msg(..))
|
||||
import Comp.MenuBar as MB
|
||||
import Data.BookmarkedQuery exposing (AllBookmarks)
|
||||
import Data.Bookmarks exposing (AllBookmarks)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
@ -43,16 +43,10 @@ type DeleteConfirm
|
||||
| DeleteConfirmOn
|
||||
|
||||
|
||||
type alias FormData =
|
||||
{ model : Comp.BookmarkQueryForm.Model
|
||||
, oldName : Maybe String
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ viewMode : ViewMode
|
||||
, bookmarks : AllBookmarks
|
||||
, formData : FormData
|
||||
, formModel : Comp.BookmarkQueryForm.Model
|
||||
, loading : Bool
|
||||
, formError : FormError
|
||||
, deleteConfirm : DeleteConfirm
|
||||
@ -66,11 +60,8 @@ init flags =
|
||||
Comp.BookmarkQueryForm.init
|
||||
in
|
||||
( { viewMode = Table
|
||||
, bookmarks = Data.BookmarkedQuery.allBookmarksEmpty
|
||||
, formData =
|
||||
{ model = fm
|
||||
, oldName = Nothing
|
||||
}
|
||||
, bookmarks = Data.Bookmarks.empty
|
||||
, formModel = fm
|
||||
, loading = False
|
||||
, formError = FormErrorNone
|
||||
, deleteConfirm = DeleteConfirmOff
|
||||
@ -84,14 +75,14 @@ init flags =
|
||||
|
||||
type Msg
|
||||
= LoadBookmarks
|
||||
| TableMsg Data.BookmarkedQuery.Location Comp.BookmarkTable.Msg
|
||||
| TableMsg Comp.BookmarkTable.Msg
|
||||
| FormMsg Comp.BookmarkQueryForm.Msg
|
||||
| InitNewBookmark
|
||||
| SetViewMode ViewMode
|
||||
| Submit
|
||||
| RequestDelete
|
||||
| CancelDelete
|
||||
| DeleteBookmarkNow Data.BookmarkedQuery.Location String
|
||||
| DeleteBookmarkNow String
|
||||
| LoadBookmarksResp (Result Http.Error AllBookmarks)
|
||||
| AddBookmarkResp (Result Http.Error BasicResult)
|
||||
| UpdateBookmarkResp (Result Http.Error BasicResult)
|
||||
@ -119,8 +110,7 @@ update flags msg model =
|
||||
{ model
|
||||
| viewMode = Form
|
||||
, formError = FormErrorNone
|
||||
, formData =
|
||||
{ model = bm, oldName = Nothing }
|
||||
, formModel = bm
|
||||
}
|
||||
in
|
||||
( nm, Cmd.map FormMsg bc, Sub.none )
|
||||
@ -138,14 +128,14 @@ update flags msg model =
|
||||
FormMsg lm ->
|
||||
let
|
||||
( fm, fc, fs ) =
|
||||
Comp.BookmarkQueryForm.update flags lm model.formData.model
|
||||
Comp.BookmarkQueryForm.update flags lm model.formModel
|
||||
in
|
||||
( { model | formData = { model = fm, oldName = model.formData.oldName }, formError = FormErrorNone }
|
||||
( { model | formModel = fm, formError = FormErrorNone }
|
||||
, Cmd.map FormMsg fc
|
||||
, Sub.map FormMsg fs
|
||||
)
|
||||
|
||||
TableMsg loc lm ->
|
||||
TableMsg lm ->
|
||||
let
|
||||
action =
|
||||
Comp.BookmarkTable.update lm
|
||||
@ -154,15 +144,12 @@ update flags msg model =
|
||||
Comp.BookmarkTable.Edit bookmark ->
|
||||
let
|
||||
( bm, bc ) =
|
||||
Comp.BookmarkQueryForm.initWith
|
||||
{ query = bookmark
|
||||
, location = loc
|
||||
}
|
||||
Comp.BookmarkQueryForm.initWith bookmark
|
||||
in
|
||||
( { model
|
||||
| viewMode = Form
|
||||
, formError = FormErrorNone
|
||||
, formData = { model = bm, oldName = Just bookmark.name }
|
||||
, formModel = bm
|
||||
}
|
||||
, Cmd.map FormMsg bc
|
||||
, Sub.none
|
||||
@ -174,9 +161,9 @@ update flags msg model =
|
||||
CancelDelete ->
|
||||
( { model | deleteConfirm = DeleteConfirmOff }, Cmd.none, Sub.none )
|
||||
|
||||
DeleteBookmarkNow loc name ->
|
||||
DeleteBookmarkNow id ->
|
||||
( { model | deleteConfirm = DeleteConfirmOff, loading = True }
|
||||
, Api.deleteBookmark flags loc name DeleteBookmarkResp
|
||||
, Api.deleteBookmark flags id DeleteBookmarkResp
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
@ -196,14 +183,13 @@ update flags msg model =
|
||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none, Sub.none )
|
||||
|
||||
Submit ->
|
||||
case Comp.BookmarkQueryForm.get model.formData.model of
|
||||
case Comp.BookmarkQueryForm.get model.formModel of
|
||||
Just data ->
|
||||
case model.formData.oldName of
|
||||
Just prevName ->
|
||||
( { model | loading = True }, Api.updateBookmark flags prevName data AddBookmarkResp, Sub.none )
|
||||
if data.id /= "" then
|
||||
( { model | loading = True }, Api.updateBookmark flags data AddBookmarkResp, Sub.none )
|
||||
|
||||
Nothing ->
|
||||
( { model | loading = True }, Api.addBookmark flags data AddBookmarkResp, Sub.none )
|
||||
else
|
||||
( { model | loading = True }, Api.addBookmark flags data AddBookmarkResp, Sub.none )
|
||||
|
||||
Nothing ->
|
||||
( { model | formError = FormErrorInvalid }, Cmd.none, Sub.none )
|
||||
@ -254,6 +240,10 @@ view texts settings flags model =
|
||||
|
||||
viewTable : Texts -> Model -> Html Msg
|
||||
viewTable texts model =
|
||||
let
|
||||
( user, coll ) =
|
||||
List.partition .personal model.bookmarks.bookmarks
|
||||
in
|
||||
div [ class "flex flex-col" ]
|
||||
[ MB.view
|
||||
{ start =
|
||||
@ -268,17 +258,23 @@ viewTable texts model =
|
||||
]
|
||||
, rootClasses = "mb-4"
|
||||
}
|
||||
, div [ class "flex flex-col" ]
|
||||
, div
|
||||
[ class "flex flex-col"
|
||||
, classList [ ( "hidden", user == [] ) ]
|
||||
]
|
||||
[ h3 [ class S.header3 ]
|
||||
[ text texts.userBookmarks ]
|
||||
, Html.map (TableMsg Data.BookmarkedQuery.User)
|
||||
(Comp.BookmarkTable.view texts.bookmarkTable model.bookmarks.user)
|
||||
, Html.map TableMsg
|
||||
(Comp.BookmarkTable.view texts.bookmarkTable user)
|
||||
]
|
||||
, div
|
||||
[ class "flex flex-col mt-3"
|
||||
, classList [ ( "hidden", coll == [] ) ]
|
||||
]
|
||||
, div [ class "flex flex-col mt-3" ]
|
||||
[ h3 [ class S.header3 ]
|
||||
[ text texts.collectiveBookmarks ]
|
||||
, Html.map (TableMsg Data.BookmarkedQuery.Collective)
|
||||
(Comp.BookmarkTable.view texts.bookmarkTable model.bookmarks.collective)
|
||||
, Html.map TableMsg
|
||||
(Comp.BookmarkTable.view texts.bookmarkTable coll)
|
||||
]
|
||||
, B.loadingDimmer
|
||||
{ label = ""
|
||||
@ -291,10 +287,10 @@ viewForm : Texts -> UiSettings -> Flags -> Model -> Html Msg
|
||||
viewForm texts _ _ model =
|
||||
let
|
||||
newBookmark =
|
||||
model.formData.oldName == Nothing
|
||||
model.formModel.bookmark.id == ""
|
||||
|
||||
isValid =
|
||||
Comp.BookmarkQueryForm.get model.formData.model /= Nothing
|
||||
Comp.BookmarkQueryForm.get model.formModel /= Nothing
|
||||
in
|
||||
div []
|
||||
[ Html.form []
|
||||
@ -305,7 +301,7 @@ viewForm texts _ _ model =
|
||||
|
||||
else
|
||||
h1 [ class S.header2 ]
|
||||
[ text (Maybe.withDefault "" model.formData.model.name)
|
||||
[ text (Maybe.withDefault "" model.formModel.name)
|
||||
]
|
||||
, MB.view
|
||||
{ start =
|
||||
@ -360,7 +356,7 @@ viewForm texts _ _ model =
|
||||
text m
|
||||
]
|
||||
, div []
|
||||
[ Html.map FormMsg (Comp.BookmarkQueryForm.view texts.bookmarkForm model.formData.model)
|
||||
[ Html.map FormMsg (Comp.BookmarkQueryForm.view texts.bookmarkForm model.formModel)
|
||||
]
|
||||
, B.loadingDimmer
|
||||
{ active = model.loading
|
||||
@ -378,11 +374,7 @@ viewForm texts _ _ model =
|
||||
{ label = texts.basics.yes
|
||||
, icon = "fa fa-check"
|
||||
, disabled = False
|
||||
, handler =
|
||||
onClick
|
||||
(DeleteBookmarkNow model.formData.model.location
|
||||
(Maybe.withDefault "" model.formData.model.name)
|
||||
)
|
||||
, handler = onClick (DeleteBookmarkNow model.formModel.bookmark.id)
|
||||
, attrs = [ href "#" ]
|
||||
}
|
||||
, B.secondaryButton
|
||||
|
@ -8,9 +8,9 @@
|
||||
module Comp.BookmarkQueryForm exposing (Model, Msg, get, init, initQuery, initWith, update, view)
|
||||
|
||||
import Api
|
||||
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||
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 (..)
|
||||
@ -24,10 +24,11 @@ import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ name : Maybe String
|
||||
{ bookmark : BookmarkedQuery
|
||||
, name : Maybe String
|
||||
, nameExists : Bool
|
||||
, queryModel : Comp.PowerSearchInput.Model
|
||||
, location : Location
|
||||
, isPersonal : Bool
|
||||
, nameExistsThrottle : Throttle Msg
|
||||
}
|
||||
|
||||
@ -40,10 +41,11 @@ initQuery q =
|
||||
(Comp.PowerSearchInput.setSearchString q)
|
||||
Comp.PowerSearchInput.init
|
||||
in
|
||||
( { name = Nothing
|
||||
( { bookmark = Api.Model.BookmarkedQuery.empty
|
||||
, name = Nothing
|
||||
, nameExists = False
|
||||
, queryModel = res.model
|
||||
, location = User
|
||||
, isPersonal = True
|
||||
, nameExistsThrottle = Throttle.create 1
|
||||
}
|
||||
, Cmd.batch
|
||||
@ -57,15 +59,16 @@ init =
|
||||
initQuery ""
|
||||
|
||||
|
||||
initWith : BookmarkedQueryDef -> ( Model, Cmd Msg )
|
||||
initWith : BookmarkedQuery -> ( Model, Cmd Msg )
|
||||
initWith bm =
|
||||
let
|
||||
( m, c ) =
|
||||
initQuery bm.query.query
|
||||
initQuery bm.query
|
||||
in
|
||||
( { m
|
||||
| name = Just bm.query.name
|
||||
, location = bm.location
|
||||
| name = Just bm.name
|
||||
, isPersonal = bm.personal
|
||||
, bookmark = bm
|
||||
}
|
||||
, c
|
||||
)
|
||||
@ -78,19 +81,21 @@ isValid model =
|
||||
/= Nothing
|
||||
|
||||
|
||||
get : Model -> Maybe BookmarkedQueryDef
|
||||
get : Model -> Maybe BookmarkedQuery
|
||||
get model =
|
||||
let
|
||||
qStr =
|
||||
Maybe.withDefault "" model.queryModel.input
|
||||
|
||||
bm =
|
||||
model.bookmark
|
||||
in
|
||||
if isValid model then
|
||||
Just
|
||||
{ query =
|
||||
{ query = qStr
|
||||
{ bm
|
||||
| query = qStr
|
||||
, name = Maybe.withDefault "" model.name
|
||||
}
|
||||
, location = model.location
|
||||
, personal = model.isPersonal
|
||||
}
|
||||
|
||||
else
|
||||
@ -100,7 +105,7 @@ get model =
|
||||
type Msg
|
||||
= SetName String
|
||||
| QueryMsg Comp.PowerSearchInput.Msg
|
||||
| SetLocation Location
|
||||
| SetPersonal Bool
|
||||
| NameExistsResp (Result Http.Error Bool)
|
||||
| UpdateThrottle
|
||||
|
||||
@ -109,12 +114,12 @@ update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
||||
update flags msg model =
|
||||
let
|
||||
nameCheck1 name =
|
||||
Api.bookmarkNameExists flags model.location name NameExistsResp
|
||||
Api.bookmarkNameExists flags name NameExistsResp
|
||||
|
||||
nameCheck2 loc =
|
||||
nameCheck2 =
|
||||
case model.name of
|
||||
Just n ->
|
||||
Api.bookmarkNameExists flags loc n NameExistsResp
|
||||
Api.bookmarkNameExists flags n NameExistsResp
|
||||
|
||||
Nothing ->
|
||||
Cmd.none
|
||||
@ -135,12 +140,12 @@ update flags msg model =
|
||||
, throttleSub
|
||||
)
|
||||
|
||||
SetLocation loc ->
|
||||
SetPersonal flag ->
|
||||
let
|
||||
( newThrottle, cmd ) =
|
||||
Throttle.try (nameCheck2 loc) model.nameExistsThrottle
|
||||
Throttle.try nameCheck2 model.nameExistsThrottle
|
||||
in
|
||||
( { model | location = loc, nameExistsThrottle = newThrottle }, cmd, throttleSub )
|
||||
( { model | isPersonal = flag, nameExistsThrottle = newThrottle }, cmd, throttleSub )
|
||||
|
||||
QueryMsg lm ->
|
||||
let
|
||||
@ -224,8 +229,8 @@ view texts model =
|
||||
[ label [ class "inline-flex items-center" ]
|
||||
[ input
|
||||
[ type_ "radio"
|
||||
, checked (model.location == User)
|
||||
, onCheck (\_ -> SetLocation User)
|
||||
, checked model.isPersonal
|
||||
, onCheck (\_ -> SetPersonal True)
|
||||
, class S.radioInput
|
||||
]
|
||||
[]
|
||||
@ -235,9 +240,9 @@ view texts model =
|
||||
, label [ class "inline-flex items-center" ]
|
||||
[ input
|
||||
[ type_ "radio"
|
||||
, checked (model.location == Collective)
|
||||
, checked (not model.isPersonal)
|
||||
, class S.radioInput
|
||||
, onCheck (\_ -> SetLocation Collective)
|
||||
, onCheck (\_ -> SetPersonal False)
|
||||
]
|
||||
[]
|
||||
, span [ class "ml-2" ] [ text texts.collectiveLocation ]
|
||||
|
@ -2,12 +2,12 @@ module Comp.BookmarkQueryManage exposing (..)
|
||||
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||
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.Attributes exposing (class, href)
|
||||
import Html.Events exposing (onClick)
|
||||
import Http
|
||||
import Messages.Comp.BookmarkQueryManage exposing (Texts)
|
||||
@ -55,7 +55,7 @@ type Msg
|
||||
|
||||
|
||||
type FormResult
|
||||
= Submitted BookmarkedQueryDef
|
||||
= Submitted BookmarkedQuery
|
||||
| Cancelled
|
||||
| Done
|
||||
| None
|
||||
@ -117,7 +117,7 @@ update flags msg model =
|
||||
{ empty | model = { model | loading = False, formState = FormStateError err } }
|
||||
|
||||
|
||||
save : Flags -> BookmarkedQueryDef -> Cmd Msg
|
||||
save : Flags -> BookmarkedQuery -> Cmd Msg
|
||||
save flags model =
|
||||
Api.addBookmark flags model SaveResp
|
||||
|
||||
|
@ -12,8 +12,8 @@ module Comp.BookmarkTable exposing
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||
import Comp.Basic as B
|
||||
import Data.BookmarkedQuery exposing (BookmarkedQuery, Bookmarks)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Messages.Comp.BookmarkTable exposing (Texts)
|
||||
@ -39,7 +39,7 @@ update msg =
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> Bookmarks -> Html Msg
|
||||
view : Texts -> List BookmarkedQuery -> Html Msg
|
||||
view texts bms =
|
||||
table [ class S.tableMain ]
|
||||
[ thead []
|
||||
@ -51,7 +51,7 @@ view texts bms =
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(Data.BookmarkedQuery.map (renderBookmarkLine texts) bms)
|
||||
(List.map (renderBookmarkLine texts) bms)
|
||||
]
|
||||
|
||||
|
||||
|
@ -43,7 +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.Bookmarks exposing (AllBookmarks)
|
||||
import Data.CustomFieldChange exposing (CustomFieldValueCollect)
|
||||
import Data.Direction exposing (Direction)
|
||||
import Data.DropdownStyle as DS
|
||||
@ -146,7 +146,7 @@ init flags =
|
||||
, customFieldModel = Comp.CustomFieldMultiInput.initWith []
|
||||
, customValues = Data.CustomFieldChange.emptyCollect
|
||||
, sourceModel = Nothing
|
||||
, allBookmarks = Comp.BookmarkChooser.init Data.BookmarkedQuery.allBookmarksEmpty
|
||||
, allBookmarks = Comp.BookmarkChooser.init Data.Bookmarks.empty
|
||||
, selectedBookmarks = Comp.BookmarkChooser.emptySelection
|
||||
, openTabs = Set.fromList [ "Tags", "Inbox" ]
|
||||
, searchMode = Data.SearchMode.Normal
|
||||
|
@ -1,138 +0,0 @@
|
||||
module Data.BookmarkedQuery exposing
|
||||
( AllBookmarks
|
||||
, BookmarkedQuery
|
||||
, BookmarkedQueryDef
|
||||
, 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
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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 []
|
||||
|
||||
|
||||
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
|
||||
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 )
|
||||
]
|
48
modules/webapp/src/main/elm/Data/Bookmarks.elm
Normal file
48
modules/webapp/src/main/elm/Data/Bookmarks.elm
Normal file
@ -0,0 +1,48 @@
|
||||
module Data.Bookmarks exposing
|
||||
( AllBookmarks
|
||||
, Bookmarks
|
||||
, bookmarksDecoder
|
||||
, empty
|
||||
, exists
|
||||
, sort
|
||||
)
|
||||
|
||||
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||
import Json.Decode as D
|
||||
|
||||
|
||||
type alias AllBookmarks =
|
||||
{ bookmarks : List BookmarkedQuery
|
||||
, shares : List ShareDetail
|
||||
}
|
||||
|
||||
|
||||
empty : AllBookmarks
|
||||
empty =
|
||||
AllBookmarks [] []
|
||||
|
||||
|
||||
type alias Bookmarks =
|
||||
List BookmarkedQuery
|
||||
|
||||
|
||||
{-| Checks wether a bookmark of this name already exists.
|
||||
-}
|
||||
exists : String -> Bookmarks -> Bool
|
||||
exists name bookmarks =
|
||||
List.any (\b -> b.name == name) bookmarks
|
||||
|
||||
|
||||
sort : Bookmarks -> Bookmarks
|
||||
sort bms =
|
||||
let
|
||||
labelName b =
|
||||
Maybe.withDefault b.name b.label
|
||||
in
|
||||
List.sortBy labelName bms
|
||||
|
||||
|
||||
bookmarksDecoder : D.Decoder Bookmarks
|
||||
bookmarksDecoder =
|
||||
D.list Api.Model.BookmarkedQuery.decoder
|
Loading…
Reference in New Issue
Block a user