Extend search stats to fully populate search menu

Refs: #856
This commit is contained in:
eikek 2021-10-05 13:50:31 +02:00
parent e961a5ac10
commit 813797756c
8 changed files with 167 additions and 8 deletions

View File

@ -5305,6 +5305,10 @@ components:
- tagCategoryCloud
- fieldStats
- folderStats
- corrOrgStats
- corrPersStats
- concPersStats
- concEquipStats
properties:
count:
type: integer
@ -5321,6 +5325,23 @@ components:
type: array
items:
$ref: "#/components/schemas/FolderStats"
corrOrgStats:
type: array
items:
$ref: "#/components/schemas/IdRefStats"
corrPersStats:
type: array
items:
$ref: "#/components/schemas/IdRefStats"
concPersStats:
type: array
items:
$ref: "#/components/schemas/IdRefStats"
concEquipStats:
type: array
items:
$ref: "#/components/schemas/IdRefStats"
ItemInsights:
description: |
Information about the items in docspell.
@ -5454,6 +5475,19 @@ components:
type: integer
format: int32
IdRefStats:
description: |
Counting some objects that have an id and a name.
required:
- ref
- count
properties:
ref:
$ref: "#/components/schemas/IdName"
count:
type: integer
format: int32
AttachmentMeta:
description: |
Extracted meta data of an attachment.

View File

@ -7,11 +7,9 @@
package docspell.restserver.conv
import java.time.{LocalDate, ZoneId}
import cats.effect.{Async, Sync}
import cats.implicits._
import fs2.Stream
import docspell.backend.ops.OCollective.{InsightData, PassChangeResult}
import docspell.backend.ops.OCustomFields.SetValueResult
import docspell.backend.ops.OJob.JobCancelResult
@ -22,10 +20,9 @@ import docspell.common.syntax.all._
import docspell.ftsclient.FtsResult
import docspell.restapi.model._
import docspell.restserver.conv.Conversions._
import docspell.store.queries.{AttachmentLight => QAttachmentLight}
import docspell.store.queries.{AttachmentLight => QAttachmentLight, IdRefCount}
import docspell.store.records._
import docspell.store.{AddResult, UpdateResult}
import org.http4s.headers.`Content-Type`
import org.http4s.multipart.Multipart
import org.log4s.Logger
@ -38,9 +35,16 @@ trait Conversions {
mkTagCloud(sum.tags),
mkTagCategoryCloud(sum.cats),
sum.fields.map(mkFieldStats),
sum.folders.map(mkFolderStats)
sum.folders.map(mkFolderStats),
sum.corrOrgs.map(mkIdRefStats),
sum.corrPers.map(mkIdRefStats),
sum.concPers.map(mkIdRefStats),
sum.concEquip.map(mkIdRefStats)
)
def mkIdRefStats(s: IdRefCount): IdRefStats =
IdRefStats(mkIdName(s.ref), s.count)
def mkFolderStats(fs: docspell.store.queries.FolderCount): FolderStats =
FolderStats(fs.id, fs.name, mkIdName(fs.owner), fs.count)

View File

@ -0,0 +1,5 @@
package docspell.store.queries
import docspell.common._
final case class IdRefCount(ref: IdRef, count: Int) {}

View File

@ -192,7 +192,21 @@ object QItem {
cats <- searchTagCategorySummary(today)(q)
fields <- searchFieldSummary(today)(q)
folders <- searchFolderSummary(today)(q)
} yield SearchSummary(count, tags, cats, fields, folders)
orgs <- searchCorrOrgSummary(today)(q)
corrPers <- searchCorrPersonSummary(today)(q)
concPers <- searchConcPersonSummary(today)(q)
concEquip <- searchConcEquipSummary(today)(q)
} yield SearchSummary(
count,
tags,
cats,
fields,
folders,
orgs,
corrPers,
concPers,
concEquip
)
def searchTagCategorySummary(
today: LocalDate
@ -251,6 +265,40 @@ object QItem {
.query[Int]
.unique
def searchCorrOrgSummary(today: LocalDate)(q: Query): ConnectionIO[List[IdRefCount]] =
searchIdRefSummary(org.oid, org.name, i.corrOrg, today)(q)
def searchCorrPersonSummary(today: LocalDate)(
q: Query
): ConnectionIO[List[IdRefCount]] =
searchIdRefSummary(pers0.pid, pers0.name, i.corrPerson, today)(q)
def searchConcPersonSummary(today: LocalDate)(
q: Query
): ConnectionIO[List[IdRefCount]] =
searchIdRefSummary(pers1.pid, pers1.name, i.concPerson, today)(q)
def searchConcEquipSummary(today: LocalDate)(
q: Query
): ConnectionIO[List[IdRefCount]] =
searchIdRefSummary(equip.eid, equip.name, i.concEquipment, today)(q)
private def searchIdRefSummary(
idCol: Column[Ident],
nameCol: Column[String],
fkCol: Column[Ident],
today: LocalDate
)(q: Query): ConnectionIO[List[IdRefCount]] =
findItemsBase(q.fix, today, 0).unwrap
.withSelect(select(idCol, nameCol).append(count(idCol).as("num")))
.changeWhere(c =>
c && fkCol.isNotNull && queryCondition(today, q.fix.account.collective, q.cond)
)
.groupBy(idCol, nameCol)
.build
.query[IdRefCount]
.to[List]
def searchFolderSummary(today: LocalDate)(q: Query): ConnectionIO[List[FolderCount]] = {
val fu = RUser.as("fu")
findItemsBase(q.fix, today, 0).unwrap

View File

@ -11,7 +11,11 @@ case class SearchSummary(
tags: List[TagCount],
cats: List[CategoryCount],
fields: List[FieldStats],
folders: List[FolderCount]
folders: List[FolderCount],
corrOrgs: List[IdRefCount],
corrPers: List[IdRefCount],
concPers: List[IdRefCount],
concEquip: List[IdRefCount]
) {
def onlyExisting: SearchSummary =
@ -20,6 +24,10 @@ case class SearchSummary(
tags.filter(_.count > 0),
cats.filter(_.count > 0),
fields.filter(_.count > 0),
folders.filter(_.count > 0)
folders.filter(_.count > 0),
corrOrgs = corrOrgs.filter(_.count > 0),
corrPers = corrPers.filter(_.count > 0),
concPers = concPers.filter(_.count > 0),
concEquip = concEquip.filter(_.count > 0)
)
}

View File

@ -16,6 +16,7 @@ module Comp.CustomFieldMultiInput exposing
, isEmpty
, nonEmpty
, reset
, setOptions
, setValues
, update
, updateSearch
@ -125,6 +126,11 @@ setValues values =
SetValues values
setOptions : List CustomField -> Msg
setOptions fields =
CustomFieldResp (Ok (CustomFieldList fields))
reset : Model -> Model
reset model =
let

View File

@ -60,6 +60,7 @@ import Http
import Messages.Comp.SearchMenu exposing (Texts)
import Set exposing (Set)
import Styles as S
import Util.CustomField
import Util.Html exposing (KeyCode(..))
import Util.ItemDragDrop as DD
import Util.Maybe
@ -564,6 +565,42 @@ updateDrop ddm flags settings msg model =
selectModel =
Comp.TagSelect.modifyCount model.tagSelectModel tagCount catCount
orgOpts =
Comp.Dropdown.update (Comp.Dropdown.SetOptions (List.map .ref stats.corrOrgStats))
model.orgModel
|> Tuple.first
corrPersOpts =
Comp.Dropdown.update (Comp.Dropdown.SetOptions (List.map .ref stats.corrPersStats))
model.corrPersonModel
|> Tuple.first
concPersOpts =
Comp.Dropdown.update (Comp.Dropdown.SetOptions (List.map .ref stats.concPersStats))
model.concPersonModel
|> Tuple.first
concEquipOpts =
let
mkEquip ref =
Equipment ref.id ref.name 0 Nothing ""
in
Comp.Dropdown.update
(Comp.Dropdown.SetOptions
(List.map (.ref >> mkEquip) stats.concEquipStats)
)
model.concEquipmentModel
|> Tuple.first
fields =
Util.CustomField.statsToFields stats
fieldOpts =
Comp.CustomFieldMultiInput.update flags
(Comp.CustomFieldMultiInput.setOptions fields)
model.customFieldModel
|> .model
model_ =
{ model
| tagSelectModel = selectModel
@ -571,6 +608,11 @@ updateDrop ddm flags settings msg model =
Comp.FolderSelect.modify model.selectedFolder
model.folderList
stats.folderStats
, orgModel = orgOpts
, corrPersonModel = corrPersOpts
, concPersonModel = concPersOpts
, concEquipmentModel = concEquipOpts
, customFieldModel = fieldOpts
}
in
{ model = model_

View File

@ -10,9 +10,12 @@ module Util.CustomField exposing
, nameOrLabel
, renderValue
, renderValue2
, statsToFields
)
import Api.Model.CustomField exposing (CustomField)
import Api.Model.ItemFieldValue exposing (ItemFieldValue)
import Api.Model.SearchStats exposing (SearchStats)
import Data.CustomFieldType
import Data.Icons as Icons
import Html exposing (..)
@ -20,6 +23,15 @@ import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
statsToFields : SearchStats -> List CustomField
statsToFields stats =
let
mkField fs =
CustomField fs.id fs.name fs.label fs.ftype fs.count 0
in
List.map mkField stats.fieldStats
{-| This is how the server wants the value to a bool custom field
-}
boolValue : Bool -> String