mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-06 15:15:58 +00:00
Merge pull request #834 from eikek/feature/usersettings-in-db
Feature/usersettings in db
This commit is contained in:
commit
de19b1d216
@ -38,6 +38,7 @@ trait BackendApp[F[_]] {
|
|||||||
def folder: OFolder[F]
|
def folder: OFolder[F]
|
||||||
def customFields: OCustomFields[F]
|
def customFields: OCustomFields[F]
|
||||||
def simpleSearch: OSimpleSearch[F]
|
def simpleSearch: OSimpleSearch[F]
|
||||||
|
def clientSettings: OClientSettings[F]
|
||||||
}
|
}
|
||||||
|
|
||||||
object BackendApp {
|
object BackendApp {
|
||||||
@ -73,26 +74,28 @@ object BackendApp {
|
|||||||
folderImpl <- OFolder(store)
|
folderImpl <- OFolder(store)
|
||||||
customFieldsImpl <- OCustomFields(store)
|
customFieldsImpl <- OCustomFields(store)
|
||||||
simpleSearchImpl = OSimpleSearch(fulltextImpl, itemSearchImpl)
|
simpleSearchImpl = OSimpleSearch(fulltextImpl, itemSearchImpl)
|
||||||
|
clientSettingsImpl <- OClientSettings(store)
|
||||||
} yield new BackendApp[F] {
|
} yield new BackendApp[F] {
|
||||||
val login = loginImpl
|
val login = loginImpl
|
||||||
val signup = signupImpl
|
val signup = signupImpl
|
||||||
val collective = collImpl
|
val collective = collImpl
|
||||||
val source = sourceImpl
|
val source = sourceImpl
|
||||||
val tag = tagImpl
|
val tag = tagImpl
|
||||||
val equipment = equipImpl
|
val equipment = equipImpl
|
||||||
val organization = orgImpl
|
val organization = orgImpl
|
||||||
val upload = uploadImpl
|
val upload = uploadImpl
|
||||||
val node = nodeImpl
|
val node = nodeImpl
|
||||||
val job = jobImpl
|
val job = jobImpl
|
||||||
val item = itemImpl
|
val item = itemImpl
|
||||||
val itemSearch = itemSearchImpl
|
val itemSearch = itemSearchImpl
|
||||||
val fulltext = fulltextImpl
|
val fulltext = fulltextImpl
|
||||||
val mail = mailImpl
|
val mail = mailImpl
|
||||||
val joex = joexImpl
|
val joex = joexImpl
|
||||||
val userTask = userTaskImpl
|
val userTask = userTaskImpl
|
||||||
val folder = folderImpl
|
val folder = folderImpl
|
||||||
val customFields = customFieldsImpl
|
val customFields = customFieldsImpl
|
||||||
val simpleSearch = simpleSearchImpl
|
val simpleSearch = simpleSearchImpl
|
||||||
|
val clientSettings = clientSettingsImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
def apply[F[_]: ConcurrentEffect: ContextShift](
|
def apply[F[_]: ConcurrentEffect: ContextShift](
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
package docspell.backend.ops
|
||||||
|
|
||||||
|
import cats.data.OptionT
|
||||||
|
import cats.effect.{Effect, Resource}
|
||||||
|
import cats.implicits._
|
||||||
|
|
||||||
|
import docspell.common.AccountId
|
||||||
|
import docspell.common._
|
||||||
|
import docspell.common.syntax.all._
|
||||||
|
import docspell.store.Store
|
||||||
|
import docspell.store.records.RClientSettings
|
||||||
|
import docspell.store.records.RUser
|
||||||
|
|
||||||
|
import io.circe.Json
|
||||||
|
import org.log4s._
|
||||||
|
|
||||||
|
trait OClientSettings[F[_]] {
|
||||||
|
|
||||||
|
def delete(clientId: Ident, account: AccountId): F[Boolean]
|
||||||
|
def save(clientId: Ident, account: AccountId, data: Json): F[Unit]
|
||||||
|
def load(clientId: Ident, account: AccountId): F[Option[RClientSettings]]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object OClientSettings {
|
||||||
|
private[this] val logger = getLogger
|
||||||
|
|
||||||
|
def apply[F[_]: Effect](store: Store[F]): Resource[F, OClientSettings[F]] =
|
||||||
|
Resource.pure[F, OClientSettings[F]](new OClientSettings[F] {
|
||||||
|
|
||||||
|
private def getUserId(account: AccountId): OptionT[F, Ident] =
|
||||||
|
OptionT(store.transact(RUser.findByAccount(account))).map(_.uid)
|
||||||
|
|
||||||
|
def delete(clientId: Ident, account: AccountId): F[Boolean] =
|
||||||
|
(for {
|
||||||
|
_ <- OptionT.liftF(
|
||||||
|
logger.fdebug(
|
||||||
|
s"Deleting client settings for client ${clientId.id} and account $account"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
userId <- getUserId(account)
|
||||||
|
n <- OptionT.liftF(
|
||||||
|
store.transact(
|
||||||
|
RClientSettings.delete(clientId, userId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} yield n > 0).getOrElse(false)
|
||||||
|
|
||||||
|
def save(clientId: Ident, account: AccountId, data: Json): F[Unit] =
|
||||||
|
(for {
|
||||||
|
_ <- OptionT.liftF(
|
||||||
|
logger.fdebug(
|
||||||
|
s"Storing client settings for client ${clientId.id} and account $account"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
userId <- getUserId(account)
|
||||||
|
n <- OptionT.liftF(
|
||||||
|
store.transact(RClientSettings.upsert(clientId, userId, data))
|
||||||
|
)
|
||||||
|
_ <- OptionT.liftF(
|
||||||
|
if (n <= 0) Effect[F].raiseError(new Exception("No rows updated!"))
|
||||||
|
else ().pure[F]
|
||||||
|
)
|
||||||
|
} yield ()).getOrElse(())
|
||||||
|
|
||||||
|
def load(clientId: Ident, account: AccountId): F[Option[RClientSettings]] =
|
||||||
|
(for {
|
||||||
|
_ <- OptionT.liftF(
|
||||||
|
logger.fdebug(
|
||||||
|
s"Loading client settings for client ${clientId.id} and account $account"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
userId <- getUserId(account)
|
||||||
|
data <- OptionT(store.transact(RClientSettings.find(clientId, userId)))
|
||||||
|
} yield data).value
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
@ -1185,6 +1185,68 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/BasicResult"
|
$ref: "#/components/schemas/BasicResult"
|
||||||
|
|
||||||
|
/sec/clientSettings/{clientId}:
|
||||||
|
parameters:
|
||||||
|
- $ref: "#/components/parameters/clientId"
|
||||||
|
get:
|
||||||
|
tags: [ Client Settings ]
|
||||||
|
summary: Return the current user settings
|
||||||
|
description: |
|
||||||
|
Returns the settings for the current user. The `clientId` is
|
||||||
|
an identifier to a client application. It returns a JSON
|
||||||
|
structure. The server doesn't care about the actual data,
|
||||||
|
since it is meant to be interpreted by clients.
|
||||||
|
security:
|
||||||
|
- authTokenHeader: []
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {}
|
||||||
|
put:
|
||||||
|
tags: [ Client Settings ]
|
||||||
|
summary: Update current user settings
|
||||||
|
description: |
|
||||||
|
Updates (replaces or creates) the current user's settings with
|
||||||
|
the given data. The `clientId` is an identifier to a client
|
||||||
|
application. The request body is expected to be JSON, the
|
||||||
|
structure is not important to the server.
|
||||||
|
|
||||||
|
The data is stored for the current user and given `clientId`.
|
||||||
|
|
||||||
|
The data is only saved without being checked in any way
|
||||||
|
(besides being valid JSON). It is returned "as is" to the
|
||||||
|
client in the corresponding GET endpoint.
|
||||||
|
security:
|
||||||
|
- authTokenHeader: []
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {}
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/BasicResult"
|
||||||
|
delete:
|
||||||
|
tags: [ Client Settings ]
|
||||||
|
summary: Clears the current user settings
|
||||||
|
description: |
|
||||||
|
Removes all stored user settings for the client identified by
|
||||||
|
`clientId`.
|
||||||
|
security:
|
||||||
|
- authTokenHeader: []
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/BasicResult"
|
||||||
|
|
||||||
/admin/user/resetPassword:
|
/admin/user/resetPassword:
|
||||||
post:
|
post:
|
||||||
tags: [ Collective, Admin ]
|
tags: [ Collective, Admin ]
|
||||||
@ -5571,3 +5633,11 @@ components:
|
|||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
clientId:
|
||||||
|
name: clientId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
some identifier for a client application
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
@ -91,7 +91,8 @@ object RestServer {
|
|||||||
"calevent/check" -> CalEventCheckRoutes(),
|
"calevent/check" -> CalEventCheckRoutes(),
|
||||||
"fts" -> FullTextIndexRoutes.secured(cfg, restApp.backend, token),
|
"fts" -> FullTextIndexRoutes.secured(cfg, restApp.backend, token),
|
||||||
"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)
|
||||||
)
|
)
|
||||||
|
|
||||||
def openRoutes[F[_]: Effect](cfg: Config, restApp: RestApp[F]): HttpRoutes[F] =
|
def openRoutes[F[_]: Effect](cfg: Config, restApp: RestApp[F]): HttpRoutes[F] =
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package docspell.restserver.routes
|
||||||
|
|
||||||
|
import cats.effect._
|
||||||
|
import cats.implicits._
|
||||||
|
|
||||||
|
import docspell.backend.BackendApp
|
||||||
|
import docspell.backend.auth.AuthToken
|
||||||
|
import docspell.common._
|
||||||
|
import docspell.restapi.model._
|
||||||
|
|
||||||
|
import io.circe.Json
|
||||||
|
import org.http4s.HttpRoutes
|
||||||
|
import org.http4s.circe.CirceEntityDecoder._
|
||||||
|
import org.http4s.circe.CirceEntityEncoder._
|
||||||
|
import org.http4s.dsl.Http4sDsl
|
||||||
|
|
||||||
|
object ClientSettingsRoutes {
|
||||||
|
|
||||||
|
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
|
||||||
|
val dsl = new Http4sDsl[F] {}
|
||||||
|
import dsl._
|
||||||
|
|
||||||
|
HttpRoutes.of {
|
||||||
|
case req @ PUT -> Root / Ident(clientId) =>
|
||||||
|
for {
|
||||||
|
data <- req.as[Json]
|
||||||
|
_ <- backend.clientSettings.save(clientId, user.account, data)
|
||||||
|
res <- Ok(BasicResult(true, "Settings stored"))
|
||||||
|
} yield res
|
||||||
|
|
||||||
|
case GET -> Root / Ident(clientId) =>
|
||||||
|
for {
|
||||||
|
data <- backend.clientSettings.load(clientId, user.account)
|
||||||
|
res <- data match {
|
||||||
|
case Some(d) => Ok(d.settingsData)
|
||||||
|
case None => NotFound()
|
||||||
|
}
|
||||||
|
} yield res
|
||||||
|
|
||||||
|
case DELETE -> Root / Ident(clientId) =>
|
||||||
|
for {
|
||||||
|
flag <- backend.clientSettings.delete(clientId, user.account)
|
||||||
|
res <- Ok(
|
||||||
|
BasicResult(
|
||||||
|
flag,
|
||||||
|
if (flag) "Settings deleted" else "Deleting settings failed"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} yield res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE "client_settings" (
|
||||||
|
"id" varchar(254) not null primary key,
|
||||||
|
"client_id" varchar(254) not null,
|
||||||
|
"user_id" varchar(254) not null,
|
||||||
|
"settings_data" text not null,
|
||||||
|
"created" timestamp not null,
|
||||||
|
"updated" timestamp not null,
|
||||||
|
foreign key ("user_id") references "user_"("uid") on delete cascade,
|
||||||
|
unique ("client_id", "user_id")
|
||||||
|
);
|
@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE `client_settings` (
|
||||||
|
`id` varchar(254) not null primary key,
|
||||||
|
`client_id` varchar(254) not null,
|
||||||
|
`user_id` varchar(254) not null,
|
||||||
|
`settings_data` longtext not null,
|
||||||
|
`created` timestamp not null,
|
||||||
|
`updated` timestamp not null,
|
||||||
|
foreign key (`user_id`) references `user_`(`uid`) on delete cascade,
|
||||||
|
unique (`client_id`, `user_id`)
|
||||||
|
);
|
@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE "client_settings" (
|
||||||
|
"id" varchar(254) not null primary key,
|
||||||
|
"client_id" varchar(254) not null,
|
||||||
|
"user_id" varchar(254) not null,
|
||||||
|
"settings_data" text not null,
|
||||||
|
"created" timestamp not null,
|
||||||
|
"updated" timestamp not null,
|
||||||
|
foreign key ("user_id") references "user_"("uid") on delete cascade,
|
||||||
|
unique ("client_id", "user_id")
|
||||||
|
);
|
@ -11,6 +11,7 @@ import doobie._
|
|||||||
import doobie.implicits.legacy.instant._
|
import doobie.implicits.legacy.instant._
|
||||||
import doobie.util.log.Success
|
import doobie.util.log.Success
|
||||||
import emil.doobie.EmilDoobieMeta
|
import emil.doobie.EmilDoobieMeta
|
||||||
|
import io.circe.Json
|
||||||
import io.circe.{Decoder, Encoder}
|
import io.circe.{Decoder, Encoder}
|
||||||
|
|
||||||
trait DoobieMeta extends EmilDoobieMeta {
|
trait DoobieMeta extends EmilDoobieMeta {
|
||||||
@ -112,10 +113,18 @@ trait DoobieMeta extends EmilDoobieMeta {
|
|||||||
|
|
||||||
implicit val metaOrgUse: Meta[OrgUse] =
|
implicit val metaOrgUse: Meta[OrgUse] =
|
||||||
Meta[String].timap(OrgUse.unsafeFromString)(_.name)
|
Meta[String].timap(OrgUse.unsafeFromString)(_.name)
|
||||||
|
|
||||||
|
implicit val metaJsonString: Meta[Json] =
|
||||||
|
Meta[String].timap(DoobieMeta.parseJsonUnsafe)(_.noSpaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
object DoobieMeta extends DoobieMeta {
|
object DoobieMeta extends DoobieMeta {
|
||||||
import org.log4s._
|
import org.log4s._
|
||||||
private val logger = getLogger
|
private val logger = getLogger
|
||||||
|
|
||||||
|
private def parseJsonUnsafe(str: String): Json =
|
||||||
|
io.circe.parser
|
||||||
|
.parse(str)
|
||||||
|
.fold(throw _, identity)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package docspell.store.records
|
||||||
|
|
||||||
|
import cats.data.NonEmptyList
|
||||||
|
import cats.implicits._
|
||||||
|
|
||||||
|
import docspell.common._
|
||||||
|
import docspell.store.qb.DSL._
|
||||||
|
import docspell.store.qb._
|
||||||
|
|
||||||
|
import doobie._
|
||||||
|
import doobie.implicits._
|
||||||
|
import io.circe.Json
|
||||||
|
|
||||||
|
case class RClientSettings(
|
||||||
|
id: Ident,
|
||||||
|
clientId: Ident,
|
||||||
|
userId: Ident,
|
||||||
|
settingsData: Json,
|
||||||
|
updated: Timestamp,
|
||||||
|
created: Timestamp
|
||||||
|
) {}
|
||||||
|
|
||||||
|
object RClientSettings {
|
||||||
|
|
||||||
|
final case class Table(alias: Option[String]) extends TableDef {
|
||||||
|
val tableName = "client_settings"
|
||||||
|
|
||||||
|
val id = Column[Ident]("id", this)
|
||||||
|
val clientId = Column[Ident]("client_id", this)
|
||||||
|
val userId = Column[Ident]("user_id", this)
|
||||||
|
val settingsData = Column[Json]("settings_data", this)
|
||||||
|
val updated = Column[Timestamp]("updated", this)
|
||||||
|
val created = Column[Timestamp]("created", this)
|
||||||
|
val all =
|
||||||
|
NonEmptyList.of[Column[_]](id, clientId, userId, settingsData, updated, created)
|
||||||
|
}
|
||||||
|
|
||||||
|
def as(alias: String): Table = Table(Some(alias))
|
||||||
|
val T = Table(None)
|
||||||
|
|
||||||
|
def insert(v: RClientSettings): ConnectionIO[Int] = {
|
||||||
|
val t = Table(None)
|
||||||
|
DML.insert(
|
||||||
|
t,
|
||||||
|
t.all,
|
||||||
|
fr"${v.id},${v.clientId},${v.userId},${v.settingsData},${v.updated},${v.created}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateSettings(
|
||||||
|
clientId: Ident,
|
||||||
|
userId: Ident,
|
||||||
|
data: Json,
|
||||||
|
updateTs: Timestamp
|
||||||
|
): ConnectionIO[Int] =
|
||||||
|
DML.update(
|
||||||
|
T,
|
||||||
|
T.clientId === clientId && T.userId === userId,
|
||||||
|
DML.set(T.settingsData.setTo(data), T.updated.setTo(updateTs))
|
||||||
|
)
|
||||||
|
|
||||||
|
def upsert(clientId: Ident, userId: Ident, data: Json): ConnectionIO[Int] =
|
||||||
|
for {
|
||||||
|
id <- Ident.randomId[ConnectionIO]
|
||||||
|
now <- Timestamp.current[ConnectionIO]
|
||||||
|
nup <- updateSettings(clientId, userId, data, now)
|
||||||
|
nin <-
|
||||||
|
if (nup <= 0) insert(RClientSettings(id, clientId, userId, data, now, now))
|
||||||
|
else 0.pure[ConnectionIO]
|
||||||
|
} yield nup + nin
|
||||||
|
|
||||||
|
def delete(clientId: Ident, userId: Ident): ConnectionIO[Int] =
|
||||||
|
DML.delete(T, T.clientId === clientId && T.userId === userId)
|
||||||
|
|
||||||
|
def find(clientId: Ident, userId: Ident): ConnectionIO[Option[RClientSettings]] =
|
||||||
|
run(select(T.all), from(T), T.clientId === clientId && T.userId === userId)
|
||||||
|
.query[RClientSettings]
|
||||||
|
.option
|
||||||
|
}
|
@ -37,6 +37,7 @@ module Api exposing
|
|||||||
, deleteUser
|
, deleteUser
|
||||||
, fileURL
|
, fileURL
|
||||||
, getAttachmentMeta
|
, getAttachmentMeta
|
||||||
|
, getClientSettings
|
||||||
, getCollective
|
, getCollective
|
||||||
, getCollectiveSettings
|
, getCollectiveSettings
|
||||||
, getContacts
|
, getContacts
|
||||||
@ -51,7 +52,6 @@ module Api exposing
|
|||||||
, getJobQueueState
|
, getJobQueueState
|
||||||
, getJobQueueStateIn
|
, getJobQueueStateIn
|
||||||
, getMailSettings
|
, getMailSettings
|
||||||
, getNewUi
|
|
||||||
, getNotifyDueItems
|
, getNotifyDueItems
|
||||||
, getOrgFull
|
, getOrgFull
|
||||||
, getOrgLight
|
, getOrgLight
|
||||||
@ -92,6 +92,7 @@ module Api exposing
|
|||||||
, removeTagsMultiple
|
, removeTagsMultiple
|
||||||
, reprocessItem
|
, reprocessItem
|
||||||
, reprocessMultiple
|
, reprocessMultiple
|
||||||
|
, saveClientSettings
|
||||||
, sendMail
|
, sendMail
|
||||||
, setAttachmentName
|
, setAttachmentName
|
||||||
, setCollectiveSettings
|
, setCollectiveSettings
|
||||||
@ -124,7 +125,6 @@ module Api exposing
|
|||||||
, startOnceScanMailbox
|
, startOnceScanMailbox
|
||||||
, startReIndex
|
, startReIndex
|
||||||
, submitNotifyDueItems
|
, submitNotifyDueItems
|
||||||
, toggleNewUi
|
|
||||||
, toggleTags
|
, toggleTags
|
||||||
, unconfirmMultiple
|
, unconfirmMultiple
|
||||||
, updateNotifyDueItems
|
, updateNotifyDueItems
|
||||||
@ -206,8 +206,10 @@ import Api.Model.VersionInfo exposing (VersionInfo)
|
|||||||
import Data.ContactType exposing (ContactType)
|
import Data.ContactType exposing (ContactType)
|
||||||
import Data.Flags exposing (Flags)
|
import Data.Flags exposing (Flags)
|
||||||
import Data.Priority exposing (Priority)
|
import Data.Priority exposing (Priority)
|
||||||
|
import Data.UiSettings exposing (UiSettings)
|
||||||
import File exposing (File)
|
import File exposing (File)
|
||||||
import Http
|
import Http
|
||||||
|
import Json.Decode as JsonDecode
|
||||||
import Json.Encode as JsonEncode
|
import Json.Encode as JsonEncode
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
import Task
|
import Task
|
||||||
@ -1982,21 +1984,40 @@ getItemProposals flags item receive =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
toggleNewUi : Flags -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
|
||||||
toggleNewUi flags receive =
|
--- Client Settings
|
||||||
Http2.authPost
|
|
||||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/newui"
|
|
||||||
|
getClientSettings : Flags -> (Result Http.Error UiSettings -> msg) -> Cmd msg
|
||||||
|
getClientSettings flags receive =
|
||||||
|
let
|
||||||
|
defaults =
|
||||||
|
Data.UiSettings.defaults
|
||||||
|
|
||||||
|
decoder =
|
||||||
|
JsonDecode.map (\s -> Data.UiSettings.merge s defaults)
|
||||||
|
Data.UiSettings.storedUiSettingsDecoder
|
||||||
|
in
|
||||||
|
Http2.authGet
|
||||||
|
{ url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/webClient"
|
||||||
, account = getAccount flags
|
, account = getAccount flags
|
||||||
, body = Http.emptyBody
|
, expect = Http.expectJson receive decoder
|
||||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getNewUi : Flags -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
saveClientSettings : Flags -> UiSettings -> (Result Http.Error BasicResult -> msg) -> Cmd msg
|
||||||
getNewUi flags receive =
|
saveClientSettings flags settings receive =
|
||||||
Http2.authGet
|
let
|
||||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/newui"
|
storedSettings =
|
||||||
|
Data.UiSettings.toStoredUiSettings settings
|
||||||
|
|
||||||
|
encode =
|
||||||
|
Data.UiSettings.storedUiSettingsEncode storedSettings
|
||||||
|
in
|
||||||
|
Http2.authPut
|
||||||
|
{ url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/webClient"
|
||||||
, account = getAccount flags
|
, account = getAccount flags
|
||||||
|
, body = Http.jsonBody encode
|
||||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,11 +7,12 @@ module App.Data exposing
|
|||||||
)
|
)
|
||||||
|
|
||||||
import Api.Model.AuthResult exposing (AuthResult)
|
import Api.Model.AuthResult exposing (AuthResult)
|
||||||
|
import Api.Model.BasicResult exposing (BasicResult)
|
||||||
import Api.Model.VersionInfo exposing (VersionInfo)
|
import Api.Model.VersionInfo exposing (VersionInfo)
|
||||||
import Browser exposing (UrlRequest)
|
import Browser exposing (UrlRequest)
|
||||||
import Browser.Navigation exposing (Key)
|
import Browser.Navigation exposing (Key)
|
||||||
import Data.Flags exposing (Flags)
|
import Data.Flags exposing (Flags)
|
||||||
import Data.UiSettings exposing (UiSettings)
|
import Data.UiSettings exposing (StoredUiSettings, UiSettings)
|
||||||
import Data.UiTheme exposing (UiTheme)
|
import Data.UiTheme exposing (UiTheme)
|
||||||
import Http
|
import Http
|
||||||
import Messages.UiLanguage exposing (UiLanguage)
|
import Messages.UiLanguage exposing (UiLanguage)
|
||||||
@ -155,11 +156,13 @@ type Msg
|
|||||||
| SessionCheckResp (Result Http.Error AuthResult)
|
| SessionCheckResp (Result Http.Error AuthResult)
|
||||||
| ToggleNavMenu
|
| ToggleNavMenu
|
||||||
| ToggleUserMenu
|
| ToggleUserMenu
|
||||||
| GetUiSettings UiSettings
|
| GetUiSettings (Result Http.Error UiSettings)
|
||||||
| ToggleSidebar
|
| ToggleSidebar
|
||||||
| ToggleDarkMode
|
| ToggleDarkMode
|
||||||
| ToggleLangMenu
|
| ToggleLangMenu
|
||||||
| SetLanguage UiLanguage
|
| SetLanguage UiLanguage
|
||||||
|
| ClientSettingsSaveResp UiSettings (Result Http.Error BasicResult)
|
||||||
|
| ReceiveBrowserSettings StoredUiSettings
|
||||||
|
|
||||||
|
|
||||||
defaultPage : Flags -> Page
|
defaultPage : Flags -> Page
|
||||||
|
@ -8,6 +8,7 @@ import App.Data exposing (..)
|
|||||||
import Browser exposing (UrlRequest(..))
|
import Browser exposing (UrlRequest(..))
|
||||||
import Browser.Navigation as Nav
|
import Browser.Navigation as Nav
|
||||||
import Data.Flags
|
import Data.Flags
|
||||||
|
import Data.UiSettings exposing (UiSettings)
|
||||||
import Data.UiTheme
|
import Data.UiTheme
|
||||||
import Page exposing (Page(..))
|
import Page exposing (Page(..))
|
||||||
import Page.CollectiveSettings.Data
|
import Page.CollectiveSettings.Data
|
||||||
@ -65,11 +66,11 @@ updateWithSub msg model =
|
|||||||
{ settings | uiTheme = next }
|
{ settings | uiTheme = next }
|
||||||
in
|
in
|
||||||
-- when authenticated, store it in settings only
|
-- when authenticated, store it in settings only
|
||||||
-- once new settings arrive via a subscription,
|
-- once new settings are successfully saved (the
|
||||||
-- the ui is updated. so it is also updated on
|
-- response is arrived), the ui is updated. so it
|
||||||
-- page refresh
|
-- is also updated on page refresh
|
||||||
( { model | userMenuOpen = False }
|
( { model | userMenuOpen = False }
|
||||||
, Ports.storeUiSettings model.flags newSettings
|
, Api.saveClientSettings model.flags newSettings (ClientSettingsSaveResp newSettings)
|
||||||
, Sub.none
|
, Sub.none
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -84,6 +85,16 @@ updateWithSub msg model =
|
|||||||
, Sub.none
|
, Sub.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ClientSettingsSaveResp settings (Ok res) ->
|
||||||
|
if res.success then
|
||||||
|
applyClientSettings model settings
|
||||||
|
|
||||||
|
else
|
||||||
|
( model, Cmd.none, Sub.none )
|
||||||
|
|
||||||
|
ClientSettingsSaveResp _ (Err _) ->
|
||||||
|
( model, Cmd.none, Sub.none )
|
||||||
|
|
||||||
ToggleLangMenu ->
|
ToggleLangMenu ->
|
||||||
( { model | langMenuOpen = not model.langMenuOpen }
|
( { model | langMenuOpen = not model.langMenuOpen }
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
@ -258,22 +269,37 @@ updateWithSub msg model =
|
|||||||
, Sub.none
|
, Sub.none
|
||||||
)
|
)
|
||||||
|
|
||||||
GetUiSettings settings ->
|
GetUiSettings (Ok settings) ->
|
||||||
|
applyClientSettings model settings
|
||||||
|
|
||||||
|
GetUiSettings (Err _) ->
|
||||||
|
( model, Cmd.none, Sub.none )
|
||||||
|
|
||||||
|
ReceiveBrowserSettings sett ->
|
||||||
let
|
let
|
||||||
setTheme =
|
lm =
|
||||||
Ports.setUiTheme settings.uiTheme
|
Page.UserSettings.Data.ReceiveBrowserSettings sett
|
||||||
in
|
in
|
||||||
Util.Update.andThen2
|
updateUserSettings lm model
|
||||||
[ \m ->
|
|
||||||
( { m | sidebarVisible = settings.sideMenuVisible }
|
|
||||||
, setTheme
|
applyClientSettings : Model -> UiSettings -> ( Model, Cmd Msg, Sub Msg )
|
||||||
, Sub.none
|
applyClientSettings model settings =
|
||||||
)
|
let
|
||||||
, updateUserSettings Page.UserSettings.Data.UpdateSettings
|
setTheme =
|
||||||
, updateHome Page.Home.Data.UiSettingsUpdated
|
Ports.setUiTheme settings.uiTheme
|
||||||
, updateItemDetail Page.ItemDetail.Data.UiSettingsUpdated
|
in
|
||||||
]
|
Util.Update.andThen2
|
||||||
{ model | uiSettings = settings }
|
[ \m ->
|
||||||
|
( { m | sidebarVisible = settings.sideMenuVisible }
|
||||||
|
, setTheme
|
||||||
|
, Sub.none
|
||||||
|
)
|
||||||
|
, updateUserSettings Page.UserSettings.Data.UpdateSettings
|
||||||
|
, updateHome Page.Home.Data.UiSettingsUpdated
|
||||||
|
, updateItemDetail Page.ItemDetail.Data.UiSettingsUpdated
|
||||||
|
]
|
||||||
|
{ model | uiSettings = settings }
|
||||||
|
|
||||||
|
|
||||||
updateItemDetail : Page.ItemDetail.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
updateItemDetail : Page.ItemDetail.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
||||||
@ -360,14 +386,29 @@ updateQueue lmsg model =
|
|||||||
updateUserSettings : Page.UserSettings.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
updateUserSettings : Page.UserSettings.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
||||||
updateUserSettings lmsg model =
|
updateUserSettings lmsg model =
|
||||||
let
|
let
|
||||||
( lm, lc, ls ) =
|
result =
|
||||||
Page.UserSettings.Update.update model.flags model.uiSettings lmsg model.userSettingsModel
|
Page.UserSettings.Update.update model.flags model.uiSettings lmsg model.userSettingsModel
|
||||||
|
|
||||||
|
model_ =
|
||||||
|
{ model | userSettingsModel = result.model }
|
||||||
|
|
||||||
|
( lm2, lc2, s2 ) =
|
||||||
|
case result.newSettings of
|
||||||
|
Just sett ->
|
||||||
|
applyClientSettings model_ sett
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
( model_, Cmd.none, Sub.none )
|
||||||
in
|
in
|
||||||
( { model
|
( lm2
|
||||||
| userSettingsModel = lm
|
, Cmd.batch
|
||||||
}
|
[ Cmd.map UserSettingsMsg result.cmd
|
||||||
, Cmd.map UserSettingsMsg lc
|
, lc2
|
||||||
, Sub.map UserSettingsMsg ls
|
]
|
||||||
|
, Sub.batch
|
||||||
|
[ Sub.map UserSettingsMsg result.sub
|
||||||
|
, s2
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -415,14 +456,29 @@ updateHome lmsg model =
|
|||||||
_ ->
|
_ ->
|
||||||
Nothing
|
Nothing
|
||||||
|
|
||||||
( lm, lc, ls ) =
|
result =
|
||||||
Page.Home.Update.update mid model.key model.flags model.uiSettings lmsg model.homeModel
|
Page.Home.Update.update mid model.key model.flags model.uiSettings lmsg model.homeModel
|
||||||
|
|
||||||
|
model_ =
|
||||||
|
{ model | homeModel = result.model }
|
||||||
|
|
||||||
|
( lm, lc, ls ) =
|
||||||
|
case result.newSettings of
|
||||||
|
Just sett ->
|
||||||
|
applyClientSettings model_ sett
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
( model_, Cmd.none, Sub.none )
|
||||||
in
|
in
|
||||||
( { model
|
( lm
|
||||||
| homeModel = lm
|
, Cmd.batch
|
||||||
}
|
[ Cmd.map HomeMsg result.cmd
|
||||||
, Cmd.map HomeMsg lc
|
, lc
|
||||||
, Sub.map HomeMsg ls
|
]
|
||||||
|
, Sub.batch
|
||||||
|
[ Sub.map HomeMsg result.sub
|
||||||
|
, ls
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -463,9 +463,13 @@ update sett msg model =
|
|||||||
tagColorViewOpts2 : Texts -> Comp.ColorTagger.ViewOpts
|
tagColorViewOpts2 : Texts -> Comp.ColorTagger.ViewOpts
|
||||||
tagColorViewOpts2 texts =
|
tagColorViewOpts2 texts =
|
||||||
{ renderItem =
|
{ renderItem =
|
||||||
\( _, v ) ->
|
\( name, v ) ->
|
||||||
span [ class (" label " ++ Data.Color.toString2 v) ]
|
span [ class "flex inline-flex items-center" ]
|
||||||
[ text (texts.colorLabel v) ]
|
[ span [ class "mr-2" ] [ text name ]
|
||||||
|
, span [ class (" label " ++ Data.Color.toString2 v) ]
|
||||||
|
[ text (texts.colorLabel v)
|
||||||
|
]
|
||||||
|
]
|
||||||
, colorLabel = texts.colorLabel
|
, colorLabel = texts.colorLabel
|
||||||
, label = texts.chooseTagColorLabel
|
, label = texts.chooseTagColorLabel
|
||||||
, description = Just texts.tagColorDescription
|
, description = Just texts.tagColorDescription
|
||||||
|
@ -1,36 +1,49 @@
|
|||||||
module Comp.UiSettingsManage exposing
|
module Comp.UiSettingsManage exposing
|
||||||
( Model
|
( Model
|
||||||
, Msg(..)
|
, Msg(..)
|
||||||
|
, UpdateResult
|
||||||
, init
|
, init
|
||||||
, update
|
, update
|
||||||
, view2
|
, view2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import Api
|
||||||
import Api.Model.BasicResult exposing (BasicResult)
|
import Api.Model.BasicResult exposing (BasicResult)
|
||||||
import Comp.MenuBar as MB
|
import Comp.MenuBar as MB
|
||||||
import Comp.UiSettingsForm
|
import Comp.UiSettingsForm
|
||||||
|
import Comp.UiSettingsMigrate
|
||||||
import Data.Flags exposing (Flags)
|
import Data.Flags exposing (Flags)
|
||||||
import Data.UiSettings exposing (UiSettings)
|
import Data.UiSettings exposing (StoredUiSettings, UiSettings)
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (onClick)
|
import Http
|
||||||
import Messages.Comp.UiSettingsManage exposing (Texts)
|
import Messages.Comp.UiSettingsManage exposing (Texts)
|
||||||
import Ports
|
|
||||||
import Styles as S
|
import Styles as S
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ formModel : Comp.UiSettingsForm.Model
|
{ formModel : Comp.UiSettingsForm.Model
|
||||||
, settings : Maybe UiSettings
|
, settings : Maybe UiSettings
|
||||||
, message : Maybe BasicResult
|
, formResult : FormResult
|
||||||
|
, settingsMigrate : Comp.UiSettingsMigrate.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type FormResult
|
||||||
|
= FormInit
|
||||||
|
| FormUnchanged
|
||||||
|
| FormSaved
|
||||||
|
| FormHttpError Http.Error
|
||||||
|
| FormUnknownError
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= UiSettingsFormMsg Comp.UiSettingsForm.Msg
|
= UiSettingsFormMsg Comp.UiSettingsForm.Msg
|
||||||
|
| UiSettingsMigrateMsg Comp.UiSettingsMigrate.Msg
|
||||||
| Submit
|
| Submit
|
||||||
| SettingsSaved
|
|
||||||
| UpdateSettings
|
| UpdateSettings
|
||||||
|
| SaveSettingsResp UiSettings (Result Http.Error BasicResult)
|
||||||
|
| ReceiveBrowserSettings StoredUiSettings
|
||||||
|
|
||||||
|
|
||||||
init : Flags -> UiSettings -> ( Model, Cmd Msg )
|
init : Flags -> UiSettings -> ( Model, Cmd Msg )
|
||||||
@ -38,12 +51,19 @@ init flags settings =
|
|||||||
let
|
let
|
||||||
( fm, fc ) =
|
( fm, fc ) =
|
||||||
Comp.UiSettingsForm.init flags settings
|
Comp.UiSettingsForm.init flags settings
|
||||||
|
|
||||||
|
( mm, mc ) =
|
||||||
|
Comp.UiSettingsMigrate.init flags
|
||||||
in
|
in
|
||||||
( { formModel = fm
|
( { formModel = fm
|
||||||
, settings = Nothing
|
, settings = Nothing
|
||||||
, message = Nothing
|
, formResult = FormInit
|
||||||
|
, settingsMigrate = mm
|
||||||
}
|
}
|
||||||
, Cmd.map UiSettingsFormMsg fc
|
, Cmd.batch
|
||||||
|
[ Cmd.map UiSettingsFormMsg fc
|
||||||
|
, Cmd.map UiSettingsMigrateMsg mc
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +71,15 @@ init flags settings =
|
|||||||
--- update
|
--- update
|
||||||
|
|
||||||
|
|
||||||
update : Flags -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
type alias UpdateResult =
|
||||||
|
{ model : Model
|
||||||
|
, cmd : Cmd Msg
|
||||||
|
, sub : Sub Msg
|
||||||
|
, newSettings : Maybe UiSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update : Flags -> UiSettings -> Msg -> Model -> UpdateResult
|
||||||
update flags settings msg model =
|
update flags settings msg model =
|
||||||
case msg of
|
case msg of
|
||||||
UiSettingsFormMsg lm ->
|
UiSettingsFormMsg lm ->
|
||||||
@ -62,54 +90,89 @@ update flags settings msg model =
|
|||||||
( m_, sett ) =
|
( m_, sett ) =
|
||||||
Comp.UiSettingsForm.update inSettings lm model.formModel
|
Comp.UiSettingsForm.update inSettings lm model.formModel
|
||||||
in
|
in
|
||||||
( { model
|
{ model =
|
||||||
| formModel = m_
|
{ model
|
||||||
, settings =
|
| formModel = m_
|
||||||
if sett == Nothing then
|
, settings =
|
||||||
model.settings
|
if sett == Nothing then
|
||||||
|
model.settings
|
||||||
|
|
||||||
else
|
else
|
||||||
sett
|
sett
|
||||||
, message =
|
, formResult =
|
||||||
if sett /= Nothing then
|
if sett /= Nothing then
|
||||||
Nothing
|
FormInit
|
||||||
|
|
||||||
else
|
else
|
||||||
model.message
|
model.formResult
|
||||||
}
|
}
|
||||||
, Cmd.none
|
, cmd = Cmd.none
|
||||||
, Sub.none
|
, sub = Sub.none
|
||||||
)
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
UiSettingsMigrateMsg lm ->
|
||||||
|
let
|
||||||
|
result =
|
||||||
|
Comp.UiSettingsMigrate.update flags lm model.settingsMigrate
|
||||||
|
in
|
||||||
|
{ model = { model | settingsMigrate = result.model }
|
||||||
|
, cmd = Cmd.map UiSettingsMigrateMsg result.cmd
|
||||||
|
, sub = Sub.map UiSettingsMigrateMsg result.sub
|
||||||
|
, newSettings = result.newSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceiveBrowserSettings sett ->
|
||||||
|
let
|
||||||
|
lm =
|
||||||
|
UiSettingsMigrateMsg (Comp.UiSettingsMigrate.receiveBrowserSettings sett)
|
||||||
|
in
|
||||||
|
update flags settings lm model
|
||||||
|
|
||||||
Submit ->
|
Submit ->
|
||||||
case model.settings of
|
case model.settings of
|
||||||
Just s ->
|
Just s ->
|
||||||
( { model | message = Nothing }
|
{ model = { model | formResult = FormInit }
|
||||||
, Ports.storeUiSettings flags s
|
, cmd = Api.saveClientSettings flags s (SaveSettingsResp s)
|
||||||
, Ports.onUiSettingsSaved SettingsSaved
|
, sub = Sub.none
|
||||||
)
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
( { model | message = Just (BasicResult False "Settings unchanged or invalid.") }
|
{ model = { model | formResult = FormUnchanged }
|
||||||
, Cmd.none
|
, cmd = Cmd.none
|
||||||
, Sub.none
|
, sub = Sub.none
|
||||||
)
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
SettingsSaved ->
|
SaveSettingsResp newSettings (Ok res) ->
|
||||||
( { model | message = Just (BasicResult True "Settings saved.") }
|
if res.success then
|
||||||
, Cmd.none
|
{ model = { model | formResult = FormSaved }
|
||||||
, Sub.none
|
, cmd = Cmd.none
|
||||||
)
|
, sub = Sub.none
|
||||||
|
, newSettings = Just newSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{ model = { model | formResult = FormUnknownError }
|
||||||
|
, cmd = Cmd.none
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveSettingsResp _ (Err err) ->
|
||||||
|
UpdateResult { model | formResult = FormHttpError err } Cmd.none Sub.none Nothing
|
||||||
|
|
||||||
UpdateSettings ->
|
UpdateSettings ->
|
||||||
let
|
let
|
||||||
( fm, fc ) =
|
( fm, fc ) =
|
||||||
Comp.UiSettingsForm.init flags settings
|
Comp.UiSettingsForm.init flags settings
|
||||||
in
|
in
|
||||||
( { model | formModel = fm }
|
{ model = { model | formModel = fm }
|
||||||
, Cmd.map UiSettingsFormMsg fc
|
, cmd = Cmd.map UiSettingsFormMsg fc
|
||||||
, Sub.none
|
, sub = Sub.none
|
||||||
)
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -118,12 +181,26 @@ update flags settings msg model =
|
|||||||
|
|
||||||
isError : Model -> Bool
|
isError : Model -> Bool
|
||||||
isError model =
|
isError model =
|
||||||
Maybe.map .success model.message == Just False
|
case model.formResult of
|
||||||
|
FormSaved ->
|
||||||
|
False
|
||||||
|
|
||||||
|
FormInit ->
|
||||||
|
False
|
||||||
|
|
||||||
|
FormUnchanged ->
|
||||||
|
True
|
||||||
|
|
||||||
|
FormHttpError _ ->
|
||||||
|
True
|
||||||
|
|
||||||
|
FormUnknownError ->
|
||||||
|
True
|
||||||
|
|
||||||
|
|
||||||
isSuccess : Model -> Bool
|
isSuccess : Model -> Bool
|
||||||
isSuccess model =
|
isSuccess model =
|
||||||
Maybe.map .success model.message == Just True
|
not (isError model)
|
||||||
|
|
||||||
|
|
||||||
view2 : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg
|
view2 : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg
|
||||||
@ -141,16 +218,32 @@ view2 texts flags settings classes model =
|
|||||||
, end = []
|
, end = []
|
||||||
, rootClasses = "mb-4"
|
, rootClasses = "mb-4"
|
||||||
}
|
}
|
||||||
|
, div []
|
||||||
|
[ Html.map UiSettingsMigrateMsg
|
||||||
|
(Comp.UiSettingsMigrate.view model.settingsMigrate)
|
||||||
|
]
|
||||||
, div
|
, div
|
||||||
[ classList
|
[ classList
|
||||||
[ ( S.successMessage, isSuccess model )
|
[ ( S.successMessage, isSuccess model )
|
||||||
, ( S.errorMessage, isError model )
|
, ( S.errorMessage, isError model )
|
||||||
, ( "hidden", model.message == Nothing )
|
, ( "hidden", model.formResult == FormInit )
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[ Maybe.map .message model.message
|
[ case model.formResult of
|
||||||
|> Maybe.withDefault ""
|
FormInit ->
|
||||||
|> text
|
text ""
|
||||||
|
|
||||||
|
FormUnchanged ->
|
||||||
|
text texts.settingsUnchanged
|
||||||
|
|
||||||
|
FormHttpError err ->
|
||||||
|
text (texts.httpError err)
|
||||||
|
|
||||||
|
FormSaved ->
|
||||||
|
text texts.settingsSaved
|
||||||
|
|
||||||
|
FormUnknownError ->
|
||||||
|
text texts.unknownSaveError
|
||||||
]
|
]
|
||||||
, Html.map UiSettingsFormMsg
|
, Html.map UiSettingsFormMsg
|
||||||
(Comp.UiSettingsForm.view2
|
(Comp.UiSettingsForm.view2
|
||||||
|
186
modules/webapp/src/main/elm/Comp/UiSettingsMigrate.elm
Normal file
186
modules/webapp/src/main/elm/Comp/UiSettingsMigrate.elm
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
module Comp.UiSettingsMigrate exposing
|
||||||
|
( Model
|
||||||
|
, Msg
|
||||||
|
, UpdateResult
|
||||||
|
, init
|
||||||
|
, receiveBrowserSettings
|
||||||
|
, update
|
||||||
|
, view
|
||||||
|
)
|
||||||
|
|
||||||
|
import Api
|
||||||
|
import Api.Model.BasicResult exposing (BasicResult)
|
||||||
|
import Data.Flags exposing (Flags)
|
||||||
|
import Data.UiSettings exposing (StoredUiSettings, UiSettings)
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (class, href, title)
|
||||||
|
import Html.Events exposing (onClick)
|
||||||
|
import Http
|
||||||
|
import Messages.Comp.HttpError
|
||||||
|
import Ports
|
||||||
|
import Styles as S
|
||||||
|
|
||||||
|
|
||||||
|
init : Flags -> ( Model, Cmd Msg )
|
||||||
|
init flags =
|
||||||
|
( Initialized
|
||||||
|
, Cmd.batch
|
||||||
|
[ Api.getClientSettings flags GetClientSettingsResp
|
||||||
|
, requestBrowserSettings flags
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type Model
|
||||||
|
= Initialized
|
||||||
|
| WaitingForHttp StoredUiSettings
|
||||||
|
| WaitingForBrowser
|
||||||
|
| MigrateActive StoredUiSettings
|
||||||
|
| MigrateDone
|
||||||
|
| MigrateRequestRunning
|
||||||
|
| MigrateRequestFailed String
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= GetClientSettingsResp (Result Http.Error UiSettings)
|
||||||
|
| GetBrowserSettings StoredUiSettings
|
||||||
|
| MigrateSettings StoredUiSettings
|
||||||
|
| SaveSettingsResp UiSettings (Result Http.Error BasicResult)
|
||||||
|
|
||||||
|
|
||||||
|
receiveBrowserSettings : StoredUiSettings -> Msg
|
||||||
|
receiveBrowserSettings sett =
|
||||||
|
GetBrowserSettings sett
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Update
|
||||||
|
|
||||||
|
|
||||||
|
requestBrowserSettings : Flags -> Cmd Msg
|
||||||
|
requestBrowserSettings flags =
|
||||||
|
case flags.account of
|
||||||
|
Just acc ->
|
||||||
|
Ports.requestUiSettings acc
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
Cmd.none
|
||||||
|
|
||||||
|
|
||||||
|
type alias UpdateResult =
|
||||||
|
{ model : Model
|
||||||
|
, cmd : Cmd Msg
|
||||||
|
, sub : Sub Msg
|
||||||
|
, newSettings : Maybe UiSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update : Flags -> Msg -> Model -> UpdateResult
|
||||||
|
update flags msg model =
|
||||||
|
let
|
||||||
|
empty =
|
||||||
|
{ model = model
|
||||||
|
, cmd = Cmd.none
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
in
|
||||||
|
case msg of
|
||||||
|
GetClientSettingsResp (Err (Http.BadStatus 404)) ->
|
||||||
|
case model of
|
||||||
|
Initialized ->
|
||||||
|
{ model = WaitingForBrowser
|
||||||
|
, cmd = requestBrowserSettings flags
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitingForHttp sett ->
|
||||||
|
{ empty | model = MigrateActive sett }
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
{ empty
|
||||||
|
| sub = Sub.none
|
||||||
|
, cmd = requestBrowserSettings flags
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
|
||||||
|
GetBrowserSettings sett ->
|
||||||
|
case model of
|
||||||
|
Initialized ->
|
||||||
|
{ empty | model = WaitingForHttp sett }
|
||||||
|
|
||||||
|
WaitingForBrowser ->
|
||||||
|
{ empty | model = MigrateActive sett }
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
empty
|
||||||
|
|
||||||
|
GetClientSettingsResp _ ->
|
||||||
|
{ empty | model = MigrateDone }
|
||||||
|
|
||||||
|
MigrateSettings settings ->
|
||||||
|
let
|
||||||
|
uiSettings =
|
||||||
|
Data.UiSettings.merge settings Data.UiSettings.defaults
|
||||||
|
|
||||||
|
cmd =
|
||||||
|
Api.saveClientSettings flags uiSettings (SaveSettingsResp uiSettings)
|
||||||
|
in
|
||||||
|
{ empty | model = MigrateRequestRunning, cmd = cmd }
|
||||||
|
|
||||||
|
SaveSettingsResp settings (Ok res) ->
|
||||||
|
if res.success then
|
||||||
|
{ empty | model = MigrateDone, newSettings = Just settings }
|
||||||
|
|
||||||
|
else
|
||||||
|
{ empty | model = MigrateRequestFailed "Unknown error saving settings." }
|
||||||
|
|
||||||
|
SaveSettingsResp _ (Err err) ->
|
||||||
|
{ empty | model = MigrateRequestFailed <| Messages.Comp.HttpError.gb err }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- View
|
||||||
|
{-
|
||||||
|
Note: this module will be removed later, it only exists for the
|
||||||
|
transition from storing ui settings at the server. Therefore
|
||||||
|
strings here are not externalized; translation is not necessary.
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
case model of
|
||||||
|
MigrateActive sett ->
|
||||||
|
div
|
||||||
|
[ class (S.box ++ " px-2 py-2")
|
||||||
|
, class S.infoMessage
|
||||||
|
, class "flex flex-col"
|
||||||
|
]
|
||||||
|
[ div [ class S.header2 ] [ text "Migrate your settings" ]
|
||||||
|
, p [ class " mb-3" ]
|
||||||
|
[ text "The UI settings are now stored at the server. You have "
|
||||||
|
, text "settings stored at the browser that you can now move to the "
|
||||||
|
, text "server by clicking below."
|
||||||
|
]
|
||||||
|
, p [ class " mb-2" ]
|
||||||
|
[ text "Alternatively, change the default settings here and submit "
|
||||||
|
, text "this form. This message will disappear as soon as there are "
|
||||||
|
, text "settings at the server."
|
||||||
|
]
|
||||||
|
, div [ class "flex flex-row items-center justify-center" ]
|
||||||
|
[ a
|
||||||
|
[ href "#"
|
||||||
|
, title "Move current settings to the server"
|
||||||
|
, onClick (MigrateSettings sett)
|
||||||
|
, class S.primaryButton
|
||||||
|
]
|
||||||
|
[ text "Migrate current settings"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
span [ class "hidden" ] []
|
@ -15,6 +15,8 @@ module Data.UiSettings exposing
|
|||||||
, mergeDefaults
|
, mergeDefaults
|
||||||
, posFromString
|
, posFromString
|
||||||
, posToString
|
, posToString
|
||||||
|
, storedUiSettingsDecoder
|
||||||
|
, storedUiSettingsEncode
|
||||||
, tagColor
|
, tagColor
|
||||||
, tagColorFg2
|
, tagColorFg2
|
||||||
, tagColorString2
|
, tagColorString2
|
||||||
@ -30,6 +32,9 @@ import Data.UiTheme exposing (UiTheme)
|
|||||||
import Dict exposing (Dict)
|
import Dict exposing (Dict)
|
||||||
import Html exposing (Attribute)
|
import Html exposing (Attribute)
|
||||||
import Html.Attributes as HA
|
import Html.Attributes as HA
|
||||||
|
import Json.Decode as Decode
|
||||||
|
import Json.Decode.Pipeline as P
|
||||||
|
import Json.Encode as Encode
|
||||||
import Messages
|
import Messages
|
||||||
import Messages.UiLanguage exposing (UiLanguage)
|
import Messages.UiLanguage exposing (UiLanguage)
|
||||||
|
|
||||||
@ -67,6 +72,70 @@ type alias StoredUiSettings =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
storedUiSettingsDecoder : Decode.Decoder StoredUiSettings
|
||||||
|
storedUiSettingsDecoder =
|
||||||
|
let
|
||||||
|
maybeInt =
|
||||||
|
Decode.maybe Decode.int
|
||||||
|
|
||||||
|
maybeString =
|
||||||
|
Decode.maybe Decode.string
|
||||||
|
in
|
||||||
|
Decode.succeed StoredUiSettings
|
||||||
|
|> P.optional "itemSearchPageSize" maybeInt Nothing
|
||||||
|
|> P.optional "tagCategoryColors" (Decode.keyValuePairs Decode.string) []
|
||||||
|
|> P.optional "nativePdfPreview" Decode.bool False
|
||||||
|
|> P.optional "itemSearchNoteLength" maybeInt Nothing
|
||||||
|
|> P.optional "itemDetailNotesPosition" maybeString Nothing
|
||||||
|
|> P.optional "searchMenuFolderCount" maybeInt Nothing
|
||||||
|
|> P.optional "searchMenuTagCount" maybeInt Nothing
|
||||||
|
|> P.optional "searchMenuTagCatCount" maybeInt Nothing
|
||||||
|
|> P.optional "formFields" (Decode.maybe <| Decode.list Decode.string) Nothing
|
||||||
|
|> P.optional "itemDetailShortcuts" Decode.bool False
|
||||||
|
|> P.optional "searchMenuVisible" Decode.bool False
|
||||||
|
|> P.optional "editMenuVisible" Decode.bool False
|
||||||
|
|> P.optional "cardPreviewSize" maybeString Nothing
|
||||||
|
|> P.optional "cardTitleTemplate" maybeString Nothing
|
||||||
|
|> P.optional "cardSubtitleTemplate" maybeString Nothing
|
||||||
|
|> P.optional "searchStatsVisible" Decode.bool False
|
||||||
|
|> P.optional "cardPreviewFullWidth" Decode.bool False
|
||||||
|
|> P.optional "uiTheme" maybeString Nothing
|
||||||
|
|> P.optional "sideMenuVisible" Decode.bool False
|
||||||
|
|> P.optional "powerSearchEnabled" Decode.bool False
|
||||||
|
|> P.optional "uiLang" maybeString Nothing
|
||||||
|
|
||||||
|
|
||||||
|
storedUiSettingsEncode : StoredUiSettings -> Encode.Value
|
||||||
|
storedUiSettingsEncode value =
|
||||||
|
let
|
||||||
|
maybeEnc enca ma =
|
||||||
|
Maybe.map enca ma |> Maybe.withDefault Encode.null
|
||||||
|
in
|
||||||
|
Encode.object
|
||||||
|
[ ( "itemSearchPageSize", maybeEnc Encode.int value.itemSearchPageSize )
|
||||||
|
, ( "tagCategoryColors", Encode.dict identity Encode.string (Dict.fromList value.tagCategoryColors) )
|
||||||
|
, ( "nativePdfPreview", Encode.bool value.nativePdfPreview )
|
||||||
|
, ( "itemSearchNoteLength", maybeEnc Encode.int value.itemSearchNoteLength )
|
||||||
|
, ( "itemDetailNotesPosition", maybeEnc Encode.string value.itemDetailNotesPosition )
|
||||||
|
, ( "searchMenuFolderCount", maybeEnc Encode.int value.searchMenuFolderCount )
|
||||||
|
, ( "searchMenuTagCount", maybeEnc Encode.int value.searchMenuTagCount )
|
||||||
|
, ( "searchMenuTagCatCount", maybeEnc Encode.int value.searchMenuTagCatCount )
|
||||||
|
, ( "formFields", maybeEnc (Encode.list Encode.string) value.formFields )
|
||||||
|
, ( "itemDetailShortcuts", Encode.bool value.itemDetailShortcuts )
|
||||||
|
, ( "searchMenuVisible", Encode.bool value.searchMenuVisible )
|
||||||
|
, ( "editMenuVisible", Encode.bool value.editMenuVisible )
|
||||||
|
, ( "cardPreviewSize", maybeEnc Encode.string value.cardPreviewSize )
|
||||||
|
, ( "cardTitleTemplate", maybeEnc Encode.string value.cardTitleTemplate )
|
||||||
|
, ( "cardSubtitleTemplate", maybeEnc Encode.string value.cardSubtitleTemplate )
|
||||||
|
, ( "searchStatsVisible", Encode.bool value.searchStatsVisible )
|
||||||
|
, ( "cardPreviewFullWidth", Encode.bool value.cardPreviewFullWidth )
|
||||||
|
, ( "uiTheme", maybeEnc Encode.string value.uiTheme )
|
||||||
|
, ( "sideMenuVisible", Encode.bool value.sideMenuVisible )
|
||||||
|
, ( "powerSearchEnabled", Encode.bool value.powerSearchEnabled )
|
||||||
|
, ( "uiLang", maybeEnc Encode.string value.uiLang )
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
{-| Settings for the web ui. These fields are all mandatory, since
|
{-| Settings for the web ui. These fields are all mandatory, since
|
||||||
there is always a default value.
|
there is always a default value.
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ init flags url key =
|
|||||||
|
|
||||||
else
|
else
|
||||||
Cmd.none
|
Cmd.none
|
||||||
, Ports.getUiSettings flags
|
, Api.getClientSettings flags GetUiSettings
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -85,5 +85,5 @@ subscriptions : Model -> Sub Msg
|
|||||||
subscriptions model =
|
subscriptions model =
|
||||||
Sub.batch
|
Sub.batch
|
||||||
[ model.subs
|
[ model.subs
|
||||||
, Ports.loadUiSettings GetUiSettings
|
, Ports.receiveUiSettings ReceiveBrowserSettings
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
module Messages.Comp.UiSettingsManage exposing (Texts, gb)
|
module Messages.Comp.UiSettingsManage exposing (Texts, gb)
|
||||||
|
|
||||||
|
import Http
|
||||||
import Messages.Basics
|
import Messages.Basics
|
||||||
|
import Messages.Comp.HttpError
|
||||||
import Messages.Comp.UiSettingsForm
|
import Messages.Comp.UiSettingsForm
|
||||||
|
|
||||||
|
|
||||||
@ -8,6 +10,10 @@ type alias Texts =
|
|||||||
{ basics : Messages.Basics.Texts
|
{ basics : Messages.Basics.Texts
|
||||||
, uiSettingsForm : Messages.Comp.UiSettingsForm.Texts
|
, uiSettingsForm : Messages.Comp.UiSettingsForm.Texts
|
||||||
, saveSettings : String
|
, saveSettings : String
|
||||||
|
, settingsUnchanged : String
|
||||||
|
, settingsSaved : String
|
||||||
|
, unknownSaveError : String
|
||||||
|
, httpError : Http.Error -> String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -16,4 +22,8 @@ gb =
|
|||||||
{ basics = Messages.Basics.gb
|
{ basics = Messages.Basics.gb
|
||||||
, uiSettingsForm = Messages.Comp.UiSettingsForm.gb
|
, uiSettingsForm = Messages.Comp.UiSettingsForm.gb
|
||||||
, saveSettings = "Save settings"
|
, saveSettings = "Save settings"
|
||||||
|
, settingsUnchanged = "Settings unchanged or invalid."
|
||||||
|
, settingsSaved = "Settings saved."
|
||||||
|
, unknownSaveError = "Unknown error while trying to save settings."
|
||||||
|
, httpError = Messages.Comp.HttpError.gb
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,7 @@ type Msg
|
|||||||
| KeyUpPowerSearchbarMsg (Maybe KeyCode)
|
| KeyUpPowerSearchbarMsg (Maybe KeyCode)
|
||||||
| RequestReprocessSelected
|
| RequestReprocessSelected
|
||||||
| ReprocessSelectedConfirmed
|
| ReprocessSelectedConfirmed
|
||||||
|
| ClientSettingsSaveResp UiSettings (Result Http.Error BasicResult)
|
||||||
|
|
||||||
|
|
||||||
type SearchType
|
type SearchType
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
module Page.Home.Update exposing (update)
|
module Page.Home.Update exposing
|
||||||
|
( UpdateResult
|
||||||
|
, update
|
||||||
|
)
|
||||||
|
|
||||||
import Api
|
import Api
|
||||||
import Api.Model.ItemLightList exposing (ItemLightList)
|
import Api.Model.ItemLightList exposing (ItemLightList)
|
||||||
@ -16,7 +19,6 @@ import Data.Items
|
|||||||
import Data.UiSettings exposing (UiSettings)
|
import Data.UiSettings exposing (UiSettings)
|
||||||
import Page exposing (Page(..))
|
import Page exposing (Page(..))
|
||||||
import Page.Home.Data exposing (..)
|
import Page.Home.Data exposing (..)
|
||||||
import Ports
|
|
||||||
import Process
|
import Process
|
||||||
import Scroll
|
import Scroll
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
@ -28,7 +30,15 @@ import Util.ItemDragDrop as DD
|
|||||||
import Util.Update
|
import Util.Update
|
||||||
|
|
||||||
|
|
||||||
update : Maybe String -> Nav.Key -> Flags -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
type alias UpdateResult =
|
||||||
|
{ model : Model
|
||||||
|
, cmd : Cmd Msg
|
||||||
|
, sub : Sub Msg
|
||||||
|
, newSettings : Maybe UiSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update : Maybe String -> Nav.Key -> Flags -> UiSettings -> Msg -> Model -> UpdateResult
|
||||||
update mId key flags settings msg model =
|
update mId key flags settings msg model =
|
||||||
case msg of
|
case msg of
|
||||||
Init ->
|
Init ->
|
||||||
@ -41,11 +51,12 @@ update mId key flags settings msg model =
|
|||||||
, scroll = True
|
, scroll = True
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
Util.Update.andThen2
|
makeResult <|
|
||||||
[ update mId key flags settings (SearchMenuMsg Comp.SearchMenu.Init)
|
Util.Update.andThen3
|
||||||
, doSearch searchParam
|
[ update mId key flags settings (SearchMenuMsg Comp.SearchMenu.Init)
|
||||||
]
|
, doSearch searchParam
|
||||||
model
|
]
|
||||||
|
model
|
||||||
|
|
||||||
ResetSearch ->
|
ResetSearch ->
|
||||||
let
|
let
|
||||||
@ -79,21 +90,21 @@ update mId key flags settings msg model =
|
|||||||
BasicSearch
|
BasicSearch
|
||||||
}
|
}
|
||||||
|
|
||||||
( m2, c2, s2 ) =
|
result =
|
||||||
if nextState.stateChange && not model.searchInProgress then
|
if nextState.stateChange && not model.searchInProgress then
|
||||||
doSearch (SearchParam flags BasicSearch settings.itemSearchPageSize 0 False) newModel
|
doSearch (SearchParam flags BasicSearch settings.itemSearchPageSize 0 False) newModel
|
||||||
|
|
||||||
else
|
else
|
||||||
withSub ( newModel, Cmd.none )
|
withSub ( newModel, Cmd.none )
|
||||||
in
|
in
|
||||||
( m2
|
{ result
|
||||||
, Cmd.batch
|
| cmd =
|
||||||
[ c2
|
Cmd.batch
|
||||||
, Cmd.map SearchMenuMsg nextState.cmd
|
[ result.cmd
|
||||||
, dropCmd
|
, Cmd.map SearchMenuMsg nextState.cmd
|
||||||
]
|
, dropCmd
|
||||||
, s2
|
]
|
||||||
)
|
}
|
||||||
|
|
||||||
SetLinkTarget lt ->
|
SetLinkTarget lt ->
|
||||||
case linkTargetMsg lt of
|
case linkTargetMsg lt of
|
||||||
@ -101,7 +112,7 @@ update mId key flags settings msg model =
|
|||||||
update mId key flags settings m model
|
update mId key flags settings m model
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
( model, Cmd.none, Sub.none )
|
makeResult ( model, Cmd.none, Sub.none )
|
||||||
|
|
||||||
ItemCardListMsg m ->
|
ItemCardListMsg m ->
|
||||||
let
|
let
|
||||||
@ -144,15 +155,16 @@ update mId key flags settings msg model =
|
|||||||
, moreAvailable = list.groups /= []
|
, moreAvailable = list.groups /= []
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
Util.Update.andThen2
|
makeResult <|
|
||||||
[ update mId key flags settings (ItemCardListMsg (Comp.ItemCardList.SetResults list))
|
Util.Update.andThen3
|
||||||
, if scroll then
|
[ update mId key flags settings (ItemCardListMsg (Comp.ItemCardList.SetResults list))
|
||||||
scrollToCard mId
|
, if scroll then
|
||||||
|
scrollToCard mId
|
||||||
|
|
||||||
else
|
else
|
||||||
\next -> ( next, Cmd.none, Sub.none )
|
\next -> makeResult ( next, Cmd.none, Sub.none )
|
||||||
]
|
]
|
||||||
m
|
m
|
||||||
|
|
||||||
ItemSearchAddResp (Ok list) ->
|
ItemSearchAddResp (Ok list) ->
|
||||||
let
|
let
|
||||||
@ -167,10 +179,7 @@ update mId key flags settings msg model =
|
|||||||
, moreAvailable = list.groups /= []
|
, moreAvailable = list.groups /= []
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
Util.Update.andThen2
|
update mId key flags settings (ItemCardListMsg (Comp.ItemCardList.AddResults list)) m
|
||||||
[ update mId key flags settings (ItemCardListMsg (Comp.ItemCardList.AddResults list))
|
|
||||||
]
|
|
||||||
m
|
|
||||||
|
|
||||||
ItemSearchAddResp (Err _) ->
|
ItemSearchAddResp (Err _) ->
|
||||||
withSub
|
withSub
|
||||||
@ -514,10 +523,11 @@ update mId key flags settings msg model =
|
|||||||
res.change
|
res.change
|
||||||
(MultiUpdateResp res.change)
|
(MultiUpdateResp res.change)
|
||||||
in
|
in
|
||||||
( { model | viewMode = SelectView svm_ }
|
makeResult
|
||||||
, Cmd.batch [ cmd_, upCmd ]
|
( { model | viewMode = SelectView svm_ }
|
||||||
, sub_
|
, Cmd.batch [ cmd_, upCmd ]
|
||||||
)
|
, sub_
|
||||||
|
)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
noSub ( model, Cmd.none )
|
noSub ( model, Cmd.none )
|
||||||
@ -540,10 +550,11 @@ update mId key flags settings msg model =
|
|||||||
noSub ( nm, Cmd.none )
|
noSub ( nm, Cmd.none )
|
||||||
|
|
||||||
MultiUpdateResp change (Err _) ->
|
MultiUpdateResp change (Err _) ->
|
||||||
( updateSelectViewNameState False model change
|
makeResult
|
||||||
, Cmd.none
|
( updateSelectViewNameState False model change
|
||||||
, Sub.none
|
, Cmd.none
|
||||||
)
|
, Sub.none
|
||||||
|
)
|
||||||
|
|
||||||
ReplaceChangedItemsResp (Ok items) ->
|
ReplaceChangedItemsResp (Ok items) ->
|
||||||
noSub ( replaceItems model items, Cmd.none )
|
noSub ( replaceItems model items, Cmd.none )
|
||||||
@ -592,10 +603,24 @@ update mId key flags settings msg model =
|
|||||||
{ settings | cardPreviewFullWidth = not settings.cardPreviewFullWidth }
|
{ settings | cardPreviewFullWidth = not settings.cardPreviewFullWidth }
|
||||||
|
|
||||||
cmd =
|
cmd =
|
||||||
Ports.storeUiSettings flags newSettings
|
Api.saveClientSettings flags newSettings (ClientSettingsSaveResp newSettings)
|
||||||
in
|
in
|
||||||
noSub ( model, cmd )
|
noSub ( model, cmd )
|
||||||
|
|
||||||
|
ClientSettingsSaveResp newSettings (Ok res) ->
|
||||||
|
if res.success then
|
||||||
|
{ model = model
|
||||||
|
, cmd = Cmd.none
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Just newSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
noSub ( model, Cmd.none )
|
||||||
|
|
||||||
|
ClientSettingsSaveResp _ (Err _) ->
|
||||||
|
noSub ( model, Cmd.none )
|
||||||
|
|
||||||
PowerSearchMsg lm ->
|
PowerSearchMsg lm ->
|
||||||
let
|
let
|
||||||
result =
|
result =
|
||||||
@ -609,7 +634,7 @@ update mId key flags settings msg model =
|
|||||||
in
|
in
|
||||||
case result.action of
|
case result.action of
|
||||||
Comp.PowerSearchInput.NoAction ->
|
Comp.PowerSearchInput.NoAction ->
|
||||||
( model_, cmd_, Sub.map PowerSearchMsg result.subs )
|
makeResult ( model_, cmd_, Sub.map PowerSearchMsg result.subs )
|
||||||
|
|
||||||
Comp.PowerSearchInput.SubmitSearch ->
|
Comp.PowerSearchInput.SubmitSearch ->
|
||||||
update mId key flags settings (DoSearch model_.searchTypeDropdownValue) model_
|
update mId key flags settings (DoSearch model_.searchTypeDropdownValue) model_
|
||||||
@ -703,21 +728,22 @@ loadChangedItems flags ids =
|
|||||||
Api.itemSearch flags search ReplaceChangedItemsResp
|
Api.itemSearch flags search ReplaceChangedItemsResp
|
||||||
|
|
||||||
|
|
||||||
scrollToCard : Maybe String -> Model -> ( Model, Cmd Msg, Sub Msg )
|
scrollToCard : Maybe String -> Model -> UpdateResult
|
||||||
scrollToCard mId model =
|
scrollToCard mId model =
|
||||||
let
|
let
|
||||||
scroll id =
|
scroll id =
|
||||||
Scroll.scrollElementY "item-card-list" id 0.5 0.5
|
Scroll.scrollElementY "item-card-list" id 0.5 0.5
|
||||||
in
|
in
|
||||||
case mId of
|
makeResult <|
|
||||||
Just id ->
|
case mId of
|
||||||
( { model | scrollToCard = mId }
|
Just id ->
|
||||||
, Task.attempt ScrollResult (scroll id)
|
( { model | scrollToCard = mId }
|
||||||
, Sub.none
|
, Task.attempt ScrollResult (scroll id)
|
||||||
)
|
, Sub.none
|
||||||
|
)
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
( model, Cmd.none, Sub.none )
|
( model, Cmd.none, Sub.none )
|
||||||
|
|
||||||
|
|
||||||
loadEditModel : Flags -> Cmd Msg
|
loadEditModel : Flags -> Cmd Msg
|
||||||
@ -725,7 +751,7 @@ loadEditModel flags =
|
|||||||
Cmd.map EditMenuMsg (Comp.ItemDetail.MultiEditMenu.loadModel flags)
|
Cmd.map EditMenuMsg (Comp.ItemDetail.MultiEditMenu.loadModel flags)
|
||||||
|
|
||||||
|
|
||||||
doSearch : SearchParam -> Model -> ( Model, Cmd Msg, Sub Msg )
|
doSearch : SearchParam -> Model -> UpdateResult
|
||||||
doSearch param model =
|
doSearch param model =
|
||||||
let
|
let
|
||||||
param_ =
|
param_ =
|
||||||
@ -798,16 +824,26 @@ doSearchMore flags settings model =
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
withSub : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, Sub Msg )
|
withSub : ( Model, Cmd Msg ) -> UpdateResult
|
||||||
withSub ( m, c ) =
|
withSub ( m, c ) =
|
||||||
( m
|
makeResult
|
||||||
, c
|
( m
|
||||||
, Throttle.ifNeeded
|
, c
|
||||||
(Time.every 500 (\_ -> UpdateThrottle))
|
, Throttle.ifNeeded
|
||||||
m.throttle
|
(Time.every 500 (\_ -> UpdateThrottle))
|
||||||
)
|
m.throttle
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
noSub : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, Sub Msg )
|
noSub : ( Model, Cmd Msg ) -> UpdateResult
|
||||||
noSub ( m, c ) =
|
noSub ( m, c ) =
|
||||||
( m, c, Sub.none )
|
makeResult ( m, c, Sub.none )
|
||||||
|
|
||||||
|
|
||||||
|
makeResult : ( Model, Cmd Msg, Sub Msg ) -> UpdateResult
|
||||||
|
makeResult ( m, c, s ) =
|
||||||
|
{ model = m
|
||||||
|
, cmd = c
|
||||||
|
, sub = s
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
@ -12,7 +12,7 @@ import Comp.NotificationManage
|
|||||||
import Comp.ScanMailboxManage
|
import Comp.ScanMailboxManage
|
||||||
import Comp.UiSettingsManage
|
import Comp.UiSettingsManage
|
||||||
import Data.Flags exposing (Flags)
|
import Data.Flags exposing (Flags)
|
||||||
import Data.UiSettings exposing (UiSettings)
|
import Data.UiSettings exposing (StoredUiSettings, UiSettings)
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
@ -62,3 +62,4 @@ type Msg
|
|||||||
| ScanMailboxMsg Comp.ScanMailboxManage.Msg
|
| ScanMailboxMsg Comp.ScanMailboxManage.Msg
|
||||||
| UiSettingsMsg Comp.UiSettingsManage.Msg
|
| UiSettingsMsg Comp.UiSettingsManage.Msg
|
||||||
| UpdateSettings
|
| UpdateSettings
|
||||||
|
| ReceiveBrowserSettings StoredUiSettings
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
module Page.UserSettings.Update exposing (update)
|
module Page.UserSettings.Update exposing (UpdateResult, update)
|
||||||
|
|
||||||
import Comp.ChangePasswordForm
|
import Comp.ChangePasswordForm
|
||||||
import Comp.EmailSettingsManage
|
import Comp.EmailSettingsManage
|
||||||
@ -11,7 +11,15 @@ import Data.UiSettings exposing (UiSettings)
|
|||||||
import Page.UserSettings.Data exposing (..)
|
import Page.UserSettings.Data exposing (..)
|
||||||
|
|
||||||
|
|
||||||
update : Flags -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
type alias UpdateResult =
|
||||||
|
{ model : Model
|
||||||
|
, cmd : Cmd Msg
|
||||||
|
, sub : Sub Msg
|
||||||
|
, newSettings : Maybe UiSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update : Flags -> UiSettings -> Msg -> Model -> UpdateResult
|
||||||
update flags settings msg model =
|
update flags settings msg model =
|
||||||
case msg of
|
case msg of
|
||||||
SetTab t ->
|
SetTab t ->
|
||||||
@ -25,17 +33,25 @@ update flags settings msg model =
|
|||||||
( em, c ) =
|
( em, c ) =
|
||||||
Comp.EmailSettingsManage.init flags
|
Comp.EmailSettingsManage.init flags
|
||||||
in
|
in
|
||||||
( { m | emailSettingsModel = em }, Cmd.map EmailSettingsMsg c, Sub.none )
|
{ model = { m | emailSettingsModel = em }
|
||||||
|
, cmd = Cmd.map EmailSettingsMsg c
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
ImapSettingsTab ->
|
ImapSettingsTab ->
|
||||||
let
|
let
|
||||||
( em, c ) =
|
( em, c ) =
|
||||||
Comp.ImapSettingsManage.init flags
|
Comp.ImapSettingsManage.init flags
|
||||||
in
|
in
|
||||||
( { m | imapSettingsModel = em }, Cmd.map ImapSettingsMsg c, Sub.none )
|
{ model = { m | imapSettingsModel = em }
|
||||||
|
, cmd = Cmd.map ImapSettingsMsg c
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
ChangePassTab ->
|
ChangePassTab ->
|
||||||
( m, Cmd.none, Sub.none )
|
UpdateResult m Cmd.none Sub.none Nothing
|
||||||
|
|
||||||
NotificationTab ->
|
NotificationTab ->
|
||||||
let
|
let
|
||||||
@ -43,7 +59,7 @@ update flags settings msg model =
|
|||||||
Cmd.map NotificationMsg
|
Cmd.map NotificationMsg
|
||||||
(Tuple.second (Comp.NotificationManage.init flags))
|
(Tuple.second (Comp.NotificationManage.init flags))
|
||||||
in
|
in
|
||||||
( m, initCmd, Sub.none )
|
UpdateResult m initCmd Sub.none Nothing
|
||||||
|
|
||||||
ScanMailboxTab ->
|
ScanMailboxTab ->
|
||||||
let
|
let
|
||||||
@ -51,64 +67,86 @@ update flags settings msg model =
|
|||||||
Cmd.map ScanMailboxMsg
|
Cmd.map ScanMailboxMsg
|
||||||
(Tuple.second (Comp.ScanMailboxManage.init flags))
|
(Tuple.second (Comp.ScanMailboxManage.init flags))
|
||||||
in
|
in
|
||||||
( m, initCmd, Sub.none )
|
UpdateResult m initCmd Sub.none Nothing
|
||||||
|
|
||||||
UiSettingsTab ->
|
UiSettingsTab ->
|
||||||
( m, Cmd.none, Sub.none )
|
UpdateResult m Cmd.none Sub.none Nothing
|
||||||
|
|
||||||
ChangePassMsg m ->
|
ChangePassMsg m ->
|
||||||
let
|
let
|
||||||
( m2, c2 ) =
|
( m2, c2 ) =
|
||||||
Comp.ChangePasswordForm.update flags m model.changePassModel
|
Comp.ChangePasswordForm.update flags m model.changePassModel
|
||||||
in
|
in
|
||||||
( { model | changePassModel = m2 }, Cmd.map ChangePassMsg c2, Sub.none )
|
{ model = { model | changePassModel = m2 }
|
||||||
|
, cmd = Cmd.map ChangePassMsg c2
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
EmailSettingsMsg m ->
|
EmailSettingsMsg m ->
|
||||||
let
|
let
|
||||||
( m2, c2 ) =
|
( m2, c2 ) =
|
||||||
Comp.EmailSettingsManage.update flags m model.emailSettingsModel
|
Comp.EmailSettingsManage.update flags m model.emailSettingsModel
|
||||||
in
|
in
|
||||||
( { model | emailSettingsModel = m2 }, Cmd.map EmailSettingsMsg c2, Sub.none )
|
{ model = { model | emailSettingsModel = m2 }
|
||||||
|
, cmd = Cmd.map EmailSettingsMsg c2
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
ImapSettingsMsg m ->
|
ImapSettingsMsg m ->
|
||||||
let
|
let
|
||||||
( m2, c2 ) =
|
( m2, c2 ) =
|
||||||
Comp.ImapSettingsManage.update flags m model.imapSettingsModel
|
Comp.ImapSettingsManage.update flags m model.imapSettingsModel
|
||||||
in
|
in
|
||||||
( { model | imapSettingsModel = m2 }, Cmd.map ImapSettingsMsg c2, Sub.none )
|
{ model = { model | imapSettingsModel = m2 }
|
||||||
|
, cmd = Cmd.map ImapSettingsMsg c2
|
||||||
|
, sub = Sub.none
|
||||||
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
NotificationMsg lm ->
|
NotificationMsg lm ->
|
||||||
let
|
let
|
||||||
( m2, c2 ) =
|
( m2, c2 ) =
|
||||||
Comp.NotificationManage.update flags lm model.notificationModel
|
Comp.NotificationManage.update flags lm model.notificationModel
|
||||||
in
|
in
|
||||||
( { model | notificationModel = m2 }
|
{ model = { model | notificationModel = m2 }
|
||||||
, Cmd.map NotificationMsg c2
|
, cmd = Cmd.map NotificationMsg c2
|
||||||
, Sub.none
|
, sub = Sub.none
|
||||||
)
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
ScanMailboxMsg lm ->
|
ScanMailboxMsg lm ->
|
||||||
let
|
let
|
||||||
( m2, c2 ) =
|
( m2, c2 ) =
|
||||||
Comp.ScanMailboxManage.update flags lm model.scanMailboxModel
|
Comp.ScanMailboxManage.update flags lm model.scanMailboxModel
|
||||||
in
|
in
|
||||||
( { model | scanMailboxModel = m2 }
|
{ model = { model | scanMailboxModel = m2 }
|
||||||
, Cmd.map ScanMailboxMsg c2
|
, cmd = Cmd.map ScanMailboxMsg c2
|
||||||
, Sub.none
|
, sub = Sub.none
|
||||||
)
|
, newSettings = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
UiSettingsMsg lm ->
|
UiSettingsMsg lm ->
|
||||||
let
|
let
|
||||||
( m2, c2, s2 ) =
|
res =
|
||||||
Comp.UiSettingsManage.update flags settings lm model.uiSettingsModel
|
Comp.UiSettingsManage.update flags settings lm model.uiSettingsModel
|
||||||
in
|
in
|
||||||
( { model | uiSettingsModel = m2 }
|
{ model = { model | uiSettingsModel = res.model }
|
||||||
, Cmd.map UiSettingsMsg c2
|
, cmd = Cmd.map UiSettingsMsg res.cmd
|
||||||
, Sub.map UiSettingsMsg s2
|
, sub = Sub.map UiSettingsMsg res.sub
|
||||||
)
|
, newSettings = res.newSettings
|
||||||
|
}
|
||||||
|
|
||||||
UpdateSettings ->
|
UpdateSettings ->
|
||||||
update flags
|
update flags
|
||||||
settings
|
settings
|
||||||
(UiSettingsMsg Comp.UiSettingsManage.UpdateSettings)
|
(UiSettingsMsg Comp.UiSettingsManage.UpdateSettings)
|
||||||
model
|
model
|
||||||
|
|
||||||
|
ReceiveBrowserSettings sett ->
|
||||||
|
let
|
||||||
|
lm =
|
||||||
|
Comp.UiSettingsManage.ReceiveBrowserSettings sett
|
||||||
|
in
|
||||||
|
update flags settings (UiSettingsMsg lm) model
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
port module Ports exposing
|
port module Ports exposing
|
||||||
( checkSearchQueryString
|
( checkSearchQueryString
|
||||||
, getUiSettings
|
|
||||||
, initClipboard
|
, initClipboard
|
||||||
, loadUiSettings
|
|
||||||
, onUiSettingsSaved
|
|
||||||
, receiveCheckQueryResult
|
, receiveCheckQueryResult
|
||||||
|
, receiveUiSettings
|
||||||
, removeAccount
|
, removeAccount
|
||||||
|
, requestUiSettings
|
||||||
, setAccount
|
, setAccount
|
||||||
, setUiTheme
|
, setUiTheme
|
||||||
, storeUiSettings
|
|
||||||
)
|
)
|
||||||
|
|
||||||
import Api.Model.AuthResult exposing (AuthResult)
|
import Api.Model.AuthResult exposing (AuthResult)
|
||||||
import Api.Model.BasicResult exposing (BasicResult)
|
|
||||||
import Data.Flags exposing (Flags)
|
|
||||||
import Data.QueryParseResult exposing (QueryParseResult)
|
import Data.QueryParseResult exposing (QueryParseResult)
|
||||||
import Data.UiSettings exposing (StoredUiSettings, UiSettings)
|
import Data.UiSettings exposing (StoredUiSettings)
|
||||||
import Data.UiTheme exposing (UiTheme)
|
import Data.UiTheme exposing (UiTheme)
|
||||||
|
|
||||||
|
|
||||||
@ -27,18 +23,6 @@ port setAccount : AuthResult -> Cmd msg
|
|||||||
port removeAccount : () -> Cmd msg
|
port removeAccount : () -> Cmd msg
|
||||||
|
|
||||||
|
|
||||||
port saveUiSettings : ( AuthResult, StoredUiSettings ) -> Cmd msg
|
|
||||||
|
|
||||||
|
|
||||||
port receiveUiSettings : (StoredUiSettings -> msg) -> Sub msg
|
|
||||||
|
|
||||||
|
|
||||||
port requestUiSettings : ( AuthResult, StoredUiSettings ) -> Cmd msg
|
|
||||||
|
|
||||||
|
|
||||||
port uiSettingsSaved : (() -> msg) -> Sub msg
|
|
||||||
|
|
||||||
|
|
||||||
port internalSetUiTheme : String -> Cmd msg
|
port internalSetUiTheme : String -> Cmd msg
|
||||||
|
|
||||||
|
|
||||||
@ -48,45 +32,15 @@ port checkSearchQueryString : String -> Cmd msg
|
|||||||
port receiveCheckQueryResult : (QueryParseResult -> msg) -> Sub msg
|
port receiveCheckQueryResult : (QueryParseResult -> msg) -> Sub msg
|
||||||
|
|
||||||
|
|
||||||
|
port initClipboard : ( String, String ) -> Cmd msg
|
||||||
|
|
||||||
|
|
||||||
|
port receiveUiSettings : (StoredUiSettings -> msg) -> Sub msg
|
||||||
|
|
||||||
|
|
||||||
|
port requestUiSettings : AuthResult -> Cmd msg
|
||||||
|
|
||||||
|
|
||||||
setUiTheme : UiTheme -> Cmd msg
|
setUiTheme : UiTheme -> Cmd msg
|
||||||
setUiTheme theme =
|
setUiTheme theme =
|
||||||
internalSetUiTheme (Data.UiTheme.toString theme)
|
internalSetUiTheme (Data.UiTheme.toString theme)
|
||||||
|
|
||||||
|
|
||||||
onUiSettingsSaved : msg -> Sub msg
|
|
||||||
onUiSettingsSaved m =
|
|
||||||
uiSettingsSaved (\_ -> m)
|
|
||||||
|
|
||||||
|
|
||||||
storeUiSettings : Flags -> UiSettings -> Cmd msg
|
|
||||||
storeUiSettings flags settings =
|
|
||||||
case flags.account of
|
|
||||||
Just ar ->
|
|
||||||
saveUiSettings
|
|
||||||
( ar
|
|
||||||
, Data.UiSettings.toStoredUiSettings settings
|
|
||||||
)
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
Cmd.none
|
|
||||||
|
|
||||||
|
|
||||||
loadUiSettings : (UiSettings -> msg) -> Sub msg
|
|
||||||
loadUiSettings tagger =
|
|
||||||
receiveUiSettings (Data.UiSettings.mergeDefaults >> tagger)
|
|
||||||
|
|
||||||
|
|
||||||
getUiSettings : Flags -> Cmd msg
|
|
||||||
getUiSettings flags =
|
|
||||||
case flags.account of
|
|
||||||
Just ar ->
|
|
||||||
requestUiSettings
|
|
||||||
( ar
|
|
||||||
, Data.UiSettings.toStoredUiSettings Data.UiSettings.defaults
|
|
||||||
)
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
Cmd.none
|
|
||||||
|
|
||||||
|
|
||||||
port initClipboard : ( String, String ) -> Cmd msg
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
module Util.Update exposing
|
module Util.Update exposing
|
||||||
( andThen1
|
( andThen1
|
||||||
, andThen2
|
, andThen2
|
||||||
|
, andThen3
|
||||||
, cmdUnit
|
, cmdUnit
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,6 +45,21 @@ andThen2 fs m =
|
|||||||
|> combine
|
|> combine
|
||||||
|
|
||||||
|
|
||||||
|
andThen3 :
|
||||||
|
List (model -> { x | model : model, cmd : Cmd msg, sub : Sub msg })
|
||||||
|
-> model
|
||||||
|
-> ( model, Cmd msg, Sub msg )
|
||||||
|
andThen3 list m =
|
||||||
|
let
|
||||||
|
mkTuple r =
|
||||||
|
( r.model, r.cmd, r.sub )
|
||||||
|
|
||||||
|
list2 =
|
||||||
|
List.map (\e -> e >> mkTuple) list
|
||||||
|
in
|
||||||
|
andThen2 list2 m
|
||||||
|
|
||||||
|
|
||||||
cmdUnit : a -> Cmd a
|
cmdUnit : a -> Cmd a
|
||||||
cmdUnit a =
|
cmdUnit a =
|
||||||
Task.perform (\_ -> a) (Task.succeed ())
|
Task.perform (\_ -> a) (Task.succeed ())
|
||||||
|
@ -50,40 +50,22 @@ elmApp.ports.removeAccount.subscribe(function() {
|
|||||||
localStorage.removeItem("account");
|
localStorage.removeItem("account");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
elmApp.ports.saveUiSettings.subscribe(function(args) {
|
|
||||||
if (Array.isArray(args) && args.length == 2) {
|
|
||||||
var authResult = args[0];
|
|
||||||
var settings = args[1];
|
|
||||||
if (authResult && settings) {
|
|
||||||
var key = authResult.collective + "/" + authResult.user + "/uiSettings";
|
|
||||||
console.log("Save ui settings to local storage");
|
|
||||||
localStorage.setItem(key, JSON.stringify(settings));
|
|
||||||
elmApp.ports.receiveUiSettings.send(settings);
|
|
||||||
elmApp.ports.uiSettingsSaved.send(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
elmApp.ports.requestUiSettings.subscribe(function(args) {
|
elmApp.ports.requestUiSettings.subscribe(function(args) {
|
||||||
console.log("Requesting ui settings");
|
console.log("Requesting ui settings");
|
||||||
if (Array.isArray(args) && args.length == 2) {
|
var account = args;
|
||||||
var account = args[0];
|
var collective = account ? account.collective : null;
|
||||||
var defaults = args[1];
|
var user = account ? account.user : null;
|
||||||
var collective = account ? account.collective : null;
|
if (collective && user) {
|
||||||
var user = account ? account.user : null;
|
var key = collective + "/" + user + "/uiSettings";
|
||||||
if (collective && user) {
|
var settings = localStorage.getItem(key);
|
||||||
var key = collective + "/" + user + "/uiSettings";
|
try {
|
||||||
var settings = localStorage.getItem(key);
|
|
||||||
var data = settings ? JSON.parse(settings) : null;
|
var data = settings ? JSON.parse(settings) : null;
|
||||||
if (data && defaults) {
|
if (data) {
|
||||||
var defaults = extend(defaults, data);
|
console.log("Sending browser ui settings");
|
||||||
elmApp.ports.receiveUiSettings.send(defaults);
|
elmApp.ports.receiveUiSettings.send(data);
|
||||||
} else if (defaults) {
|
|
||||||
elmApp.ports.receiveUiSettings.send(defaults);
|
|
||||||
}
|
}
|
||||||
} else if (defaults) {
|
} catch (error) {
|
||||||
elmApp.ports.receiveUiSettings.send(defaults);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user