Change job priority on queue page

This commit is contained in:
Eike Kettner
2020-09-05 16:00:41 +02:00
parent 1dcccbcf7d
commit 06879456a6
10 changed files with 140 additions and 11 deletions

View File

@ -5,8 +5,10 @@ import cats.effect._
import cats.implicits._ import cats.implicits._
import docspell.backend.ops.OJob.{CollectiveQueueState, JobCancelResult} import docspell.backend.ops.OJob.{CollectiveQueueState, JobCancelResult}
import docspell.common.Priority
import docspell.common.{Ident, JobState} import docspell.common.{Ident, JobState}
import docspell.store.Store import docspell.store.Store
import docspell.store.UpdateResult
import docspell.store.queries.QJob import docspell.store.queries.QJob
import docspell.store.records.{RJob, RJobLog} import docspell.store.records.{RJob, RJobLog}
@ -15,6 +17,8 @@ trait OJob[F[_]] {
def queueState(collective: Ident, maxResults: Int): F[CollectiveQueueState] def queueState(collective: Ident, maxResults: Int): F[CollectiveQueueState]
def cancelJob(id: Ident, collective: Ident): F[JobCancelResult] def cancelJob(id: Ident, collective: Ident): F[JobCancelResult]
def setPriority(id: Ident, collective: Ident, prio: Priority): F[UpdateResult]
} }
object OJob { object OJob {
@ -56,6 +60,9 @@ object OJob {
.toVector .toVector
.map(CollectiveQueueState) .map(CollectiveQueueState)
def setPriority(id: Ident, collective: Ident, prio: Priority): F[UpdateResult] =
UpdateResult.fromUpdate(store.transact(RJob.setPriority(id, collective, prio)))
def cancelJob(id: Ident, collective: Ident): F[JobCancelResult] = { def cancelJob(id: Ident, collective: Ident): F[JobCancelResult] = {
def remove(job: RJob): F[JobCancelResult] = def remove(job: RJob): F[JobCancelResult] =
store.transact(RJob.delete(job.id)) *> JobCancelResult.removed.pure[F] store.transact(RJob.delete(job.id)) *> JobCancelResult.removed.pure[F]

View File

@ -12,6 +12,8 @@ object JobState {
/** Waiting for being executed. */ /** Waiting for being executed. */
case object Waiting extends JobState {} case object Waiting extends JobState {}
def waiting: JobState = Waiting
/** A scheduler has picked up this job and will pass it to the next /** A scheduler has picked up this job and will pass it to the next
* free slot. * free slot.
*/ */

View File

@ -2167,6 +2167,30 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/queue/{id}/priority:
post:
tags: [ Job Queue ]
summary: Change the priority of a waiting job.
description: |
A waiting job can change its priority. If the job is not in
state waiting, this operation fails.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/JobPriority"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/email/settings/smtp: /sec/email/settings/smtp:
get: get:
tags: [ E-Mail ] tags: [ E-Mail ]
@ -2678,6 +2702,18 @@ paths:
components: components:
schemas: schemas:
JobPriority:
description: |
Transfer the priority of a job.
required:
- priority
properties:
priority:
type: string
format: priority
enum:
- high
- low
IdList: IdList:
description: description:
A list of identifiers. A list of identifiers.
@ -3512,6 +3548,9 @@ components:
priority: priority:
type: string type: string
format: priority format: priority
enum:
- high
- low
state: state:
type: string type: string
format: jobstate format: jobstate
@ -3744,6 +3783,9 @@ components:
priority: priority:
type: string type: string
format: priority format: priority
enum:
- high
- low
folder: folder:
type: string type: string
format: ident format: ident

View File

@ -6,9 +6,11 @@ import cats.implicits._
import docspell.backend.BackendApp import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken import docspell.backend.auth.AuthToken
import docspell.common.Ident import docspell.common.Ident
import docspell.restapi.model.JobPriority
import docspell.restserver.conv.Conversions import docspell.restserver.conv.Conversions
import org.http4s.HttpRoutes import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._ import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl import org.http4s.dsl.Http4sDsl
@ -31,6 +33,13 @@ object JobQueueRoutes {
result <- backend.job.cancelJob(id, user.account.collective) result <- backend.job.cancelJob(id, user.account.collective)
resp <- Ok(Conversions.basicResult(result)) resp <- Ok(Conversions.basicResult(result))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "priority" =>
for {
prio <- req.as[JobPriority]
res <- backend.job.setPriority(id, user.account.collective, prio.priority)
resp <- Ok(Conversions.basicResult(res, "Job priority changed"))
} yield resp
} }
} }

View File

@ -231,6 +231,13 @@ object RJob {
) )
).update.run ).update.run
def setPriority(jobId: Ident, jobGroup: Ident, prio: Priority): ConnectionIO[Int] =
updateRow(
table,
and(id.is(jobId), group.is(jobGroup), state.is(JobState.waiting)),
priority.setTo(prio)
).update.run
def getRetries(jobId: Ident): ConnectionIO[Option[Int]] = def getRetries(jobId: Ident): ConnectionIO[Option[Int]] =
selectSimple(List(retries), table, id.is(jobId)).query[Int].option selectSimple(List(retries), table, id.is(jobId)).query[Int].option

View File

@ -86,6 +86,7 @@ module Api exposing
, setItemDueDate , setItemDueDate
, setItemName , setItemName
, setItemNotes , setItemNotes
, setJobPrio
, setTags , setTags
, setUnconfirmed , setUnconfirmed
, startClassifier , startClassifier
@ -129,6 +130,7 @@ import Api.Model.ItemLightList exposing (ItemLightList)
import Api.Model.ItemProposals exposing (ItemProposals) import Api.Model.ItemProposals exposing (ItemProposals)
import Api.Model.ItemSearch exposing (ItemSearch) import Api.Model.ItemSearch exposing (ItemSearch)
import Api.Model.ItemUploadMeta exposing (ItemUploadMeta) import Api.Model.ItemUploadMeta exposing (ItemUploadMeta)
import Api.Model.JobPriority exposing (JobPriority)
import Api.Model.JobQueueState exposing (JobQueueState) import Api.Model.JobQueueState exposing (JobQueueState)
import Api.Model.MoveAttachment exposing (MoveAttachment) import Api.Model.MoveAttachment exposing (MoveAttachment)
import Api.Model.NewFolder exposing (NewFolder) import Api.Model.NewFolder exposing (NewFolder)
@ -160,6 +162,7 @@ import Api.Model.UserPass exposing (UserPass)
import Api.Model.VersionInfo exposing (VersionInfo) 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 File exposing (File) import File exposing (File)
import Http import Http
import Json.Encode as JsonEncode import Json.Encode as JsonEncode
@ -1197,6 +1200,21 @@ deleteUser flags user receive =
--- Job Queue --- Job Queue
setJobPrio : Flags -> String -> Priority -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setJobPrio flags jobid prio receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/queue/" ++ jobid ++ "/priority"
, account = getAccount flags
, body =
Data.Priority.toName prio
|> String.toLower
|> JobPriority
|> Api.Model.JobPriority.encode
|> Http.jsonBody
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
cancelJob : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg cancelJob : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
cancelJob flags jobid receive = cancelJob flags jobid receive =
Http2.authPost Http2.authPost

View File

@ -2,6 +2,7 @@ module Data.Priority exposing
( Priority(..) ( Priority(..)
, all , all
, fromString , fromString
, next
, toName , toName
) )
@ -38,6 +39,16 @@ toName lang =
"High" "High"
next : Priority -> Priority
next prio =
case prio of
High ->
Low
Low ->
High
all : List Priority all : List Priority
all = all =
[ Low, High ] [ Low, High ]

View File

@ -10,6 +10,7 @@ import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.JobDetail exposing (JobDetail) import Api.Model.JobDetail exposing (JobDetail)
import Api.Model.JobQueueState exposing (JobQueueState) import Api.Model.JobQueueState exposing (JobQueueState)
import Comp.YesNoDimmer import Comp.YesNoDimmer
import Data.Priority exposing (Priority)
import Http import Http
import Time import Time
import Util.Duration import Util.Duration
@ -53,6 +54,7 @@ type Msg
| RequestCancelJob JobDetail | RequestCancelJob JobDetail
| DimmerMsg JobDetail Comp.YesNoDimmer.Msg | DimmerMsg JobDetail Comp.YesNoDimmer.Msg
| CancelResp (Result Http.Error BasicResult) | CancelResp (Result Http.Error BasicResult)
| ChangePrio String Priority
getRunningTime : Model -> JobDetail -> Maybe String getRunningTime : Model -> JobDetail -> Maybe String

View File

@ -86,6 +86,9 @@ update flags msg model =
CancelResp (Err _) -> CancelResp (Err _) ->
( model, Cmd.none ) ( model, Cmd.none )
ChangePrio id prio ->
( model, Api.setJobPrio flags id prio CancelResp )
getNewTime : Cmd Msg getNewTime : Cmd Msg
getNewTime = getNewTime =

View File

@ -143,6 +143,11 @@ dimmerSettings =
renderInfoCard : Model -> JobDetail -> Html Msg renderInfoCard : Model -> JobDetail -> Html Msg
renderInfoCard model job = renderInfoCard model job =
let
prio =
Data.Priority.fromString job.priority
|> Maybe.withDefault Data.Priority.Low
in
div div
[ classList [ classList
[ ( "ui fluid card", True ) [ ( "ui fluid card", True )
@ -195,7 +200,21 @@ renderInfoCard model job =
else else
span [ class "invisible" ] [] span [ class "invisible" ] []
, div [ class ("ui basic label " ++ jobStateColor job) ] , div [ class ("ui basic label " ++ jobStateColor job) ]
[ text "Prio" [ text "Retries"
, div [ class "detail" ]
[ job.retries |> String.fromInt |> text
]
]
, case job.state of
"waiting" ->
a
[ class ("ui basic label " ++ jobStateColor job)
, onClick (ChangePrio job.id (Data.Priority.next prio))
, href "#"
, title "Change priority of this job"
]
[ i [ class "sort numeric up icon" ] []
, text "Prio"
, div [ class "detail" ] , div [ class "detail" ]
[ code [] [ code []
[ Data.Priority.fromString job.priority [ Data.Priority.fromString job.priority
@ -205,10 +224,19 @@ renderInfoCard model job =
] ]
] ]
] ]
, div [ class ("ui basic label " ++ jobStateColor job) ]
[ text "Retries" _ ->
div
[ class ("ui basic label " ++ jobStateColor job)
]
[ text "Prio"
, div [ class "detail" ] , div [ class "detail" ]
[ job.retries |> String.fromInt |> text [ code []
[ Data.Priority.fromString job.priority
|> Maybe.map Data.Priority.toName
|> Maybe.withDefault job.priority
|> text
]
] ]
] ]
] ]