mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-06 15:15:58 +00:00
parent
e961a5ac10
commit
813797756c
@ -5305,6 +5305,10 @@ components:
|
|||||||
- tagCategoryCloud
|
- tagCategoryCloud
|
||||||
- fieldStats
|
- fieldStats
|
||||||
- folderStats
|
- folderStats
|
||||||
|
- corrOrgStats
|
||||||
|
- corrPersStats
|
||||||
|
- concPersStats
|
||||||
|
- concEquipStats
|
||||||
properties:
|
properties:
|
||||||
count:
|
count:
|
||||||
type: integer
|
type: integer
|
||||||
@ -5321,6 +5325,23 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/FolderStats"
|
$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:
|
ItemInsights:
|
||||||
description: |
|
description: |
|
||||||
Information about the items in docspell.
|
Information about the items in docspell.
|
||||||
@ -5454,6 +5475,19 @@ components:
|
|||||||
type: integer
|
type: integer
|
||||||
format: int32
|
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:
|
AttachmentMeta:
|
||||||
description: |
|
description: |
|
||||||
Extracted meta data of an attachment.
|
Extracted meta data of an attachment.
|
||||||
|
@ -7,11 +7,9 @@
|
|||||||
package docspell.restserver.conv
|
package docspell.restserver.conv
|
||||||
|
|
||||||
import java.time.{LocalDate, ZoneId}
|
import java.time.{LocalDate, ZoneId}
|
||||||
|
|
||||||
import cats.effect.{Async, Sync}
|
import cats.effect.{Async, Sync}
|
||||||
import cats.implicits._
|
import cats.implicits._
|
||||||
import fs2.Stream
|
import fs2.Stream
|
||||||
|
|
||||||
import docspell.backend.ops.OCollective.{InsightData, PassChangeResult}
|
import docspell.backend.ops.OCollective.{InsightData, PassChangeResult}
|
||||||
import docspell.backend.ops.OCustomFields.SetValueResult
|
import docspell.backend.ops.OCustomFields.SetValueResult
|
||||||
import docspell.backend.ops.OJob.JobCancelResult
|
import docspell.backend.ops.OJob.JobCancelResult
|
||||||
@ -22,10 +20,9 @@ import docspell.common.syntax.all._
|
|||||||
import docspell.ftsclient.FtsResult
|
import docspell.ftsclient.FtsResult
|
||||||
import docspell.restapi.model._
|
import docspell.restapi.model._
|
||||||
import docspell.restserver.conv.Conversions._
|
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.records._
|
||||||
import docspell.store.{AddResult, UpdateResult}
|
import docspell.store.{AddResult, UpdateResult}
|
||||||
|
|
||||||
import org.http4s.headers.`Content-Type`
|
import org.http4s.headers.`Content-Type`
|
||||||
import org.http4s.multipart.Multipart
|
import org.http4s.multipart.Multipart
|
||||||
import org.log4s.Logger
|
import org.log4s.Logger
|
||||||
@ -38,9 +35,16 @@ trait Conversions {
|
|||||||
mkTagCloud(sum.tags),
|
mkTagCloud(sum.tags),
|
||||||
mkTagCategoryCloud(sum.cats),
|
mkTagCategoryCloud(sum.cats),
|
||||||
sum.fields.map(mkFieldStats),
|
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 =
|
def mkFolderStats(fs: docspell.store.queries.FolderCount): FolderStats =
|
||||||
FolderStats(fs.id, fs.name, mkIdName(fs.owner), fs.count)
|
FolderStats(fs.id, fs.name, mkIdName(fs.owner), fs.count)
|
||||||
|
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package docspell.store.queries
|
||||||
|
|
||||||
|
import docspell.common._
|
||||||
|
|
||||||
|
final case class IdRefCount(ref: IdRef, count: Int) {}
|
@ -192,7 +192,21 @@ object QItem {
|
|||||||
cats <- searchTagCategorySummary(today)(q)
|
cats <- searchTagCategorySummary(today)(q)
|
||||||
fields <- searchFieldSummary(today)(q)
|
fields <- searchFieldSummary(today)(q)
|
||||||
folders <- searchFolderSummary(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(
|
def searchTagCategorySummary(
|
||||||
today: LocalDate
|
today: LocalDate
|
||||||
@ -251,6 +265,40 @@ object QItem {
|
|||||||
.query[Int]
|
.query[Int]
|
||||||
.unique
|
.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]] = {
|
def searchFolderSummary(today: LocalDate)(q: Query): ConnectionIO[List[FolderCount]] = {
|
||||||
val fu = RUser.as("fu")
|
val fu = RUser.as("fu")
|
||||||
findItemsBase(q.fix, today, 0).unwrap
|
findItemsBase(q.fix, today, 0).unwrap
|
||||||
|
@ -11,7 +11,11 @@ case class SearchSummary(
|
|||||||
tags: List[TagCount],
|
tags: List[TagCount],
|
||||||
cats: List[CategoryCount],
|
cats: List[CategoryCount],
|
||||||
fields: List[FieldStats],
|
fields: List[FieldStats],
|
||||||
folders: List[FolderCount]
|
folders: List[FolderCount],
|
||||||
|
corrOrgs: List[IdRefCount],
|
||||||
|
corrPers: List[IdRefCount],
|
||||||
|
concPers: List[IdRefCount],
|
||||||
|
concEquip: List[IdRefCount]
|
||||||
) {
|
) {
|
||||||
|
|
||||||
def onlyExisting: SearchSummary =
|
def onlyExisting: SearchSummary =
|
||||||
@ -20,6 +24,10 @@ case class SearchSummary(
|
|||||||
tags.filter(_.count > 0),
|
tags.filter(_.count > 0),
|
||||||
cats.filter(_.count > 0),
|
cats.filter(_.count > 0),
|
||||||
fields.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)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ module Comp.CustomFieldMultiInput exposing
|
|||||||
, isEmpty
|
, isEmpty
|
||||||
, nonEmpty
|
, nonEmpty
|
||||||
, reset
|
, reset
|
||||||
|
, setOptions
|
||||||
, setValues
|
, setValues
|
||||||
, update
|
, update
|
||||||
, updateSearch
|
, updateSearch
|
||||||
@ -125,6 +126,11 @@ setValues values =
|
|||||||
SetValues values
|
SetValues values
|
||||||
|
|
||||||
|
|
||||||
|
setOptions : List CustomField -> Msg
|
||||||
|
setOptions fields =
|
||||||
|
CustomFieldResp (Ok (CustomFieldList fields))
|
||||||
|
|
||||||
|
|
||||||
reset : Model -> Model
|
reset : Model -> Model
|
||||||
reset model =
|
reset model =
|
||||||
let
|
let
|
||||||
|
@ -60,6 +60,7 @@ import Http
|
|||||||
import Messages.Comp.SearchMenu exposing (Texts)
|
import Messages.Comp.SearchMenu exposing (Texts)
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
import Styles as S
|
import Styles as S
|
||||||
|
import Util.CustomField
|
||||||
import Util.Html exposing (KeyCode(..))
|
import Util.Html exposing (KeyCode(..))
|
||||||
import Util.ItemDragDrop as DD
|
import Util.ItemDragDrop as DD
|
||||||
import Util.Maybe
|
import Util.Maybe
|
||||||
@ -564,6 +565,42 @@ updateDrop ddm flags settings msg model =
|
|||||||
selectModel =
|
selectModel =
|
||||||
Comp.TagSelect.modifyCount model.tagSelectModel tagCount catCount
|
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_ =
|
||||||
{ model
|
{ model
|
||||||
| tagSelectModel = selectModel
|
| tagSelectModel = selectModel
|
||||||
@ -571,6 +608,11 @@ updateDrop ddm flags settings msg model =
|
|||||||
Comp.FolderSelect.modify model.selectedFolder
|
Comp.FolderSelect.modify model.selectedFolder
|
||||||
model.folderList
|
model.folderList
|
||||||
stats.folderStats
|
stats.folderStats
|
||||||
|
, orgModel = orgOpts
|
||||||
|
, corrPersonModel = corrPersOpts
|
||||||
|
, concPersonModel = concPersOpts
|
||||||
|
, concEquipmentModel = concEquipOpts
|
||||||
|
, customFieldModel = fieldOpts
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
{ model = model_
|
{ model = model_
|
||||||
|
@ -10,9 +10,12 @@ module Util.CustomField exposing
|
|||||||
, nameOrLabel
|
, nameOrLabel
|
||||||
, renderValue
|
, renderValue
|
||||||
, renderValue2
|
, renderValue2
|
||||||
|
, statsToFields
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import Api.Model.CustomField exposing (CustomField)
|
||||||
import Api.Model.ItemFieldValue exposing (ItemFieldValue)
|
import Api.Model.ItemFieldValue exposing (ItemFieldValue)
|
||||||
|
import Api.Model.SearchStats exposing (SearchStats)
|
||||||
import Data.CustomFieldType
|
import Data.CustomFieldType
|
||||||
import Data.Icons as Icons
|
import Data.Icons as Icons
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
@ -20,6 +23,15 @@ import Html.Attributes exposing (..)
|
|||||||
import Html.Events exposing (onClick)
|
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
|
{-| This is how the server wants the value to a bool custom field
|
||||||
-}
|
-}
|
||||||
boolValue : Bool -> String
|
boolValue : Bool -> String
|
||||||
|
Loading…
x
Reference in New Issue
Block a user