From a8ea391715770ce7115619d18fbfcc630b953de0 Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Thu, 6 Aug 2020 23:38:55 +0200 Subject: [PATCH 1/4] Render edit-modals above the menu and not the whole page --- .../webapp/src/main/elm/Comp/ContactField.elm | 32 ++++++++++++++++--- .../webapp/src/main/elm/Comp/DetailEdit.elm | 15 ++++++--- .../src/main/elm/Comp/ItemDetail/View.elm | 6 ++-- modules/webapp/src/main/elm/Comp/OrgForm.elm | 8 ++++- .../webapp/src/main/elm/Comp/PersonForm.elm | 8 ++++- modules/webapp/src/main/webjar/docspell.css | 8 +++++ 6 files changed, 62 insertions(+), 15 deletions(-) diff --git a/modules/webapp/src/main/elm/Comp/ContactField.elm b/modules/webapp/src/main/elm/Comp/ContactField.elm index c349009a..f93c34ac 100644 --- a/modules/webapp/src/main/elm/Comp/ContactField.elm +++ b/modules/webapp/src/main/elm/Comp/ContactField.elm @@ -5,6 +5,7 @@ module Comp.ContactField exposing , getContacts , update , view + , view1 ) import Api.Model.Contact exposing (Contact) @@ -81,9 +82,15 @@ update msg model = Comp.Dropdown.getSelected model.kind |> List.head |> Maybe.map Data.ContactType.toString - |> Maybe.withDefault "" in - ( { model | items = Contact "" model.value kind :: model.items, value = "" }, Cmd.none ) + case kind of + Just k -> + ( { model | items = Contact "" model.value k :: model.items, value = "" } + , Cmd.none + ) + + Nothing -> + ( model, Cmd.none ) Select contact -> let @@ -100,12 +107,27 @@ update msg model = view : UiSettings -> Model -> Html Msg view settings model = + view1 settings False model + + +view1 : UiSettings -> Bool -> Model -> Html Msg +view1 settings compact model = div [] - [ div [ class "fields" ] - [ div [ class "four wide field" ] + [ div [ classList [ ( "fields", not compact ) ] ] + [ div + [ classList + [ ( "field", True ) + , ( "four wide", not compact ) + ] + ] [ Html.map TypeMsg (Comp.Dropdown.view settings model.kind) ] - , div [ class "twelve wide field" ] + , div + [ classList + [ ( "twelve wide", not compact ) + , ( "field", True ) + ] + ] [ div [ class "ui action input" ] [ input [ type_ "text" diff --git a/modules/webapp/src/main/elm/Comp/DetailEdit.elm b/modules/webapp/src/main/elm/Comp/DetailEdit.elm index 2e4f9f44..2b7e79b9 100644 --- a/modules/webapp/src/main/elm/Comp/DetailEdit.elm +++ b/modules/webapp/src/main/elm/Comp/DetailEdit.elm @@ -416,13 +416,13 @@ viewIntern settings withButtons model = Html.map TagMsg (Comp.TagForm.view tm) PMR pm -> - Html.map PersonMsg (Comp.PersonForm.view settings pm) + Html.map PersonMsg (Comp.PersonForm.view1 settings True pm) PMC pm -> - Html.map PersonMsg (Comp.PersonForm.view settings pm) + Html.map PersonMsg (Comp.PersonForm.view1 settings True pm) OM om -> - Html.map OrgMsg (Comp.OrgForm.view settings om) + Html.map OrgMsg (Comp.OrgForm.view1 settings True om) EM em -> Html.map EquipMsg (Comp.EquipmentForm.view em) @@ -461,13 +461,18 @@ viewModal settings mm = in div [ classList - [ ( "ui inverted modals page dimmer", True ) + [ ( "ui inverted dimmer", True ) , ( "invisibe hidden", hidden ) , ( "active", not hidden ) ] , style "display" "flex !important" ] - [ div [ class "ui modal active" ] + [ div + [ classList + [ ( "ui modal keep-small", True ) + , ( "active", not hidden ) + ] + ] [ div [ class "header" ] [ Maybe.map .form mm |> Maybe.map headIcon diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm index c089c552..fcc7c921 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm @@ -37,8 +37,7 @@ import Util.Time view : { prev : Maybe String, next : Maybe String } -> UiSettings -> Model -> Html Msg view inav settings model = div [] - [ Html.map ModalEditMsg (Comp.DetailEdit.viewModal settings model.modalEdit) - , renderItemInfo settings model + [ renderItemInfo settings model , renderDetailMenu inav model , renderMailForm settings model , renderAddFilesForm model @@ -684,7 +683,8 @@ renderTags settings model = renderEditMenu : UiSettings -> Model -> List (Html Msg) renderEditMenu settings model = - [ div [ class "ui segments" ] + [ Html.map ModalEditMsg (Comp.DetailEdit.viewModal settings model.modalEdit) + , div [ class "ui segments" ] [ renderEditButtons model , renderEditForm settings model ] diff --git a/modules/webapp/src/main/elm/Comp/OrgForm.elm b/modules/webapp/src/main/elm/Comp/OrgForm.elm index 0ea6ed0c..6645d90d 100644 --- a/modules/webapp/src/main/elm/Comp/OrgForm.elm +++ b/modules/webapp/src/main/elm/Comp/OrgForm.elm @@ -6,6 +6,7 @@ module Comp.OrgForm exposing , isValid , update , view + , view1 ) import Api.Model.Organization exposing (Organization) @@ -109,6 +110,11 @@ update flags msg model = view : UiSettings -> Model -> Html Msg view settings model = + view1 settings False model + + +view1 : UiSettings -> Bool -> Model -> Html Msg +view1 settings compact model = div [ class "ui form" ] [ div [ classList @@ -132,7 +138,7 @@ view settings model = , h3 [ class "ui dividing header" ] [ text "Contacts" ] - , Html.map ContactMsg (Comp.ContactField.view settings model.contactModel) + , Html.map ContactMsg (Comp.ContactField.view1 settings compact model.contactModel) , h3 [ class "ui dividing header" ] [ text "Notes" ] diff --git a/modules/webapp/src/main/elm/Comp/PersonForm.elm b/modules/webapp/src/main/elm/Comp/PersonForm.elm index 35cc529b..2fba1b03 100644 --- a/modules/webapp/src/main/elm/Comp/PersonForm.elm +++ b/modules/webapp/src/main/elm/Comp/PersonForm.elm @@ -6,6 +6,7 @@ module Comp.PersonForm exposing , isValid , update , view + , view1 ) import Api.Model.Person exposing (Person) @@ -123,6 +124,11 @@ update flags msg model = view : UiSettings -> Model -> Html Msg view settings model = + view1 settings False model + + +view1 : UiSettings -> Bool -> Model -> Html Msg +view1 settings compact model = div [ class "ui form" ] [ div [ classList @@ -157,7 +163,7 @@ view settings model = , h3 [ class "ui dividing header" ] [ text "Contacts" ] - , Html.map ContactMsg (Comp.ContactField.view settings model.contactModel) + , Html.map ContactMsg (Comp.ContactField.view1 settings compact model.contactModel) , h3 [ class "ui dividing header" ] [ text "Notes" ] diff --git a/modules/webapp/src/main/webjar/docspell.css b/modules/webapp/src/main/webjar/docspell.css index cb32ed8f..72c026b2 100644 --- a/modules/webapp/src/main/webjar/docspell.css +++ b/modules/webapp/src/main/webjar/docspell.css @@ -170,6 +170,14 @@ textarea.markdown-editor { background: rgba(0,0,0,0.2); } +@media only screen and (min-width: 992px) { + .ui.modal.keep-small { + width: inherit; + margin: 0 0 0 1rem; + } +} + + label span.muted { font-size: smaller; color: rgba(0,0,0,0.6); From 639ab7440e2d23676cf57a447b2bd4b6218c7488 Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Thu, 6 Aug 2020 23:49:54 +0200 Subject: [PATCH 2/4] Fix edit menu layout --- modules/webapp/src/main/elm/Comp/ItemDetail/View.elm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm index fcc7c921..9d281923 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm @@ -6,7 +6,7 @@ import Comp.DatePicker import Comp.DetailEdit import Comp.Dropdown import Comp.Dropzone -import Comp.ItemDetail.Model exposing (Model, NotesField(..), isEditNotes) +import Comp.ItemDetail.Model exposing (Model, NotesField(..)) import Comp.ItemDetail.Update exposing (Msg(..)) import Comp.ItemMail import Comp.MarkdownInput @@ -684,7 +684,7 @@ renderTags settings model = renderEditMenu : UiSettings -> Model -> List (Html Msg) renderEditMenu settings model = [ Html.map ModalEditMsg (Comp.DetailEdit.viewModal settings model.modalEdit) - , div [ class "ui segments" ] + , div [] [ renderEditButtons model , renderEditForm settings model ] @@ -742,7 +742,7 @@ renderEditForm settings model = [ i [ class "grey plus link icon" ] [] ] in - div [ class "ui segment" ] + div [ class "ui attached segment" ] [ div [ class "ui form warning" ] [ div [ class "field" ] [ label [] From f3ba2241242f3f80c7b88aefda1e29579b8ee74c Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Fri, 7 Aug 2020 01:20:26 +0200 Subject: [PATCH 3/4] Add missing organization/person/equipment routes --- .../docspell/backend/ops/OEquipment.scala | 5 ++ .../docspell/backend/ops/OOrganization.scala | 13 +++++ .../src/main/resources/docspell-openapi.yml | 17 ++++++ .../restserver/routes/EquipmentRoutes.scala | 7 +++ .../routes/OrganizationRoutes.scala | 7 +++ .../restserver/routes/PersonRoutes.scala | 7 +++ .../store/queries/QOrganization.scala | 56 +++++++++++++++++++ .../docspell/store/records/TagItemName.scala | 4 +- 8 files changed, 115 insertions(+), 1 deletion(-) diff --git a/modules/backend/src/main/scala/docspell/backend/ops/OEquipment.scala b/modules/backend/src/main/scala/docspell/backend/ops/OEquipment.scala index bfb8537d..9457e6a6 100644 --- a/modules/backend/src/main/scala/docspell/backend/ops/OEquipment.scala +++ b/modules/backend/src/main/scala/docspell/backend/ops/OEquipment.scala @@ -11,6 +11,8 @@ trait OEquipment[F[_]] { def findAll(account: AccountId, nameQuery: Option[String]): F[Vector[REquipment]] + def find(account: AccountId, id: Ident): F[Option[REquipment]] + def add(s: REquipment): F[AddResult] def update(s: REquipment): F[AddResult] @@ -25,6 +27,9 @@ object OEquipment { def findAll(account: AccountId, nameQuery: Option[String]): F[Vector[REquipment]] = store.transact(REquipment.findAll(account.collective, nameQuery, _.name)) + def find(account: AccountId, id: Ident): F[Option[REquipment]] = + store.transact(REquipment.findById(id)).map(_.filter(_.cid == account.collective)) + def add(e: REquipment): F[AddResult] = { def insert = REquipment.insert(e) def exists = REquipment.existsByName(e.cid, e.name) diff --git a/modules/backend/src/main/scala/docspell/backend/ops/OOrganization.scala b/modules/backend/src/main/scala/docspell/backend/ops/OOrganization.scala index ca192b97..e007b1af 100644 --- a/modules/backend/src/main/scala/docspell/backend/ops/OOrganization.scala +++ b/modules/backend/src/main/scala/docspell/backend/ops/OOrganization.scala @@ -11,6 +11,7 @@ import docspell.store.records._ trait OOrganization[F[_]] { def findAllOrg(account: AccountId, query: Option[String]): F[Vector[OrgAndContacts]] + def findOrg(account: AccountId, orgId: Ident): F[Option[OrgAndContacts]] def findAllOrgRefs(account: AccountId, nameQuery: Option[String]): F[Vector[IdRef]] @@ -23,6 +24,8 @@ trait OOrganization[F[_]] { query: Option[String] ): F[Vector[PersonAndContacts]] + def findPerson(account: AccountId, persId: Ident): F[Option[PersonAndContacts]] + def findAllPersonRefs(account: AccountId, nameQuery: Option[String]): F[Vector[IdRef]] def addPerson(s: PersonAndContacts): F[AddResult] @@ -53,6 +56,11 @@ object OOrganization { .compile .toVector + def findOrg(account: AccountId, orgId: Ident): F[Option[OrgAndContacts]] = + store + .transact(QOrganization.getOrgAndContact(account.collective, orgId)) + .map(_.map({ case (org, cont) => OrgAndContacts(org, cont) })) + def findAllOrgRefs( account: AccountId, nameQuery: Option[String] @@ -75,6 +83,11 @@ object OOrganization { .compile .toVector + def findPerson(account: AccountId, persId: Ident): F[Option[PersonAndContacts]] = + store + .transact(QOrganization.getPersonAndContact(account.collective, persId)) + .map(_.map({ case (org, cont) => PersonAndContacts(org, cont) })) + def findAllPersonRefs( account: AccountId, nameQuery: Option[String] diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml index 96f66c07..2b23aab9 100644 --- a/modules/restapi/src/main/resources/docspell-openapi.yml +++ b/modules/restapi/src/main/resources/docspell-openapi.yml @@ -778,6 +778,23 @@ paths: schema: $ref: "#/components/schemas/BasicResult" /sec/equipment/{id}: + get: + tags: [ Equipment ] + summary: Get details about a single equipment. + description: | + Loads one equipment by its id. + security: + - authTokenHeader: [] + parameters: + - $ref: "#/components/parameters/id" + responses: + 200: + description: Ok + content: + application/json: + schema: + $ref: "#/components/schemas/Equipment" + delete: tags: [ Equipment ] summary: Delete a equipment. diff --git a/modules/restserver/src/main/scala/docspell/restserver/routes/EquipmentRoutes.scala b/modules/restserver/src/main/scala/docspell/restserver/routes/EquipmentRoutes.scala index a7699115..edfc7521 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/routes/EquipmentRoutes.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/routes/EquipmentRoutes.scala @@ -1,5 +1,6 @@ package docspell.restserver.routes +import cats.data.OptionT import cats.effect._ import cats.implicits._ @@ -49,6 +50,12 @@ object EquipmentRoutes { del <- backend.equipment.delete(id, user.account.collective) resp <- Ok(basicResult(del, "Equipment deleted.")) } yield resp + + case GET -> Root / Ident(id) => + (for { + equip <- OptionT(backend.equipment.find(user.account, id)) + resp <- OptionT.liftF(Ok(mkEquipment(equip))) + } yield resp).getOrElseF(NotFound()) } } } diff --git a/modules/restserver/src/main/scala/docspell/restserver/routes/OrganizationRoutes.scala b/modules/restserver/src/main/scala/docspell/restserver/routes/OrganizationRoutes.scala index 59d17017..4bed90e4 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/routes/OrganizationRoutes.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/routes/OrganizationRoutes.scala @@ -1,5 +1,6 @@ package docspell.restserver.routes +import cats.data.OptionT import cats.effect._ import cats.implicits._ @@ -55,6 +56,12 @@ object OrganizationRoutes { delOrg <- backend.organization.deleteOrg(id, user.account.collective) resp <- Ok(basicResult(delOrg, "Organization deleted.")) } yield resp + + case GET -> Root / Ident(id) => + (for { + org <- OptionT(backend.organization.findOrg(user.account, id)) + resp <- OptionT.liftF(Ok(mkOrg(org))) + } yield resp).getOrElseF(NotFound()) } } diff --git a/modules/restserver/src/main/scala/docspell/restserver/routes/PersonRoutes.scala b/modules/restserver/src/main/scala/docspell/restserver/routes/PersonRoutes.scala index 2e90a9b4..a37ac536 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/routes/PersonRoutes.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/routes/PersonRoutes.scala @@ -1,5 +1,6 @@ package docspell.restserver.routes +import cats.data.OptionT import cats.effect._ import cats.implicits._ @@ -59,6 +60,12 @@ object PersonRoutes { delOrg <- backend.organization.deletePerson(id, user.account.collective) resp <- Ok(basicResult(delOrg, "Person deleted.")) } yield resp + + case GET -> Root / Ident(id) => + (for { + org <- OptionT(backend.organization.findPerson(user.account, id)) + resp <- OptionT.liftF(Ok(mkPerson(org))) + } yield resp).getOrElseF(NotFound()) } } diff --git a/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala b/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala index 159f423c..55ed5259 100644 --- a/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala +++ b/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala @@ -52,6 +52,34 @@ object QOrganization { }) } + def getOrgAndContact( + coll: Ident, + orgId: Ident + ): ConnectionIO[Option[(ROrganization, Vector[RContact])]] = { + val oColl = ROrganization.Columns.cid.prefix("o") + val oId = ROrganization.Columns.oid.prefix("o") + val cOrg = RContact.Columns.orgId.prefix("c") + + val cols = ROrganization.Columns.all.map(_.prefix("o")) ++ RContact.Columns.all + .map(_.prefix("c")) + val from = ROrganization.table ++ fr"o LEFT JOIN" ++ + RContact.table ++ fr"c ON" ++ cOrg.is(oId) + + val q = and(oColl.is(coll), oId.is(orgId)) + + selectSimple(cols, from, q) + .query[(ROrganization, Option[RContact])] + .stream + .groupAdjacentBy(_._1) + .map({ + case (ro, chunk) => + val cs = chunk.toVector.flatMap(_._2) + (ro, cs) + }) + .compile + .last + } + def findPersonAndContact( coll: Ident, query: Option[String], @@ -88,6 +116,34 @@ object QOrganization { }) } + def getPersonAndContact( + coll: Ident, + persId: Ident + ): ConnectionIO[Option[(RPerson, Vector[RContact])]] = { + val pColl = PC.cid.prefix("p") + val pId = RPerson.Columns.pid.prefix("p") + val cPers = RContact.Columns.personId.prefix("c") + + val cols = RPerson.Columns.all.map(_.prefix("p")) ++ RContact.Columns.all + .map(_.prefix("c")) + val from = RPerson.table ++ fr"p LEFT JOIN" ++ + RContact.table ++ fr"c ON" ++ cPers.is(pId) + + val q = and(pColl.is(coll), pId.is(persId)) + + selectSimple(cols, from, q) + .query[(RPerson, Option[RContact])] + .stream + .groupAdjacentBy(_._1) + .map({ + case (ro, chunk) => + val cs = chunk.toVector.flatMap(_._2) + (ro, cs) + }) + .compile + .last + } + def findPersonByContact( coll: Ident, value: String, diff --git a/modules/store/src/main/scala/docspell/store/records/TagItemName.scala b/modules/store/src/main/scala/docspell/store/records/TagItemName.scala index 05689ffd..fffa1f61 100644 --- a/modules/store/src/main/scala/docspell/store/records/TagItemName.scala +++ b/modules/store/src/main/scala/docspell/store/records/TagItemName.scala @@ -1,8 +1,10 @@ package docspell.store.records +import cats.data.NonEmptyList + import docspell.common._ import docspell.store.impl.Implicits._ -import cats.data.NonEmptyList + import doobie._ import doobie.implicits._ From af7cfa0ae1a3bbcf64f8501a9a647896a336b992 Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Fri, 7 Aug 2020 01:22:18 +0200 Subject: [PATCH 4/4] Allow editing metadata in item-detail --- modules/webapp/src/main/elm/Api.elm | 30 ++++ .../webapp/src/main/elm/Comp/DetailEdit.elm | 153 +++++++++++++++++- modules/webapp/src/main/elm/Comp/Dropdown.elm | 6 + .../src/main/elm/Comp/ItemDetail/Update.elm | 57 +++++++ .../src/main/elm/Comp/ItemDetail/View.elm | 23 +++ 5 files changed, 263 insertions(+), 6 deletions(-) diff --git a/modules/webapp/src/main/elm/Api.elm b/modules/webapp/src/main/elm/Api.elm index 2934547d..db1b3aae 100644 --- a/modules/webapp/src/main/elm/Api.elm +++ b/modules/webapp/src/main/elm/Api.elm @@ -31,6 +31,7 @@ module Api exposing , getCollective , getCollectiveSettings , getContacts + , getEquipment , getEquipments , getFolderDetail , getFolders @@ -41,8 +42,10 @@ module Api exposing , getJobQueueStateIn , getMailSettings , getNotifyDueItems + , getOrgFull , getOrgLight , getOrganizations + , getPersonFull , getPersons , getPersonsLight , getScanMailbox @@ -903,6 +906,15 @@ getEquipments flags query receive = } +getEquipment : Flags -> String -> (Result Http.Error Equipment -> msg) -> Cmd msg +getEquipment flags id receive = + Http2.authGet + { url = flags.config.baseUrl ++ "/api/v1/sec/equipment/" ++ id + , account = getAccount flags + , expect = Http.expectJson receive Api.Model.Equipment.decoder + } + + postEquipment : Flags -> Equipment -> (Result Http.Error BasicResult -> msg) -> Cmd msg postEquipment flags equip receive = let @@ -942,6 +954,15 @@ getOrgLight flags receive = } +getOrgFull : String -> Flags -> (Result Http.Error Organization -> msg) -> Cmd msg +getOrgFull id flags receive = + Http2.authGet + { url = flags.config.baseUrl ++ "/api/v1/sec/organization/" ++ id + , account = getAccount flags + , expect = Http.expectJson receive Api.Model.Organization.decoder + } + + getOrganizations : Flags -> String -> (Result Http.Error OrganizationList -> msg) -> Cmd msg getOrganizations flags query receive = Http2.authGet @@ -990,6 +1011,15 @@ getPersonsLight flags receive = } +getPersonFull : String -> Flags -> (Result Http.Error Person -> msg) -> Cmd msg +getPersonFull id flags receive = + Http2.authGet + { url = flags.config.baseUrl ++ "/api/v1/sec/person/" ++ id + , account = getAccount flags + , expect = Http.expectJson receive Api.Model.Person.decoder + } + + getPersons : Flags -> String -> (Result Http.Error PersonList -> msg) -> Cmd msg getPersons flags query receive = Http2.authGet diff --git a/modules/webapp/src/main/elm/Comp/DetailEdit.elm b/modules/webapp/src/main/elm/Comp/DetailEdit.elm index 2b7e79b9..3d734c63 100644 --- a/modules/webapp/src/main/elm/Comp/DetailEdit.elm +++ b/modules/webapp/src/main/elm/Comp/DetailEdit.elm @@ -2,6 +2,9 @@ module Comp.DetailEdit exposing ( Model , Msg , Value(..) + , editEquip + , editOrg + , editPerson , initConcPerson , initCorrPerson , initEquip @@ -44,6 +47,7 @@ type alias Model = { form : FormModel , itemId : String , submitting : Bool + , loading : Bool , result : Maybe BasicResult } @@ -86,6 +90,7 @@ init itemId fm = { form = fm , itemId = itemId , submitting = False + , loading = False , result = Nothing } @@ -100,6 +105,42 @@ initOrg itemId om = init itemId (OM om) +editOrg : Flags -> String -> Comp.OrgForm.Model -> ( Model, Cmd Msg ) +editOrg flags orgId om = + ( { form = OM om + , itemId = "" + , submitting = False + , loading = True + , result = Nothing + } + , Api.getOrgFull orgId flags GetOrgResp + ) + + +editPerson : Flags -> String -> Comp.PersonForm.Model -> ( Model, Cmd Msg ) +editPerson flags persId pm = + ( { form = PMC pm + , itemId = "" + , submitting = False + , loading = True + , result = Nothing + } + , Api.getPersonFull persId flags GetPersonResp + ) + + +editEquip : Flags -> String -> Comp.EquipmentForm.Model -> ( Model, Cmd Msg ) +editEquip flags equipId em = + ( { form = EM em + , itemId = "" + , submitting = False + , loading = True + , result = Nothing + } + , Api.getEquipment flags equipId GetEquipResp + ) + + initCorrPerson : String -> Comp.PersonForm.Model -> Model initCorrPerson itemId pm = init itemId (PMR pm) @@ -135,6 +176,9 @@ type Msg | Submit | Cancel | SubmitResp (Result Http.Error BasicResult) + | GetOrgResp (Result Http.Error Organization) + | GetPersonResp (Result Http.Error Person) + | GetEquipResp (Result Http.Error Equipment) type Value @@ -174,6 +218,87 @@ update flags msg model = Cancel -> ( model, Cmd.none, Just CancelForm ) + GetOrgResp (Ok org) -> + case model.form of + OM om -> + let + ( om_, oc_ ) = + Comp.OrgForm.update flags (Comp.OrgForm.SetOrg org) om + in + ( { model + | loading = False + , form = OM om_ + } + , Cmd.map OrgMsg oc_ + , Nothing + ) + + _ -> + ( { model | loading = False } + , Cmd.none + , Nothing + ) + + GetOrgResp (Err err) -> + ( { model | loading = False, result = Just (BasicResult False (Util.Http.errorToString err)) } + , Cmd.none + , Nothing + ) + + GetPersonResp (Ok pers) -> + case model.form of + PMC pm -> + let + ( pm_, pc_ ) = + Comp.PersonForm.update flags (Comp.PersonForm.SetPerson pers) pm + in + ( { model + | loading = False + , form = PMC pm_ + } + , Cmd.map PersonMsg pc_ + , Nothing + ) + + _ -> + ( { model | loading = False } + , Cmd.none + , Nothing + ) + + GetPersonResp (Err err) -> + ( { model | loading = False, result = Just (BasicResult False (Util.Http.errorToString err)) } + , Cmd.none + , Nothing + ) + + GetEquipResp (Ok equip) -> + case model.form of + EM em -> + let + ( em_, ec_ ) = + Comp.EquipmentForm.update flags (Comp.EquipmentForm.SetEquipment equip) em + in + ( { model + | loading = False + , form = EM em_ + } + , Cmd.map EquipMsg ec_ + , Nothing + ) + + _ -> + ( { model | loading = False } + , Cmd.none + , Nothing + ) + + GetEquipResp (Err err) -> + ( { model | loading = False, result = Just (BasicResult False (Util.Http.errorToString err)) } + , Cmd.none + , Nothing + ) + SubmitResp (Ok res) -> ( { model | result = Just res @@ -222,7 +347,11 @@ update flags msg model = in if Comp.OrgForm.isValid om then ( { model | submitting = True } - , Api.addCorrOrg flags model.itemId org SubmitResp + , if model.itemId == "" then + Api.postOrg flags org SubmitResp + + else + Api.addCorrOrg flags model.itemId org SubmitResp , Nothing ) @@ -239,7 +368,11 @@ update flags msg model = in if Comp.PersonForm.isValid pm then ( { model | submitting = True } - , Api.addConcPerson flags model.itemId pers SubmitResp + , if model.itemId == "" then + Api.postPerson flags pers SubmitResp + + else + Api.addConcPerson flags model.itemId pers SubmitResp , Nothing ) @@ -256,7 +389,11 @@ update flags msg model = in if Comp.PersonForm.isValid pm then ( { model | submitting = True } - , Api.addCorrPerson flags model.itemId pers SubmitResp + , if model.itemId == "" then + Api.postPerson flags pers SubmitResp + + else + Api.addCorrPerson flags model.itemId pers SubmitResp , Nothing ) @@ -273,7 +410,11 @@ update flags msg model = in if Comp.EquipmentForm.isValid em then ( { model | submitting = True } - , Api.addConcEquip flags model.itemId equip SubmitResp + , if model.itemId == "" then + Api.postEquipment flags equip SubmitResp + + else + Api.addConcEquip flags model.itemId equip SubmitResp , Nothing ) @@ -379,9 +520,9 @@ viewButtons model = [ class "ui primary button" , href "#" , onClick Submit - , disabled model.submitting + , disabled (model.submitting || model.loading) ] - [ if model.submitting then + [ if model.submitting || model.loading then i [ class "ui spinner loading icon" ] [] else diff --git a/modules/webapp/src/main/elm/Comp/Dropdown.elm b/modules/webapp/src/main/elm/Comp/Dropdown.elm index 458057d7..d6247e0a 100644 --- a/modules/webapp/src/main/elm/Comp/Dropdown.elm +++ b/modules/webapp/src/main/elm/Comp/Dropdown.elm @@ -9,6 +9,7 @@ module Comp.Dropdown exposing , makeSingle , makeSingleList , mkOption + , notSelected , setMkOption , update , view @@ -155,6 +156,11 @@ getSelected model = List.map .value model.selected +notSelected : Model a -> Bool +notSelected model = + getSelected model |> List.isEmpty + + type Msg a = SetOptions (List a) | SetSelection (List a) diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm index 9328b702..543a15f2 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm @@ -122,6 +122,9 @@ type Msg | EditAttachNameResp (Result Http.Error BasicResult) | GetFolderResp (Result Http.Error FolderList) | FolderDropdownMsg (Comp.Dropdown.Msg IdName) + | StartEditCorrOrgModal + | StartEditPersonModal (Comp.Dropdown.Model IdName) + | StartEditEquipModal update : Nav.Key -> Flags -> Maybe String -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg ) @@ -1046,6 +1049,42 @@ update key flags next msg model = , Cmd.none ) + StartEditCorrOrgModal -> + let + orgId = + Comp.Dropdown.getSelected model.corrOrgModel + |> List.head + |> Maybe.map .id + in + case orgId of + Just oid -> + let + ( m, c ) = + Comp.DetailEdit.editOrg flags oid Comp.OrgForm.emptyModel + in + noSub ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) + + Nothing -> + ( model, Cmd.none, Sub.none ) + + StartEditEquipModal -> + let + equipId = + Comp.Dropdown.getSelected model.concEquipModel + |> List.head + |> Maybe.map .id + in + case equipId of + Just eid -> + let + ( m, c ) = + Comp.DetailEdit.editEquip flags eid Comp.EquipmentForm.emptyModel + in + noSub ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) + + Nothing -> + ( model, Cmd.none, Sub.none ) + StartCorrPersonModal -> noSub ( { model @@ -1072,6 +1111,24 @@ update key flags next msg model = , Cmd.none ) + StartEditPersonModal pm -> + let + persId = + Comp.Dropdown.getSelected pm + |> List.head + |> Maybe.map .id + in + case persId of + Just pid -> + let + ( m, c ) = + Comp.DetailEdit.editPerson flags pid Comp.PersonForm.emptyModel + in + noSub ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) + + Nothing -> + ( model, Cmd.none, Sub.none ) + StartEquipModal -> noSub ( { model diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm index 9d281923..e98115e3 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm @@ -741,6 +741,19 @@ renderEditForm settings model = ] [ i [ class "grey plus link icon" ] [] ] + + editIconLink tip dm m = + a + [ classList + [ ( "right-float", True ) + , ( "invisible hidden", Comp.Dropdown.notSelected dm ) + ] + , href "#" + , title tip + , onClick m + ] + [ i [ class "grey pencil alternate link icon" ] [] + ] in div [ class "ui attached segment" ] [ div [ class "ui form warning" ] @@ -834,6 +847,7 @@ item visible. This message will disappear then. [ Icons.organizationIcon "grey" , text "Organization" , addIconLink "Add new organization" StartCorrOrgModal + , editIconLink "Edit organization" model.corrOrgModel StartEditCorrOrgModal ] , Html.map OrgDropdownMsg (Comp.Dropdown.view settings model.corrOrgModel) , renderOrgSuggestions model @@ -843,6 +857,9 @@ item visible. This message will disappear then. [ Icons.personIcon "grey" , text "Person" , addIconLink "Add new correspondent person" StartCorrPersonModal + , editIconLink "Edit person" + model.corrPersonModel + (StartEditPersonModal model.corrPersonModel) ] , Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel) , renderCorrPersonSuggestions model @@ -856,6 +873,9 @@ item visible. This message will disappear then. [ Icons.personIcon "grey" , text "Person" , addIconLink "Add new concerning person" StartConcPersonModal + , editIconLink "Edit person" + model.concPersonModel + (StartEditPersonModal model.concPersonModel) ] , Html.map ConcPersonMsg (Comp.Dropdown.view settings model.concPersonModel) , renderConcPersonSuggestions model @@ -865,6 +885,9 @@ item visible. This message will disappear then. [ Icons.equipmentIcon "grey" , text "Equipment" , addIconLink "Add new equipment" StartEquipModal + , editIconLink "Edit equipment" + model.concEquipModel + StartEditEquipModal ] , Html.map ConcEquipMsg (Comp.Dropdown.view settings model.concEquipModel) , renderConcEquipSuggestions model