Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(904)

Side by Side Diff: scheduler/appengine/ui/presentation.go

Issue 2945843002: scheduler WIP: add GetAllJobs api. (Closed)
Patch Set: update test Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package ui 5 package ui
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "sort" 10 "sort"
11 "strings" 11 "strings"
12 "time" 12 "time"
13 13
14 "github.com/dustin/go-humanize" 14 "github.com/dustin/go-humanize"
15 "github.com/golang/protobuf/proto" 15 "github.com/golang/protobuf/proto"
16 "golang.org/x/net/context" 16 "golang.org/x/net/context"
17 17
18 "github.com/luci/luci-go/common/clock" 18 "github.com/luci/luci-go/common/clock"
19 "github.com/luci/luci-go/common/logging" 19 "github.com/luci/luci-go/common/logging"
20 20
21 "github.com/luci/luci-go/common/data/sortby" 21 "github.com/luci/luci-go/common/data/sortby"
22 "github.com/luci/luci-go/scheduler/appengine/catalog" 22 "github.com/luci/luci-go/scheduler/appengine/catalog"
23 "github.com/luci/luci-go/scheduler/appengine/engine" 23 "github.com/luci/luci-go/scheduler/appengine/engine"
24 "github.com/luci/luci-go/scheduler/appengine/messages" 24 "github.com/luci/luci-go/scheduler/appengine/messages"
25 "github.com/luci/luci-go/scheduler/appengine/presentation"
25 "github.com/luci/luci-go/scheduler/appengine/schedule" 26 "github.com/luci/luci-go/scheduler/appengine/schedule"
26 "github.com/luci/luci-go/scheduler/appengine/task" 27 "github.com/luci/luci-go/scheduler/appengine/task"
27 ) 28 )
28 29
29 // schedulerJob is UI representation of engine.Job entity. 30 // schedulerJob is UI representation of engine.Job entity.
30 type schedulerJob struct { 31 type schedulerJob struct {
31 ProjectID string 32 ProjectID string
32 JobID string 33 JobID string
33 Schedule string 34 Schedule string
34 Definition string 35 Definition string
35 Revision string 36 Revision string
36 RevisionURL string 37 RevisionURL string
37 State string 38 State string
38 Overruns int 39 Overruns int
39 NextRun string 40 NextRun string
40 Paused bool 41 Paused bool
41 LabelClass string 42 LabelClass string
42 JobFlavorIcon string 43 JobFlavorIcon string
43 JobFlavorTitle string 44 JobFlavorTitle string
44 45
45 sortGroup string // used only for sorting, doesn't show up in UI 46 sortGroup string // used only for sorting, doesn't show up in UI
46 now time.Time // as passed to makeJob 47 now time.Time // as passed to makeJob
47 traits task.Traits // as extracted from corresponding task.Manager 48 traits task.Traits // as extracted from corresponding task.Manager
48 } 49 }
49 50
50 var stateToLabelClass = map[engine.StateKind]string{ 51 var stateToLabelClass = map[presentation.PublicStateKind]string{
51 » engine.JobStateDisabled: "label-default", 52 » presentation.PublicStateRetrying: "label-danger",
52 » engine.JobStateScheduled: "label-primary", 53 » presentation.PublicStatePaused: "label-default",
53 » engine.JobStateSuspended: "label-default", 54 » presentation.PublicStateScheduled: "label-primary",
54 » engine.JobStateRunning: "label-info", 55 » presentation.PublicStateSuspended: "label-default",
55 » engine.JobStateOverrun: "label-warning", 56 » presentation.PublicStateRunning: "label-info",
57 » presentation.PublicStateOverrun: "label-warning",
58 » presentation.PublicStateWaiting: "label-warning",
59 » presentation.PublicStateStarting: "label-default",
56 } 60 }
57 61
58 var flavorToIconClass = []string{ 62 var flavorToIconClass = []string{
59 catalog.JobFlavorPeriodic: "glyphicon-time", 63 catalog.JobFlavorPeriodic: "glyphicon-time",
60 catalog.JobFlavorTriggered: "glyphicon-flash", 64 catalog.JobFlavorTriggered: "glyphicon-flash",
61 catalog.JobFlavorTrigger: "glyphicon-bell", 65 catalog.JobFlavorTrigger: "glyphicon-bell",
62 } 66 }
63 67
64 var flavorToTitle = []string{ 68 var flavorToTitle = []string{
65 catalog.JobFlavorPeriodic: "Periodic job", 69 catalog.JobFlavorPeriodic: "Periodic job",
(...skipping 23 matching lines...) Expand all
89 switch ts := j.State.TickTime; { 93 switch ts := j.State.TickTime; {
90 case ts == schedule.DistantFuture: 94 case ts == schedule.DistantFuture:
91 nextRun = "-" 95 nextRun = "-"
92 case !ts.IsZero(): 96 case !ts.IsZero():
93 nextRun = humanize.RelTime(ts, now, "ago", "from now") 97 nextRun = humanize.RelTime(ts, now, "ago", "from now")
94 default: 98 default:
95 nextRun = "not scheduled yet" 99 nextRun = "not scheduled yet"
96 } 100 }
97 101
98 // Internal state names aren't very user friendly. Introduce some aliase s. 102 // Internal state names aren't very user friendly. Introduce some aliase s.
99 » state := "" 103 » state := presentation.GetPublicStateKind(j, traits)
100 » labelClass := "" 104 » labelClass := stateToLabelClass[state]
101 » switch { 105 » if j.State.State == engine.JobStateSlowQueue {
102 » case j.State.IsRetrying():
103 » » // Retries happen when invocation fails to launch (move from "ST ARTING" to
104 » » // "RUNNING" state). Such invocation is retried (as new invocati on). When
105 » » // a retry is enqueued, we display the job state as "RETRYING" ( even though
106 » » // technically it is still "QUEUED").
107 » » state = "RETRYING"
108 » » labelClass = "label-danger"
109 » case !traits.Multistage && j.State.InvocationID != 0:
110 » » // The job has an active invocation and the engine has called La unchTask for
111 » » // it already. Jobs with Multistage == false trait do all their work in
112 » » // LaunchTask, so we display them as "RUNNING" (instead of "STAR TING").
113 » » state = "RUNNING"
114 » » labelClass = "label-info"
115 » case j.State.State == engine.JobStateQueued:
116 » » // An invocation has been added to the task queue, and the engin e hasn't
117 » » // attempted to launch it yet.
118 » » state = "STARTING"
119 » » labelClass = "label-default"
120 » case j.State.State == engine.JobStateSlowQueue:
121 // Job invocation is still in the task queue, but new invocation should be 106 // Job invocation is still in the task queue, but new invocation should be
122 // starting now (so the queue is lagging for some reason). 107 // starting now (so the queue is lagging for some reason).
123 state = "STARTING"
124 labelClass = "label-warning" 108 labelClass = "label-warning"
125 case j.Paused && j.State.State == engine.JobStateSuspended:
126 // Paused jobs don't have a schedule, so they are always in "SUS PENDED"
127 // state. Make it clearer that they are just paused. This applie s to both
128 // triggered and periodic jobs.
129 state = "PAUSED"
130 labelClass = "label-default"
131 case j.State.State == engine.JobStateSuspended && j.Flavor == catalog.Jo bFlavorTriggered:
132 // Triggered jobs don't run on a schedule. They are in "SUSPENDE D" state
133 // between triggering events, rename it to "WAITING" for clarity .
134 state = "WAITING"
135 labelClass = "label-default"
136 default:
137 state = string(j.State.State)
138 labelClass = stateToLabelClass[j.State.State]
139 } 109 }
140
141 // Put triggers after regular jobs. 110 // Put triggers after regular jobs.
142 sortGroup := "A" 111 sortGroup := "A"
143 if j.Flavor == catalog.JobFlavorTrigger { 112 if j.Flavor == catalog.JobFlavorTrigger {
144 sortGroup = "B" 113 sortGroup = "B"
145 } 114 }
146 115
147 // JobID has form <project>/<id>. Split it into components. 116 // JobID has form <project>/<id>. Split it into components.
148 chunks := strings.Split(j.JobID, "/") 117 chunks := strings.Split(j.JobID, "/")
149 118
150 return &schedulerJob{ 119 return &schedulerJob{
151 ProjectID: chunks[0], 120 ProjectID: chunks[0],
152 JobID: chunks[1], 121 JobID: chunks[1],
153 Schedule: j.Schedule, 122 Schedule: j.Schedule,
154 Definition: taskToText(j.Task), 123 Definition: taskToText(j.Task),
155 Revision: j.Revision, 124 Revision: j.Revision,
156 RevisionURL: j.RevisionURL, 125 RevisionURL: j.RevisionURL,
157 » » State: state, 126 » » State: string(state),
158 Overruns: j.State.Overruns, 127 Overruns: j.State.Overruns,
159 NextRun: nextRun, 128 NextRun: nextRun,
160 Paused: j.Paused, 129 Paused: j.Paused,
161 LabelClass: labelClass, 130 LabelClass: labelClass,
162 JobFlavorIcon: flavorToIconClass[j.Flavor], 131 JobFlavorIcon: flavorToIconClass[j.Flavor],
163 JobFlavorTitle: flavorToTitle[j.Flavor], 132 JobFlavorTitle: flavorToTitle[j.Flavor],
164 133
165 sortGroup: sortGroup, 134 sortGroup: sortGroup,
166 now: now, 135 now: now,
167 traits: traits, 136 traits: traits,
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 TriggeredBy: triggeredBy, 251 TriggeredBy: triggeredBy,
283 Started: humanize.RelTime(i.Started, j.now, "ago", "from now "), 252 Started: humanize.RelTime(i.Started, j.now, "ago", "from now "),
284 Duration: duration, 253 Duration: duration,
285 Status: string(status), 254 Status: string(status),
286 DebugLog: i.DebugLog, 255 DebugLog: i.DebugLog,
287 RowClass: statusToRowClass[status], 256 RowClass: statusToRowClass[status],
288 LabelClass: statusToLabelClass[status], 257 LabelClass: statusToLabelClass[status],
289 ViewURL: i.ViewURL, 258 ViewURL: i.ViewURL,
290 } 259 }
291 } 260 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698