[ui] Adds meta to job list stub and displays a pack logo on the jobs index (#14833)
* Adds meta to job list stub and displays a pack logo on the jobs index * Changelog * Modifying struct for optional meta param * Explicitly ask for meta anytime I look up a job from index or job page * Test case for the endpoint * adding meta field to API struct and ommitting from response if empty * passthru method added to api/jobs.list * Meta param listed in docs for jobs list * Update api/jobs.go Co-authored-by: Tim Gross <tgross@hashicorp.com> Co-authored-by: Tim Gross <tgross@hashicorp.com>
This commit is contained in:
parent
6d5fe56fa1
commit
ffb4c63af7
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
ui: Adds a "Pack" tag and logo on the jobs list index when appropriate
|
||||
```
|
24
api/jobs.go
24
api/jobs.go
|
@ -155,10 +155,31 @@ func (j *Jobs) RegisterOpts(job *Job, opts *RegisterOptions, q *WriteOptions) (*
|
|||
return &resp, wm, nil
|
||||
}
|
||||
|
||||
type JobListFields struct {
|
||||
Meta bool
|
||||
}
|
||||
type JobListOptions struct {
|
||||
Fields *JobListFields
|
||||
}
|
||||
|
||||
// List is used to list all of the existing jobs.
|
||||
func (j *Jobs) List(q *QueryOptions) ([]*JobListStub, *QueryMeta, error) {
|
||||
return j.ListOptions(nil, q)
|
||||
}
|
||||
|
||||
// List is used to list all of the existing jobs.
|
||||
func (j *Jobs) ListOptions(opts *JobListOptions, q *QueryOptions) ([]*JobListStub, *QueryMeta, error) {
|
||||
var resp []*JobListStub
|
||||
qm, err := j.client.query("/v1/jobs", &resp, q)
|
||||
|
||||
destinationURL := "/v1/jobs"
|
||||
|
||||
if opts != nil && opts.Fields != nil {
|
||||
qp := url.Values{}
|
||||
qp.Add("meta", fmt.Sprint(opts.Fields.Meta))
|
||||
destinationURL = destinationURL + "?" + qp.Encode()
|
||||
}
|
||||
|
||||
qm, err := j.client.query(destinationURL, &resp, q)
|
||||
if err != nil {
|
||||
return nil, qm, err
|
||||
}
|
||||
|
@ -1063,6 +1084,7 @@ type JobListStub struct {
|
|||
ModifyIndex uint64
|
||||
JobModifyIndex uint64
|
||||
SubmitTime int64
|
||||
Meta map[string]string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// JobIDSort is used to sort jobs by their job ID's.
|
||||
|
|
|
@ -37,6 +37,16 @@ func (s *HTTPServer) jobListRequest(resp http.ResponseWriter, req *http.Request)
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
args.Fields = &structs.JobStubFields{}
|
||||
// Parse meta query param
|
||||
jobMeta, err := parseBool(req, "meta")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if jobMeta != nil {
|
||||
args.Fields.Meta = *jobMeta
|
||||
}
|
||||
|
||||
var out structs.JobListResponse
|
||||
if err := s.agent.RPC("Job.List", &args, &out); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -128,7 +128,7 @@ func (c *JobStatusCommand) Run(args []string) int {
|
|||
|
||||
// Invoke list mode if no job ID.
|
||||
if len(args) == 0 {
|
||||
jobs, _, err := client.Jobs().List(nil)
|
||||
jobs, _, err := client.Jobs().ListOptions(nil, nil)
|
||||
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error querying jobs: %s", err))
|
||||
|
|
|
@ -1377,7 +1377,7 @@ func (j *Job) List(args *structs.JobListRequest, reply *structs.JobListResponse)
|
|||
if err != nil || summary == nil {
|
||||
return fmt.Errorf("unable to look up summary for job: %v", job.ID)
|
||||
}
|
||||
jobs = append(jobs, job.Stub(summary))
|
||||
jobs = append(jobs, job.Stub(summary, args.Fields))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -5113,6 +5113,7 @@ func TestJobEndpoint_ListJobs(t *testing.T) {
|
|||
require.Len(t, resp2.Jobs, 1)
|
||||
require.Equal(t, job.ID, resp2.Jobs[0].ID)
|
||||
require.Equal(t, job.Namespace, resp2.Jobs[0].Namespace)
|
||||
require.Nil(t, resp2.Jobs[0].Meta)
|
||||
|
||||
// Lookup the jobs by prefix
|
||||
get = &structs.JobListRequest{
|
||||
|
@ -5129,6 +5130,22 @@ func TestJobEndpoint_ListJobs(t *testing.T) {
|
|||
require.Len(t, resp3.Jobs, 1)
|
||||
require.Equal(t, job.ID, resp3.Jobs[0].ID)
|
||||
require.Equal(t, job.Namespace, resp3.Jobs[0].Namespace)
|
||||
|
||||
// Lookup jobs with a meta parameter
|
||||
get = &structs.JobListRequest{
|
||||
QueryOptions: structs.QueryOptions{
|
||||
Region: "global",
|
||||
Namespace: job.Namespace,
|
||||
Prefix: resp2.Jobs[0].ID[:4],
|
||||
},
|
||||
Fields: &structs.JobStubFields{
|
||||
Meta: true,
|
||||
},
|
||||
}
|
||||
var resp4 structs.JobListResponse
|
||||
err = msgpackrpc.CallWithCodec(codec, "Job.List", get, &resp4)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, job.Meta["owner"], resp4.Jobs[0].Meta["owner"])
|
||||
}
|
||||
|
||||
// TestJobEndpoint_ListJobs_AllNamespaces_OSS asserts that server
|
||||
|
|
|
@ -689,6 +689,12 @@ type JobSpecificRequest struct {
|
|||
// JobListRequest is used to parameterize a list request
|
||||
type JobListRequest struct {
|
||||
QueryOptions
|
||||
Fields *JobStubFields
|
||||
}
|
||||
|
||||
// Stub returns a summarized version of the job
|
||||
type JobStubFields struct {
|
||||
Meta bool
|
||||
}
|
||||
|
||||
// JobPlanRequest is used for the Job.Plan endpoint to trigger a dry-run
|
||||
|
@ -4517,8 +4523,8 @@ func (j *Job) HasUpdateStrategy() bool {
|
|||
}
|
||||
|
||||
// Stub is used to return a summary of the job
|
||||
func (j *Job) Stub(summary *JobSummary) *JobListStub {
|
||||
return &JobListStub{
|
||||
func (j *Job) Stub(summary *JobSummary, fields *JobStubFields) *JobListStub {
|
||||
jobStub := &JobListStub{
|
||||
ID: j.ID,
|
||||
Namespace: j.Namespace,
|
||||
ParentID: j.ParentID,
|
||||
|
@ -4538,6 +4544,14 @@ func (j *Job) Stub(summary *JobSummary) *JobListStub {
|
|||
SubmitTime: j.SubmitTime,
|
||||
JobSummary: summary,
|
||||
}
|
||||
|
||||
if fields != nil {
|
||||
if fields.Meta {
|
||||
jobStub.Meta = j.Meta
|
||||
}
|
||||
}
|
||||
|
||||
return jobStub
|
||||
}
|
||||
|
||||
// IsPeriodic returns whether a job is periodic.
|
||||
|
@ -4721,6 +4735,7 @@ type JobListStub struct {
|
|||
ModifyIndex uint64
|
||||
JobModifyIndex uint64
|
||||
SubmitTime int64
|
||||
Meta map[string]string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// JobSummary summarizes the state of the allocations of a job
|
||||
|
|
|
@ -22,7 +22,7 @@ export default class IndexRoute extends Route.extend(
|
|||
model(params) {
|
||||
return RSVP.hash({
|
||||
jobs: this.store
|
||||
.query('job', { namespace: params.qpNamespace })
|
||||
.query('job', { namespace: params.qpNamespace, meta: true })
|
||||
.catch(notifyForbidden(this)),
|
||||
namespaces: this.store.findAll('namespace'),
|
||||
});
|
||||
|
@ -32,7 +32,7 @@ export default class IndexRoute extends Route.extend(
|
|||
controller.set('namespacesWatch', this.watchNamespaces.perform());
|
||||
controller.set(
|
||||
'modelWatch',
|
||||
this.watchJobs.perform({ namespace: controller.qpNamesapce })
|
||||
this.watchJobs.perform({ namespace: controller.qpNamespace, meta: true })
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ export default class JobRoute extends Route {
|
|||
const relatedModelsQueries = [
|
||||
job.get('allocations'),
|
||||
job.get('evaluations'),
|
||||
this.store.query('job', { namespace }),
|
||||
this.store.query('job', { namespace, meta: true }),
|
||||
this.store.findAll('namespace'),
|
||||
];
|
||||
|
||||
|
|
|
@ -31,7 +31,10 @@ export default class IndexRoute extends Route.extend(WithWatchers) {
|
|||
this.watchLatestDeployment.perform(model),
|
||||
list:
|
||||
model.get('hasChildren') &&
|
||||
this.watchAllJobs.perform({ namespace: model.namespace.get('name') }),
|
||||
this.watchAllJobs.perform({
|
||||
namespace: model.namespace.get('name'),
|
||||
meta: true,
|
||||
}),
|
||||
nodes:
|
||||
model.get('hasClientStatus') &&
|
||||
this.can.can('read client') &&
|
||||
|
|
|
@ -68,6 +68,11 @@
|
|||
vertical-align: 2px;
|
||||
}
|
||||
|
||||
&.is-pack {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
|
|
|
@ -10,6 +10,14 @@
|
|||
class="is-primary"
|
||||
>
|
||||
{{this.job.name}}
|
||||
|
||||
{{#if this.job.meta.structured.pack}}
|
||||
<span data-test-pack-tag class="tag is-pack">
|
||||
{{x-icon "box" class= "test"}}
|
||||
<span>Pack</span>
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
</LinkTo>
|
||||
</td>
|
||||
{{#if this.system.shouldShowNamespaces}}
|
||||
|
|
|
@ -46,6 +46,8 @@ The table below shows this endpoint's support for
|
|||
- `namespace` `(string: "default")` - Specifies the target namespace. Specifying
|
||||
`*` would return all jobs across all the authorized namespaces.
|
||||
|
||||
- `meta` `(bool: false)` - If set, jobs returned will include a [meta](/docs/job-specification/meta) field containing all
|
||||
|
||||
### Sample Request
|
||||
|
||||
```shell-session
|
||||
|
|
Loading…
Reference in New Issue