mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 10:28:27 +00:00
Instead of client only, make bookmarks a server aware feature
Makes it much more useful
This commit is contained in:
@ -49,6 +49,7 @@ trait BackendApp[F[_]] {
|
|||||||
def pubSub: PubSubT[F]
|
def pubSub: PubSubT[F]
|
||||||
def events: EventExchange[F]
|
def events: EventExchange[F]
|
||||||
def notification: ONotification[F]
|
def notification: ONotification[F]
|
||||||
|
def bookmarks: OQueryBookmarks[F]
|
||||||
}
|
}
|
||||||
|
|
||||||
object BackendApp {
|
object BackendApp {
|
||||||
@ -89,6 +90,7 @@ object BackendApp {
|
|||||||
OShare(store, itemSearchImpl, simpleSearchImpl, javaEmil)
|
OShare(store, itemSearchImpl, simpleSearchImpl, javaEmil)
|
||||||
)
|
)
|
||||||
notifyImpl <- ONotification(store, notificationMod)
|
notifyImpl <- ONotification(store, notificationMod)
|
||||||
|
bookmarksImpl <- OQueryBookmarks(store)
|
||||||
} yield new BackendApp[F] {
|
} yield new BackendApp[F] {
|
||||||
val pubSub = pubSubT
|
val pubSub = pubSubT
|
||||||
val login = loginImpl
|
val login = loginImpl
|
||||||
@ -115,5 +117,6 @@ object BackendApp {
|
|||||||
val share = shareImpl
|
val share = shareImpl
|
||||||
val events = notificationMod
|
val events = notificationMod
|
||||||
val notification = notifyImpl
|
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:
|
application/json:
|
||||||
schema: {}
|
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}:
|
/sec/clientSettings/{clientId}:
|
||||||
parameters:
|
parameters:
|
||||||
@ -5314,6 +5406,32 @@ paths:
|
|||||||
|
|
||||||
components:
|
components:
|
||||||
schemas:
|
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:
|
StringValue:
|
||||||
description: |
|
description: |
|
||||||
A generic string value
|
A generic string value
|
||||||
|
@ -172,7 +172,8 @@ object RestServer {
|
|||||||
"folder" -> FolderRoutes(restApp.backend, token),
|
"folder" -> FolderRoutes(restApp.backend, token),
|
||||||
"customfield" -> CustomFieldRoutes(restApp.backend, token),
|
"customfield" -> CustomFieldRoutes(restApp.backend, token),
|
||||||
"clientSettings" -> ClientSettingsRoutes(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](
|
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._
|
||||||
import doobie.implicits._
|
import doobie.implicits._
|
||||||
|
import cats.data.OptionT
|
||||||
|
import cats.effect.Sync
|
||||||
|
|
||||||
case class RUser(
|
case class RUser(
|
||||||
uid: Ident,
|
uid: Ident,
|
||||||
@ -150,6 +152,13 @@ object RUser {
|
|||||||
.query[Ident]
|
.query[Ident]
|
||||||
.option
|
.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] = {
|
def updateLogin(accountId: AccountId): ConnectionIO[Int] = {
|
||||||
val t = Table(None)
|
val t = Table(None)
|
||||||
def stmt(now: Timestamp) =
|
def stmt(now: Timestamp) =
|
||||||
|
@ -124,7 +124,6 @@ module Api exposing
|
|||||||
, restoreAllItems
|
, restoreAllItems
|
||||||
, restoreItem
|
, restoreItem
|
||||||
, sampleEvent
|
, sampleEvent
|
||||||
, saveBookmarks
|
|
||||||
, saveClientSettings
|
, saveClientSettings
|
||||||
, searchShare
|
, searchShare
|
||||||
, searchShareStats
|
, searchShareStats
|
||||||
@ -188,6 +187,7 @@ module Api exposing
|
|||||||
import Api.Model.AttachmentMeta exposing (AttachmentMeta)
|
import Api.Model.AttachmentMeta exposing (AttachmentMeta)
|
||||||
import Api.Model.AuthResult exposing (AuthResult)
|
import Api.Model.AuthResult exposing (AuthResult)
|
||||||
import Api.Model.BasicResult exposing (BasicResult)
|
import Api.Model.BasicResult exposing (BasicResult)
|
||||||
|
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||||
import Api.Model.CalEventCheck exposing (CalEventCheck)
|
import Api.Model.CalEventCheck exposing (CalEventCheck)
|
||||||
import Api.Model.CalEventCheckResult exposing (CalEventCheckResult)
|
import Api.Model.CalEventCheckResult exposing (CalEventCheckResult)
|
||||||
import Api.Model.Collective exposing (Collective)
|
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.UserList exposing (UserList)
|
||||||
import Api.Model.UserPass exposing (UserPass)
|
import Api.Model.UserPass exposing (UserPass)
|
||||||
import Api.Model.VersionInfo exposing (VersionInfo)
|
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.ContactType exposing (ContactType)
|
||||||
import Data.CustomFieldOrder exposing (CustomFieldOrder)
|
import Data.CustomFieldOrder exposing (CustomFieldOrder)
|
||||||
import Data.EquipmentOrder exposing (EquipmentOrder)
|
import Data.EquipmentOrder exposing (EquipmentOrder)
|
||||||
@ -2295,46 +2295,29 @@ saveClientSettings flags settings receive =
|
|||||||
--- Query Bookmarks
|
--- Query Bookmarks
|
||||||
|
|
||||||
|
|
||||||
type alias BookmarkLocation =
|
bookmarkUri : Flags -> String
|
||||||
Data.BookmarkedQuery.Location
|
bookmarkUri flags =
|
||||||
|
flags.config.baseUrl ++ "/api/v1/sec/querybookmark"
|
||||||
|
|
||||||
|
|
||||||
bookmarkLocationUri : Flags -> BookmarkLocation -> String
|
getBookmarksTask : Flags -> Task.Task Http.Error Bookmarks
|
||||||
bookmarkLocationUri flags loc =
|
getBookmarksTask flags =
|
||||||
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
|
Http2.authTask
|
||||||
{ method = "GET"
|
{ method = "GET"
|
||||||
, url = bookmarkLocationUri flags loc
|
, url = bookmarkUri flags
|
||||||
, account = getAccount flags
|
, account = getAccount flags
|
||||||
, body = Http.emptyBody
|
, body = Http.emptyBody
|
||||||
, resolver = Http2.jsonResolver Data.BookmarkedQuery.bookmarksDecoder
|
, resolver = Http2.jsonResolver Data.Bookmarks.bookmarksDecoder
|
||||||
, headers = []
|
, headers = []
|
||||||
, timeout = Nothing
|
, 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 -> (Result Http.Error AllBookmarks -> msg) -> Cmd msg
|
||||||
getBookmarks flags receive =
|
getBookmarks flags receive =
|
||||||
let
|
let
|
||||||
coll =
|
bms =
|
||||||
getBookmarksTask flags Data.BookmarkedQuery.Collective
|
getBookmarksTask flags
|
||||||
|
|
||||||
user =
|
|
||||||
getBookmarksTask flags Data.BookmarkedQuery.User
|
|
||||||
|
|
||||||
shares =
|
shares =
|
||||||
getSharesTask flags "" False
|
getSharesTask flags "" False
|
||||||
@ -2342,86 +2325,57 @@ getBookmarks flags receive =
|
|||||||
activeShare s =
|
activeShare s =
|
||||||
s.enabled && s.name /= Nothing
|
s.enabled && s.name /= Nothing
|
||||||
|
|
||||||
combine bc bu bs =
|
combine bm bs =
|
||||||
AllBookmarks bc bu (List.filter activeShare bs.items)
|
AllBookmarks (Data.Bookmarks.sort bm) (List.filter activeShare bs.items)
|
||||||
in
|
in
|
||||||
Task.map3 combine coll user shares
|
Task.map2 combine bms shares
|
||||||
|> Task.attempt receive
|
|> Task.attempt receive
|
||||||
|
|
||||||
|
|
||||||
saveBookmarksTask : Flags -> BookmarkLocation -> Bookmarks -> Task.Task Http.Error BasicResult
|
addBookmark : Flags -> BookmarkedQuery -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||||
saveBookmarksTask flags loc bookmarks =
|
addBookmark flags model receive =
|
||||||
Http2.authTask
|
Http2.authPost
|
||||||
{ method = "PUT"
|
{ url = bookmarkUri flags
|
||||||
, url = bookmarkLocationUri flags loc
|
|
||||||
, account = getAccount flags
|
, account = getAccount flags
|
||||||
, body = Http.jsonBody (Data.BookmarkedQuery.bookmarksEncode bookmarks)
|
, body = Http.jsonBody (Api.Model.BookmarkedQuery.encode model)
|
||||||
, resolver = Http2.jsonResolver Api.Model.BasicResult.decoder
|
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||||
, headers = []
|
|
||||||
, timeout = Nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
saveBookmarks : Flags -> Bookmarks -> BookmarkLocation -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
updateBookmark : Flags -> BookmarkedQuery -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||||
saveBookmarks flags bookmarks loc receive =
|
updateBookmark flags model receive =
|
||||||
Task.attempt receive (saveBookmarksTask flags loc bookmarks)
|
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
|
bookmarkNameExistsTask : Flags -> String -> Task.Task Http.Error Bool
|
||||||
addBookmark flags model receive =
|
bookmarkNameExistsTask flags name =
|
||||||
let
|
let
|
||||||
load =
|
load =
|
||||||
getBookmarksTask flags model.location
|
getBookmarksTask flags
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
exists current =
|
exists current =
|
||||||
Data.BookmarkedQuery.exists name current
|
Data.Bookmarks.exists name current
|
||||||
in
|
in
|
||||||
Task.map exists load
|
Task.map exists load
|
||||||
|
|
||||||
|
|
||||||
bookmarkNameExists : Flags -> BookmarkLocation -> String -> (Result Http.Error Bool -> msg) -> Cmd msg
|
bookmarkNameExists : Flags -> String -> (Result Http.Error Bool -> msg) -> Cmd msg
|
||||||
bookmarkNameExists flags loc name receive =
|
bookmarkNameExists flags name receive =
|
||||||
bookmarkNameExistsTask flags loc name |> Task.attempt receive
|
bookmarkNameExistsTask flags name |> Task.attempt receive
|
||||||
|
|
||||||
|
|
||||||
deleteBookmark : Flags -> BookmarkLocation -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
deleteBookmark : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||||
deleteBookmark flags loc name receive =
|
deleteBookmark flags id receive =
|
||||||
let
|
Http2.authDelete
|
||||||
load =
|
{ url = bookmarkUri flags ++ "/" ++ id
|
||||||
getBookmarksTask flags loc
|
, account = getAccount flags
|
||||||
|
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||||
remove current =
|
}
|
||||||
Data.BookmarkedQuery.remove name current
|
|
||||||
|> saveBookmarksTask flags loc
|
|
||||||
in
|
|
||||||
Task.andThen remove load |> Task.attempt receive
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,8 +11,9 @@ module Comp.BookmarkChooser exposing
|
|||||||
, view
|
, view
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||||
import Api.Model.ShareDetail exposing (ShareDetail)
|
import Api.Model.ShareDetail exposing (ShareDetail)
|
||||||
import Data.BookmarkedQuery exposing (AllBookmarks, BookmarkedQuery)
|
import Data.Bookmarks exposing (AllBookmarks)
|
||||||
import Data.Icons as Icons
|
import Data.Icons as Icons
|
||||||
import Html exposing (Html, a, div, i, label, span, text)
|
import Html exposing (Html, a, div, i, label, span, text)
|
||||||
import Html.Attributes exposing (class, classList, href)
|
import Html.Attributes exposing (class, classList, href)
|
||||||
@ -34,19 +35,18 @@ init all =
|
|||||||
|
|
||||||
isEmpty : Model -> Bool
|
isEmpty : Model -> Bool
|
||||||
isEmpty model =
|
isEmpty model =
|
||||||
model.all == Data.BookmarkedQuery.allBookmarksEmpty
|
model.all == Data.Bookmarks.empty
|
||||||
|
|
||||||
|
|
||||||
type alias Selection =
|
type alias Selection =
|
||||||
{ user : Set String
|
{ bookmarks : Set String
|
||||||
, collective : Set String
|
|
||||||
, shares : Set String
|
, shares : Set String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
emptySelection : Selection
|
emptySelection : Selection
|
||||||
emptySelection =
|
emptySelection =
|
||||||
{ user = Set.empty, collective = Set.empty, shares = Set.empty }
|
{ bookmarks = Set.empty, shares = Set.empty }
|
||||||
|
|
||||||
|
|
||||||
isEmptySelection : Selection -> Bool
|
isEmptySelection : Selection -> Bool
|
||||||
@ -55,8 +55,7 @@ isEmptySelection sel =
|
|||||||
|
|
||||||
|
|
||||||
type Kind
|
type Kind
|
||||||
= User
|
= Bookmark
|
||||||
| Collective
|
|
||||||
| Share
|
| Share
|
||||||
|
|
||||||
|
|
||||||
@ -68,14 +67,13 @@ getQueries : Model -> Selection -> List BookmarkedQuery
|
|||||||
getQueries model sel =
|
getQueries model sel =
|
||||||
let
|
let
|
||||||
member set bm =
|
member set bm =
|
||||||
Set.member bm.name set
|
Set.member bm.id set
|
||||||
|
|
||||||
filterBookmarks f bms =
|
filterBookmarks f bms =
|
||||||
Data.BookmarkedQuery.filter f bms |> Data.BookmarkedQuery.map identity
|
List.filter f bms |> List.map identity
|
||||||
in
|
in
|
||||||
List.concat
|
List.concat
|
||||||
[ filterBookmarks (member sel.user) model.all.user
|
[ filterBookmarks (member sel.bookmarks) model.all.bookmarks
|
||||||
, filterBookmarks (member sel.collective) model.all.collective
|
|
||||||
, List.map shareToBookmark model.all.shares
|
, List.map shareToBookmark model.all.shares
|
||||||
|> List.filter (member sel.shares)
|
|> List.filter (member sel.shares)
|
||||||
]
|
]
|
||||||
@ -96,16 +94,13 @@ update msg model current =
|
|||||||
Set.insert name set
|
Set.insert name set
|
||||||
in
|
in
|
||||||
case msg of
|
case msg of
|
||||||
Toggle kind name ->
|
Toggle kind id ->
|
||||||
case kind of
|
case kind of
|
||||||
User ->
|
Bookmark ->
|
||||||
( model, { current | user = toggle name current.user } )
|
( model, { current | bookmarks = toggle id current.bookmarks } )
|
||||||
|
|
||||||
Collective ->
|
|
||||||
( model, { current | collective = toggle name current.collective } )
|
|
||||||
|
|
||||||
Share ->
|
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 -> Html Msg
|
||||||
view texts model selection =
|
view texts model selection =
|
||||||
|
let
|
||||||
|
( user, coll ) =
|
||||||
|
List.partition .personal model.all.bookmarks
|
||||||
|
in
|
||||||
div [ class "flex flex-col" ]
|
div [ class "flex flex-col" ]
|
||||||
[ userBookmarks texts model selection
|
[ userBookmarks texts user selection
|
||||||
, collBookmarks texts model selection
|
, collBookmarks texts coll selection
|
||||||
, shares texts model 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 =
|
userBookmarks texts model sel =
|
||||||
div
|
div
|
||||||
[ class "mb-2"
|
[ class "mb-2"
|
||||||
, classList [ ( "hidden", Data.BookmarkedQuery.emptyBookmarks == model.all.user ) ]
|
, classList [ ( "hidden", model == [] ) ]
|
||||||
]
|
]
|
||||||
[ titleDiv texts.userLabel
|
[ titleDiv texts.userLabel
|
||||||
, div [ class "flex flex-col space-y-2 md:space-y-1" ]
|
, 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 =
|
collBookmarks texts model sel =
|
||||||
div
|
div
|
||||||
[ class "mb-2"
|
[ class "mb-2"
|
||||||
, classList [ ( "hidden", Data.BookmarkedQuery.emptyBookmarks == model.all.collective ) ]
|
, classList [ ( "hidden", [] == model ) ]
|
||||||
]
|
]
|
||||||
[ titleDiv texts.collectiveLabel
|
[ titleDiv texts.collectiveLabel
|
||||||
, div [ class "flex flex-col space-y-2 md:space-y-1" ]
|
, 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
|
a
|
||||||
[ class "flex flex-row items-center rounded px-1 py-1 hover:bg-blue-100 dark:hover:bg-slate-600"
|
[ class "flex flex-row items-center rounded px-1 py-1 hover:bg-blue-100 dark:hover:bg-slate-600"
|
||||||
, href "#"
|
, 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" ] []
|
i [ class "fa fa-check" ] []
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -187,14 +186,11 @@ mkItem icon sel kind bm =
|
|||||||
|
|
||||||
|
|
||||||
isSelected : Selection -> Kind -> String -> Bool
|
isSelected : Selection -> Kind -> String -> Bool
|
||||||
isSelected sel kind name =
|
isSelected sel kind id =
|
||||||
Set.member name <|
|
Set.member id <|
|
||||||
case kind of
|
case kind of
|
||||||
User ->
|
Bookmark ->
|
||||||
sel.user
|
sel.bookmarks
|
||||||
|
|
||||||
Collective ->
|
|
||||||
sel.collective
|
|
||||||
|
|
||||||
Share ->
|
Share ->
|
||||||
sel.shares
|
sel.shares
|
||||||
@ -202,4 +198,4 @@ isSelected sel kind name =
|
|||||||
|
|
||||||
shareToBookmark : ShareDetail -> BookmarkedQuery
|
shareToBookmark : ShareDetail -> BookmarkedQuery
|
||||||
shareToBookmark share =
|
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.BookmarkTable
|
||||||
import Comp.ItemDetail.Model exposing (Msg(..))
|
import Comp.ItemDetail.Model exposing (Msg(..))
|
||||||
import Comp.MenuBar as MB
|
import Comp.MenuBar as MB
|
||||||
import Data.BookmarkedQuery exposing (AllBookmarks)
|
import Data.Bookmarks exposing (AllBookmarks)
|
||||||
import Data.Flags exposing (Flags)
|
import Data.Flags exposing (Flags)
|
||||||
import Data.UiSettings exposing (UiSettings)
|
import Data.UiSettings exposing (UiSettings)
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
@ -43,16 +43,10 @@ type DeleteConfirm
|
|||||||
| DeleteConfirmOn
|
| DeleteConfirmOn
|
||||||
|
|
||||||
|
|
||||||
type alias FormData =
|
|
||||||
{ model : Comp.BookmarkQueryForm.Model
|
|
||||||
, oldName : Maybe String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ viewMode : ViewMode
|
{ viewMode : ViewMode
|
||||||
, bookmarks : AllBookmarks
|
, bookmarks : AllBookmarks
|
||||||
, formData : FormData
|
, formModel : Comp.BookmarkQueryForm.Model
|
||||||
, loading : Bool
|
, loading : Bool
|
||||||
, formError : FormError
|
, formError : FormError
|
||||||
, deleteConfirm : DeleteConfirm
|
, deleteConfirm : DeleteConfirm
|
||||||
@ -66,11 +60,8 @@ init flags =
|
|||||||
Comp.BookmarkQueryForm.init
|
Comp.BookmarkQueryForm.init
|
||||||
in
|
in
|
||||||
( { viewMode = Table
|
( { viewMode = Table
|
||||||
, bookmarks = Data.BookmarkedQuery.allBookmarksEmpty
|
, bookmarks = Data.Bookmarks.empty
|
||||||
, formData =
|
, formModel = fm
|
||||||
{ model = fm
|
|
||||||
, oldName = Nothing
|
|
||||||
}
|
|
||||||
, loading = False
|
, loading = False
|
||||||
, formError = FormErrorNone
|
, formError = FormErrorNone
|
||||||
, deleteConfirm = DeleteConfirmOff
|
, deleteConfirm = DeleteConfirmOff
|
||||||
@ -84,14 +75,14 @@ init flags =
|
|||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= LoadBookmarks
|
= LoadBookmarks
|
||||||
| TableMsg Data.BookmarkedQuery.Location Comp.BookmarkTable.Msg
|
| TableMsg Comp.BookmarkTable.Msg
|
||||||
| FormMsg Comp.BookmarkQueryForm.Msg
|
| FormMsg Comp.BookmarkQueryForm.Msg
|
||||||
| InitNewBookmark
|
| InitNewBookmark
|
||||||
| SetViewMode ViewMode
|
| SetViewMode ViewMode
|
||||||
| Submit
|
| Submit
|
||||||
| RequestDelete
|
| RequestDelete
|
||||||
| CancelDelete
|
| CancelDelete
|
||||||
| DeleteBookmarkNow Data.BookmarkedQuery.Location String
|
| DeleteBookmarkNow String
|
||||||
| LoadBookmarksResp (Result Http.Error AllBookmarks)
|
| LoadBookmarksResp (Result Http.Error AllBookmarks)
|
||||||
| AddBookmarkResp (Result Http.Error BasicResult)
|
| AddBookmarkResp (Result Http.Error BasicResult)
|
||||||
| UpdateBookmarkResp (Result Http.Error BasicResult)
|
| UpdateBookmarkResp (Result Http.Error BasicResult)
|
||||||
@ -119,8 +110,7 @@ update flags msg model =
|
|||||||
{ model
|
{ model
|
||||||
| viewMode = Form
|
| viewMode = Form
|
||||||
, formError = FormErrorNone
|
, formError = FormErrorNone
|
||||||
, formData =
|
, formModel = bm
|
||||||
{ model = bm, oldName = Nothing }
|
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
( nm, Cmd.map FormMsg bc, Sub.none )
|
( nm, Cmd.map FormMsg bc, Sub.none )
|
||||||
@ -138,14 +128,14 @@ update flags msg model =
|
|||||||
FormMsg lm ->
|
FormMsg lm ->
|
||||||
let
|
let
|
||||||
( fm, fc, fs ) =
|
( fm, fc, fs ) =
|
||||||
Comp.BookmarkQueryForm.update flags lm model.formData.model
|
Comp.BookmarkQueryForm.update flags lm model.formModel
|
||||||
in
|
in
|
||||||
( { model | formData = { model = fm, oldName = model.formData.oldName }, formError = FormErrorNone }
|
( { model | formModel = fm, formError = FormErrorNone }
|
||||||
, Cmd.map FormMsg fc
|
, Cmd.map FormMsg fc
|
||||||
, Sub.map FormMsg fs
|
, Sub.map FormMsg fs
|
||||||
)
|
)
|
||||||
|
|
||||||
TableMsg loc lm ->
|
TableMsg lm ->
|
||||||
let
|
let
|
||||||
action =
|
action =
|
||||||
Comp.BookmarkTable.update lm
|
Comp.BookmarkTable.update lm
|
||||||
@ -154,15 +144,12 @@ update flags msg model =
|
|||||||
Comp.BookmarkTable.Edit bookmark ->
|
Comp.BookmarkTable.Edit bookmark ->
|
||||||
let
|
let
|
||||||
( bm, bc ) =
|
( bm, bc ) =
|
||||||
Comp.BookmarkQueryForm.initWith
|
Comp.BookmarkQueryForm.initWith bookmark
|
||||||
{ query = bookmark
|
|
||||||
, location = loc
|
|
||||||
}
|
|
||||||
in
|
in
|
||||||
( { model
|
( { model
|
||||||
| viewMode = Form
|
| viewMode = Form
|
||||||
, formError = FormErrorNone
|
, formError = FormErrorNone
|
||||||
, formData = { model = bm, oldName = Just bookmark.name }
|
, formModel = bm
|
||||||
}
|
}
|
||||||
, Cmd.map FormMsg bc
|
, Cmd.map FormMsg bc
|
||||||
, Sub.none
|
, Sub.none
|
||||||
@ -174,9 +161,9 @@ update flags msg model =
|
|||||||
CancelDelete ->
|
CancelDelete ->
|
||||||
( { model | deleteConfirm = DeleteConfirmOff }, Cmd.none, Sub.none )
|
( { model | deleteConfirm = DeleteConfirmOff }, Cmd.none, Sub.none )
|
||||||
|
|
||||||
DeleteBookmarkNow loc name ->
|
DeleteBookmarkNow id ->
|
||||||
( { model | deleteConfirm = DeleteConfirmOff, loading = True }
|
( { model | deleteConfirm = DeleteConfirmOff, loading = True }
|
||||||
, Api.deleteBookmark flags loc name DeleteBookmarkResp
|
, Api.deleteBookmark flags id DeleteBookmarkResp
|
||||||
, Sub.none
|
, Sub.none
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -196,13 +183,12 @@ update flags msg model =
|
|||||||
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none, Sub.none )
|
( { model | loading = False, formError = FormErrorHttp err }, Cmd.none, Sub.none )
|
||||||
|
|
||||||
Submit ->
|
Submit ->
|
||||||
case Comp.BookmarkQueryForm.get model.formData.model of
|
case Comp.BookmarkQueryForm.get model.formModel of
|
||||||
Just data ->
|
Just data ->
|
||||||
case model.formData.oldName of
|
if data.id /= "" then
|
||||||
Just prevName ->
|
( { model | loading = True }, Api.updateBookmark flags data AddBookmarkResp, Sub.none )
|
||||||
( { model | loading = True }, Api.updateBookmark flags prevName data AddBookmarkResp, Sub.none )
|
|
||||||
|
|
||||||
Nothing ->
|
else
|
||||||
( { model | loading = True }, Api.addBookmark flags data AddBookmarkResp, Sub.none )
|
( { model | loading = True }, Api.addBookmark flags data AddBookmarkResp, Sub.none )
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
@ -254,6 +240,10 @@ view texts settings flags model =
|
|||||||
|
|
||||||
viewTable : Texts -> Model -> Html Msg
|
viewTable : Texts -> Model -> Html Msg
|
||||||
viewTable texts model =
|
viewTable texts model =
|
||||||
|
let
|
||||||
|
( user, coll ) =
|
||||||
|
List.partition .personal model.bookmarks.bookmarks
|
||||||
|
in
|
||||||
div [ class "flex flex-col" ]
|
div [ class "flex flex-col" ]
|
||||||
[ MB.view
|
[ MB.view
|
||||||
{ start =
|
{ start =
|
||||||
@ -268,17 +258,23 @@ viewTable texts model =
|
|||||||
]
|
]
|
||||||
, rootClasses = "mb-4"
|
, rootClasses = "mb-4"
|
||||||
}
|
}
|
||||||
, div [ class "flex flex-col" ]
|
, div
|
||||||
|
[ class "flex flex-col"
|
||||||
|
, classList [ ( "hidden", user == [] ) ]
|
||||||
|
]
|
||||||
[ h3 [ class S.header3 ]
|
[ h3 [ class S.header3 ]
|
||||||
[ text texts.userBookmarks ]
|
[ text texts.userBookmarks ]
|
||||||
, Html.map (TableMsg Data.BookmarkedQuery.User)
|
, Html.map TableMsg
|
||||||
(Comp.BookmarkTable.view texts.bookmarkTable model.bookmarks.user)
|
(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 ]
|
[ h3 [ class S.header3 ]
|
||||||
[ text texts.collectiveBookmarks ]
|
[ text texts.collectiveBookmarks ]
|
||||||
, Html.map (TableMsg Data.BookmarkedQuery.Collective)
|
, Html.map TableMsg
|
||||||
(Comp.BookmarkTable.view texts.bookmarkTable model.bookmarks.collective)
|
(Comp.BookmarkTable.view texts.bookmarkTable coll)
|
||||||
]
|
]
|
||||||
, B.loadingDimmer
|
, B.loadingDimmer
|
||||||
{ label = ""
|
{ label = ""
|
||||||
@ -291,10 +287,10 @@ viewForm : Texts -> UiSettings -> Flags -> Model -> Html Msg
|
|||||||
viewForm texts _ _ model =
|
viewForm texts _ _ model =
|
||||||
let
|
let
|
||||||
newBookmark =
|
newBookmark =
|
||||||
model.formData.oldName == Nothing
|
model.formModel.bookmark.id == ""
|
||||||
|
|
||||||
isValid =
|
isValid =
|
||||||
Comp.BookmarkQueryForm.get model.formData.model /= Nothing
|
Comp.BookmarkQueryForm.get model.formModel /= Nothing
|
||||||
in
|
in
|
||||||
div []
|
div []
|
||||||
[ Html.form []
|
[ Html.form []
|
||||||
@ -305,7 +301,7 @@ viewForm texts _ _ model =
|
|||||||
|
|
||||||
else
|
else
|
||||||
h1 [ class S.header2 ]
|
h1 [ class S.header2 ]
|
||||||
[ text (Maybe.withDefault "" model.formData.model.name)
|
[ text (Maybe.withDefault "" model.formModel.name)
|
||||||
]
|
]
|
||||||
, MB.view
|
, MB.view
|
||||||
{ start =
|
{ start =
|
||||||
@ -360,7 +356,7 @@ viewForm texts _ _ model =
|
|||||||
text m
|
text m
|
||||||
]
|
]
|
||||||
, div []
|
, div []
|
||||||
[ Html.map FormMsg (Comp.BookmarkQueryForm.view texts.bookmarkForm model.formData.model)
|
[ Html.map FormMsg (Comp.BookmarkQueryForm.view texts.bookmarkForm model.formModel)
|
||||||
]
|
]
|
||||||
, B.loadingDimmer
|
, B.loadingDimmer
|
||||||
{ active = model.loading
|
{ active = model.loading
|
||||||
@ -378,11 +374,7 @@ viewForm texts _ _ model =
|
|||||||
{ label = texts.basics.yes
|
{ label = texts.basics.yes
|
||||||
, icon = "fa fa-check"
|
, icon = "fa fa-check"
|
||||||
, disabled = False
|
, disabled = False
|
||||||
, handler =
|
, handler = onClick (DeleteBookmarkNow model.formModel.bookmark.id)
|
||||||
onClick
|
|
||||||
(DeleteBookmarkNow model.formData.model.location
|
|
||||||
(Maybe.withDefault "" model.formData.model.name)
|
|
||||||
)
|
|
||||||
, attrs = [ href "#" ]
|
, attrs = [ href "#" ]
|
||||||
}
|
}
|
||||||
, B.secondaryButton
|
, B.secondaryButton
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
module Comp.BookmarkQueryForm exposing (Model, Msg, get, init, initQuery, initWith, update, view)
|
module Comp.BookmarkQueryForm exposing (Model, Msg, get, init, initQuery, initWith, update, view)
|
||||||
|
|
||||||
import Api
|
import Api
|
||||||
|
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||||
import Comp.Basic as B
|
import Comp.Basic as B
|
||||||
import Comp.PowerSearchInput
|
import Comp.PowerSearchInput
|
||||||
import Data.BookmarkedQuery exposing (BookmarkedQueryDef, Location(..))
|
|
||||||
import Data.Flags exposing (Flags)
|
import Data.Flags exposing (Flags)
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
@ -24,10 +24,11 @@ import Util.Maybe
|
|||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ name : Maybe String
|
{ bookmark : BookmarkedQuery
|
||||||
|
, name : Maybe String
|
||||||
, nameExists : Bool
|
, nameExists : Bool
|
||||||
, queryModel : Comp.PowerSearchInput.Model
|
, queryModel : Comp.PowerSearchInput.Model
|
||||||
, location : Location
|
, isPersonal : Bool
|
||||||
, nameExistsThrottle : Throttle Msg
|
, nameExistsThrottle : Throttle Msg
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +41,11 @@ initQuery q =
|
|||||||
(Comp.PowerSearchInput.setSearchString q)
|
(Comp.PowerSearchInput.setSearchString q)
|
||||||
Comp.PowerSearchInput.init
|
Comp.PowerSearchInput.init
|
||||||
in
|
in
|
||||||
( { name = Nothing
|
( { bookmark = Api.Model.BookmarkedQuery.empty
|
||||||
|
, name = Nothing
|
||||||
, nameExists = False
|
, nameExists = False
|
||||||
, queryModel = res.model
|
, queryModel = res.model
|
||||||
, location = User
|
, isPersonal = True
|
||||||
, nameExistsThrottle = Throttle.create 1
|
, nameExistsThrottle = Throttle.create 1
|
||||||
}
|
}
|
||||||
, Cmd.batch
|
, Cmd.batch
|
||||||
@ -57,15 +59,16 @@ init =
|
|||||||
initQuery ""
|
initQuery ""
|
||||||
|
|
||||||
|
|
||||||
initWith : BookmarkedQueryDef -> ( Model, Cmd Msg )
|
initWith : BookmarkedQuery -> ( Model, Cmd Msg )
|
||||||
initWith bm =
|
initWith bm =
|
||||||
let
|
let
|
||||||
( m, c ) =
|
( m, c ) =
|
||||||
initQuery bm.query.query
|
initQuery bm.query
|
||||||
in
|
in
|
||||||
( { m
|
( { m
|
||||||
| name = Just bm.query.name
|
| name = Just bm.name
|
||||||
, location = bm.location
|
, isPersonal = bm.personal
|
||||||
|
, bookmark = bm
|
||||||
}
|
}
|
||||||
, c
|
, c
|
||||||
)
|
)
|
||||||
@ -78,19 +81,21 @@ isValid model =
|
|||||||
/= Nothing
|
/= Nothing
|
||||||
|
|
||||||
|
|
||||||
get : Model -> Maybe BookmarkedQueryDef
|
get : Model -> Maybe BookmarkedQuery
|
||||||
get model =
|
get model =
|
||||||
let
|
let
|
||||||
qStr =
|
qStr =
|
||||||
Maybe.withDefault "" model.queryModel.input
|
Maybe.withDefault "" model.queryModel.input
|
||||||
|
|
||||||
|
bm =
|
||||||
|
model.bookmark
|
||||||
in
|
in
|
||||||
if isValid model then
|
if isValid model then
|
||||||
Just
|
Just
|
||||||
{ query =
|
{ bm
|
||||||
{ query = qStr
|
| query = qStr
|
||||||
, name = Maybe.withDefault "" model.name
|
, name = Maybe.withDefault "" model.name
|
||||||
}
|
, personal = model.isPersonal
|
||||||
, location = model.location
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -100,7 +105,7 @@ get model =
|
|||||||
type Msg
|
type Msg
|
||||||
= SetName String
|
= SetName String
|
||||||
| QueryMsg Comp.PowerSearchInput.Msg
|
| QueryMsg Comp.PowerSearchInput.Msg
|
||||||
| SetLocation Location
|
| SetPersonal Bool
|
||||||
| NameExistsResp (Result Http.Error Bool)
|
| NameExistsResp (Result Http.Error Bool)
|
||||||
| UpdateThrottle
|
| UpdateThrottle
|
||||||
|
|
||||||
@ -109,12 +114,12 @@ update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
|||||||
update flags msg model =
|
update flags msg model =
|
||||||
let
|
let
|
||||||
nameCheck1 name =
|
nameCheck1 name =
|
||||||
Api.bookmarkNameExists flags model.location name NameExistsResp
|
Api.bookmarkNameExists flags name NameExistsResp
|
||||||
|
|
||||||
nameCheck2 loc =
|
nameCheck2 =
|
||||||
case model.name of
|
case model.name of
|
||||||
Just n ->
|
Just n ->
|
||||||
Api.bookmarkNameExists flags loc n NameExistsResp
|
Api.bookmarkNameExists flags n NameExistsResp
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
Cmd.none
|
Cmd.none
|
||||||
@ -135,12 +140,12 @@ update flags msg model =
|
|||||||
, throttleSub
|
, throttleSub
|
||||||
)
|
)
|
||||||
|
|
||||||
SetLocation loc ->
|
SetPersonal flag ->
|
||||||
let
|
let
|
||||||
( newThrottle, cmd ) =
|
( newThrottle, cmd ) =
|
||||||
Throttle.try (nameCheck2 loc) model.nameExistsThrottle
|
Throttle.try nameCheck2 model.nameExistsThrottle
|
||||||
in
|
in
|
||||||
( { model | location = loc, nameExistsThrottle = newThrottle }, cmd, throttleSub )
|
( { model | isPersonal = flag, nameExistsThrottle = newThrottle }, cmd, throttleSub )
|
||||||
|
|
||||||
QueryMsg lm ->
|
QueryMsg lm ->
|
||||||
let
|
let
|
||||||
@ -224,8 +229,8 @@ view texts model =
|
|||||||
[ label [ class "inline-flex items-center" ]
|
[ label [ class "inline-flex items-center" ]
|
||||||
[ input
|
[ input
|
||||||
[ type_ "radio"
|
[ type_ "radio"
|
||||||
, checked (model.location == User)
|
, checked model.isPersonal
|
||||||
, onCheck (\_ -> SetLocation User)
|
, onCheck (\_ -> SetPersonal True)
|
||||||
, class S.radioInput
|
, class S.radioInput
|
||||||
]
|
]
|
||||||
[]
|
[]
|
||||||
@ -235,9 +240,9 @@ view texts model =
|
|||||||
, label [ class "inline-flex items-center" ]
|
, label [ class "inline-flex items-center" ]
|
||||||
[ input
|
[ input
|
||||||
[ type_ "radio"
|
[ type_ "radio"
|
||||||
, checked (model.location == Collective)
|
, checked (not model.isPersonal)
|
||||||
, class S.radioInput
|
, class S.radioInput
|
||||||
, onCheck (\_ -> SetLocation Collective)
|
, onCheck (\_ -> SetPersonal False)
|
||||||
]
|
]
|
||||||
[]
|
[]
|
||||||
, span [ class "ml-2" ] [ text texts.collectiveLocation ]
|
, span [ class "ml-2" ] [ text texts.collectiveLocation ]
|
||||||
|
@ -2,12 +2,12 @@ module Comp.BookmarkQueryManage exposing (..)
|
|||||||
|
|
||||||
import Api
|
import Api
|
||||||
import Api.Model.BasicResult exposing (BasicResult)
|
import Api.Model.BasicResult exposing (BasicResult)
|
||||||
|
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||||
import Comp.Basic as B
|
import Comp.Basic as B
|
||||||
import Comp.BookmarkQueryForm
|
import Comp.BookmarkQueryForm
|
||||||
import Data.BookmarkedQuery exposing (BookmarkedQueryDef)
|
|
||||||
import Data.Flags exposing (Flags)
|
import Data.Flags exposing (Flags)
|
||||||
import Html exposing (Html, div, text)
|
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 Html.Events exposing (onClick)
|
||||||
import Http
|
import Http
|
||||||
import Messages.Comp.BookmarkQueryManage exposing (Texts)
|
import Messages.Comp.BookmarkQueryManage exposing (Texts)
|
||||||
@ -55,7 +55,7 @@ type Msg
|
|||||||
|
|
||||||
|
|
||||||
type FormResult
|
type FormResult
|
||||||
= Submitted BookmarkedQueryDef
|
= Submitted BookmarkedQuery
|
||||||
| Cancelled
|
| Cancelled
|
||||||
| Done
|
| Done
|
||||||
| None
|
| None
|
||||||
@ -117,7 +117,7 @@ update flags msg model =
|
|||||||
{ empty | model = { model | loading = False, formState = FormStateError err } }
|
{ empty | model = { model | loading = False, formState = FormStateError err } }
|
||||||
|
|
||||||
|
|
||||||
save : Flags -> BookmarkedQueryDef -> Cmd Msg
|
save : Flags -> BookmarkedQuery -> Cmd Msg
|
||||||
save flags model =
|
save flags model =
|
||||||
Api.addBookmark flags model SaveResp
|
Api.addBookmark flags model SaveResp
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ module Comp.BookmarkTable exposing
|
|||||||
, view
|
, view
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import Api.Model.BookmarkedQuery exposing (BookmarkedQuery)
|
||||||
import Comp.Basic as B
|
import Comp.Basic as B
|
||||||
import Data.BookmarkedQuery exposing (BookmarkedQuery, Bookmarks)
|
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Messages.Comp.BookmarkTable exposing (Texts)
|
import Messages.Comp.BookmarkTable exposing (Texts)
|
||||||
@ -39,7 +39,7 @@ update msg =
|
|||||||
--- View
|
--- View
|
||||||
|
|
||||||
|
|
||||||
view : Texts -> Bookmarks -> Html Msg
|
view : Texts -> List BookmarkedQuery -> Html Msg
|
||||||
view texts bms =
|
view texts bms =
|
||||||
table [ class S.tableMain ]
|
table [ class S.tableMain ]
|
||||||
[ thead []
|
[ thead []
|
||||||
@ -51,7 +51,7 @@ view texts bms =
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
, tbody []
|
, 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.MenuBar as MB
|
||||||
import Comp.Tabs
|
import Comp.Tabs
|
||||||
import Comp.TagSelect
|
import Comp.TagSelect
|
||||||
import Data.BookmarkedQuery exposing (AllBookmarks)
|
import Data.Bookmarks exposing (AllBookmarks)
|
||||||
import Data.CustomFieldChange exposing (CustomFieldValueCollect)
|
import Data.CustomFieldChange exposing (CustomFieldValueCollect)
|
||||||
import Data.Direction exposing (Direction)
|
import Data.Direction exposing (Direction)
|
||||||
import Data.DropdownStyle as DS
|
import Data.DropdownStyle as DS
|
||||||
@ -146,7 +146,7 @@ init flags =
|
|||||||
, customFieldModel = Comp.CustomFieldMultiInput.initWith []
|
, customFieldModel = Comp.CustomFieldMultiInput.initWith []
|
||||||
, customValues = Data.CustomFieldChange.emptyCollect
|
, customValues = Data.CustomFieldChange.emptyCollect
|
||||||
, sourceModel = Nothing
|
, sourceModel = Nothing
|
||||||
, allBookmarks = Comp.BookmarkChooser.init Data.BookmarkedQuery.allBookmarksEmpty
|
, allBookmarks = Comp.BookmarkChooser.init Data.Bookmarks.empty
|
||||||
, selectedBookmarks = Comp.BookmarkChooser.emptySelection
|
, selectedBookmarks = Comp.BookmarkChooser.emptySelection
|
||||||
, openTabs = Set.fromList [ "Tags", "Inbox" ]
|
, openTabs = Set.fromList [ "Tags", "Inbox" ]
|
||||||
, searchMode = Data.SearchMode.Normal
|
, 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
|
Reference in New Issue
Block a user