mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-07 07:42:45 +01:00
Split correlated and related tickets (#542)
Co-authored-by: Jonas Plum <git@jonasplum.de>
This commit is contained in:
@@ -136,7 +136,7 @@ func toTicketSimpleResponse(key string, ticket *model.Ticket) (*model.TicketSimp
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toTicketWithTickets(ticketResponse *model.TicketResponse, tickets []*model.TicketSimpleResponse, logs []*model.LogEntry) *model.TicketWithTickets {
|
func toTicketWithTickets(ticketResponse *model.TicketResponse, tickets, correlatedTickets []*model.TicketSimpleResponse, logs []*model.LogEntry) *model.TicketWithTickets {
|
||||||
return &model.TicketWithTickets{
|
return &model.TicketWithTickets{
|
||||||
Artifacts: ticketResponse.Artifacts,
|
Artifacts: ticketResponse.Artifacts,
|
||||||
Comments: ticketResponse.Comments,
|
Comments: ticketResponse.Comments,
|
||||||
@@ -155,8 +155,9 @@ func toTicketWithTickets(ticketResponse *model.TicketResponse, tickets []*model.
|
|||||||
Type: ticketResponse.Type,
|
Type: ticketResponse.Type,
|
||||||
Write: ticketResponse.Write,
|
Write: ticketResponse.Write,
|
||||||
|
|
||||||
Logs: logs,
|
Logs: logs,
|
||||||
Tickets: tickets,
|
Tickets: tickets,
|
||||||
|
CorrelatedTickets: correlatedTickets,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,7 +406,6 @@ func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query st
|
|||||||
|
|
||||||
tickets := outTickets
|
tickets := outTickets
|
||||||
tickets = append(tickets, inTickets...)
|
tickets = append(tickets, inTickets...)
|
||||||
tickets = append(tickets, sameArtifactTickets...)
|
|
||||||
sort.Slice(tickets, func(i, j int) bool {
|
sort.Slice(tickets, func(i, j int) bool {
|
||||||
return tickets[i].ID < tickets[j].ID
|
return tickets[i].ID < tickets[j].ID
|
||||||
})
|
})
|
||||||
@@ -420,7 +420,7 @@ func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query st
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return toTicketWithTickets(ticketResponse, tickets, logs), nil
|
return toTicketWithTickets(ticketResponse, tickets, sameArtifactTickets, logs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) TicketUpdate(ctx context.Context, ticketID int64, ticket *model.Ticket) (*model.TicketWithTickets, error) {
|
func (db *Database) TicketUpdate(ctx context.Context, ticketID int64, ticket *model.Ticket) (*model.TicketWithTickets, error) {
|
||||||
|
|||||||
@@ -1059,6 +1059,7 @@ definitions:
|
|||||||
modified: { type: string, format: "date-time", example: "1985-04-12T23:20:50.52Z" }
|
modified: { type: string, format: "date-time", example: "1985-04-12T23:20:50.52Z" }
|
||||||
|
|
||||||
tickets: { type: array, items: { $ref: "#/definitions/TicketSimpleResponse" } }
|
tickets: { type: array, items: { $ref: "#/definitions/TicketSimpleResponse" } }
|
||||||
|
correlated_tickets: { type: array, items: { $ref: "#/definitions/TicketSimpleResponse" } }
|
||||||
|
|
||||||
TicketList:
|
TicketList:
|
||||||
type: object
|
type: object
|
||||||
|
|||||||
@@ -6964,6 +6964,12 @@
|
|||||||
},
|
},
|
||||||
"type" : "array"
|
"type" : "array"
|
||||||
},
|
},
|
||||||
|
"correlated_tickets" : {
|
||||||
|
"items" : {
|
||||||
|
"$ref" : "#/components/schemas/TicketSimpleResponse"
|
||||||
|
},
|
||||||
|
"type" : "array"
|
||||||
|
},
|
||||||
"created" : {
|
"created" : {
|
||||||
"example" : "1985-04-12T23:20:50.52Z",
|
"example" : "1985-04-12T23:20:50.52Z",
|
||||||
"format" : "date-time",
|
"format" : "date-time",
|
||||||
|
|||||||
@@ -1172,6 +1172,10 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/definitions/Comment'
|
$ref: '#/definitions/Comment'
|
||||||
type: array
|
type: array
|
||||||
|
correlated_tickets:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/TicketSimpleResponse'
|
||||||
|
type: array
|
||||||
created:
|
created:
|
||||||
example: 1985-04-12T23:20:50.52Z
|
example: 1985-04-12T23:20:50.52Z
|
||||||
format: date-time
|
format: date-time
|
||||||
|
|||||||
@@ -6385,6 +6385,12 @@
|
|||||||
},
|
},
|
||||||
"type" : "array"
|
"type" : "array"
|
||||||
},
|
},
|
||||||
|
"correlated_tickets" : {
|
||||||
|
"items" : {
|
||||||
|
"$ref" : "#/components/schemas/TicketSimpleResponse"
|
||||||
|
},
|
||||||
|
"type" : "array"
|
||||||
|
},
|
||||||
"created" : {
|
"created" : {
|
||||||
"example" : "1985-04-12T23:20:50.52Z",
|
"example" : "1985-04-12T23:20:50.52Z",
|
||||||
"format" : "date-time",
|
"format" : "date-time",
|
||||||
|
|||||||
@@ -1053,6 +1053,10 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/definitions/Comment'
|
$ref: '#/definitions/Comment'
|
||||||
type: array
|
type: array
|
||||||
|
correlated_tickets:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/TicketSimpleResponse'
|
||||||
|
type: array
|
||||||
created:
|
created:
|
||||||
example: 1985-04-12T23:20:50.52Z
|
example: 1985-04-12T23:20:50.52Z
|
||||||
format: date-time
|
format: date-time
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ func init() {
|
|||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"name":{"type":"string"}},"required":["name","icon","default_template","default_playbooks"],"$id":"#/definitions/TicketType"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"name":{"type":"string"}},"required":["name","icon","default_template","default_playbooks"],"$id":"#/definitions/TicketType"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["name","icon","default_template","default_playbooks"],"$id":"#/definitions/TicketTypeForm"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["name","icon","default_template","default_playbooks"],"$id":"#/definitions/TicketTypeForm"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","icon","default_template","default_playbooks"],"$id":"#/definitions/TicketTypeResponse"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name","icon","default_template","default_playbooks"],"$id":"#/definitions/TicketTypeResponse"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"artifacts":{"items":{"$ref":"#/definitions/Artifact"},"type":"array"},"comments":{"items":{"$ref":"#/definitions/Comment"},"type":"array"},"created":{"format":"date-time","type":"string"},"details":{"type":"object"},"files":{"items":{"$ref":"#/definitions/File"},"type":"array"},"id":{"format":"int64","type":"integer"},"logs":{"items":{"$ref":"#/definitions/LogEntry"},"type":"array"},"modified":{"format":"date-time","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"playbooks":{"type":"object","additionalProperties":{"$ref":"#/definitions/PlaybookResponse"}},"read":{"items":{"type":"string"},"type":"array"},"references":{"items":{"$ref":"#/definitions/Reference"},"type":"array"},"schema":{"type":"string"},"status":{"type":"string"},"tickets":{"items":{"$ref":"#/definitions/TicketSimpleResponse"},"type":"array"},"type":{"type":"string"},"write":{"items":{"type":"string"},"type":"array"}},"required":["id","name","type","status","created","modified","schema"],"$id":"#/definitions/TicketWithTickets"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"artifacts":{"items":{"$ref":"#/definitions/Artifact"},"type":"array"},"comments":{"items":{"$ref":"#/definitions/Comment"},"type":"array"},"correlated_tickets":{"items":{"$ref":"#/definitions/TicketSimpleResponse"},"type":"array"},"created":{"format":"date-time","type":"string"},"details":{"type":"object"},"files":{"items":{"$ref":"#/definitions/File"},"type":"array"},"id":{"format":"int64","type":"integer"},"logs":{"items":{"$ref":"#/definitions/LogEntry"},"type":"array"},"modified":{"format":"date-time","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"playbooks":{"type":"object","additionalProperties":{"$ref":"#/definitions/PlaybookResponse"}},"read":{"items":{"type":"string"},"type":"array"},"references":{"items":{"$ref":"#/definitions/Reference"},"type":"array"},"schema":{"type":"string"},"status":{"type":"string"},"tickets":{"items":{"$ref":"#/definitions/TicketSimpleResponse"},"type":"array"},"type":{"type":"string"},"write":{"items":{"type":"string"},"type":"array"}},"required":["id","name","type","status","created","modified","schema"],"$id":"#/definitions/TicketWithTickets"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"color":{"title":"Color","type":"string","enum":["error","info","success","warning"]},"icon":{"title":"Icon (https://materialdesignicons.com)","type":"string"},"id":{"title":"ID","type":"string"},"name":{"title":"Name","type":"string"}},"required":["id","name","icon"],"$id":"#/definitions/Type"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"color":{"title":"Color","type":"string","enum":["error","info","success","warning"]},"icon":{"title":"Icon (https://materialdesignicons.com)","type":"string"},"id":{"title":"ID","type":"string"},"name":{"title":"Name","type":"string"}},"required":["id","name","icon"],"$id":"#/definitions/Type"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"roles":{"items":{"type":"string"},"type":"array"},"sha256":{"type":"string"}},"required":["blocked","apikey","roles"],"$id":"#/definitions/User"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"roles":{"items":{"type":"string"},"type":"array"},"sha256":{"type":"string"}},"required":["blocked","apikey","roles"],"$id":"#/definitions/User"}`),
|
||||||
gojsonschema.NewStringLoader(`{"type":"object","properties":{"email":{"type":"string"},"image":{"type":"string"},"name":{"type":"string"},"timeformat":{"title":"Time Format (https://moment.github.io/luxon/docs/manual/formatting.html#table-of-tokens)","type":"string"}},"$id":"#/definitions/UserData"}`),
|
gojsonschema.NewStringLoader(`{"type":"object","properties":{"email":{"type":"string"},"image":{"type":"string"},"name":{"type":"string"},"timeformat":{"title":"Time Format (https://moment.github.io/luxon/docs/manual/formatting.html#table-of-tokens)","type":"string"}},"$id":"#/definitions/UserData"}`),
|
||||||
@@ -557,24 +557,25 @@ type TicketTypeResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TicketWithTickets struct {
|
type TicketWithTickets struct {
|
||||||
Artifacts []*Artifact `json:"artifacts,omitempty"`
|
Artifacts []*Artifact `json:"artifacts,omitempty"`
|
||||||
Comments []*Comment `json:"comments,omitempty"`
|
Comments []*Comment `json:"comments,omitempty"`
|
||||||
Created time.Time `json:"created"`
|
CorrelatedTickets []*TicketSimpleResponse `json:"correlated_tickets,omitempty"`
|
||||||
Details map[string]any `json:"details,omitempty"`
|
Created time.Time `json:"created"`
|
||||||
Files []*File `json:"files,omitempty"`
|
Details map[string]any `json:"details,omitempty"`
|
||||||
ID int64 `json:"id"`
|
Files []*File `json:"files,omitempty"`
|
||||||
Logs []*LogEntry `json:"logs,omitempty"`
|
ID int64 `json:"id"`
|
||||||
Modified time.Time `json:"modified"`
|
Logs []*LogEntry `json:"logs,omitempty"`
|
||||||
Name string `json:"name"`
|
Modified time.Time `json:"modified"`
|
||||||
Owner *string `json:"owner,omitempty"`
|
Name string `json:"name"`
|
||||||
Playbooks map[string]*PlaybookResponse `json:"playbooks,omitempty"`
|
Owner *string `json:"owner,omitempty"`
|
||||||
Read []string `json:"read,omitempty"`
|
Playbooks map[string]*PlaybookResponse `json:"playbooks,omitempty"`
|
||||||
References []*Reference `json:"references,omitempty"`
|
Read []string `json:"read,omitempty"`
|
||||||
Schema string `json:"schema"`
|
References []*Reference `json:"references,omitempty"`
|
||||||
Status string `json:"status"`
|
Schema string `json:"schema"`
|
||||||
Tickets []*TicketSimpleResponse `json:"tickets,omitempty"`
|
Status string `json:"status"`
|
||||||
Type string `json:"type"`
|
Tickets []*TicketSimpleResponse `json:"tickets,omitempty"`
|
||||||
Write []string `json:"write,omitempty"`
|
Type string `json:"type"`
|
||||||
|
Write []string `json:"write,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Type struct {
|
type Type struct {
|
||||||
|
|||||||
@@ -2024,6 +2024,12 @@ export interface TicketWithTickets {
|
|||||||
* @memberof TicketWithTickets
|
* @memberof TicketWithTickets
|
||||||
*/
|
*/
|
||||||
'comments'?: Array<Comment>;
|
'comments'?: Array<Comment>;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Array<TicketSimpleResponse>}
|
||||||
|
* @memberof TicketWithTickets
|
||||||
|
*/
|
||||||
|
'correlated_tickets'?: Array<TicketSimpleResponse>;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
<template v-slot:item="{ item }">
|
<template v-slot:item="{ item }">
|
||||||
<tr @click="open(item)">
|
<tr @click="open(item)">
|
||||||
<td colspan="5" class="pa-0">
|
<td colspan="5" class="pa-0">
|
||||||
<v-list-item :to="{ name: 'Ticket', params: { type: item.type, id: item.id } }" class="pa-0" style="background: none">
|
<v-list-item class="pa-0" style="background: none">
|
||||||
<ticketSnippet :ticket="item"></ticketSnippet>
|
<ticketSnippet :ticket="item"></ticketSnippet>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -715,6 +715,19 @@
|
|||||||
"
|
"
|
||||||
></TicketSnippet>
|
></TicketSnippet>
|
||||||
</v-list>
|
</v-list>
|
||||||
|
<div
|
||||||
|
v-if="ticket.correlated_tickets && ticket.correlated_tickets.length"
|
||||||
|
style="display: flex; align-items: center" class="py-1" >
|
||||||
|
<span class="text--disabled">Correlated Tickets</span>
|
||||||
|
</div>
|
||||||
|
<v-list dense v-if="ticket.correlated_tickets && ticket.correlated_tickets.length">
|
||||||
|
<TicketSnippet
|
||||||
|
v-for="relatedTicket in ticket.correlated_tickets"
|
||||||
|
:key="relatedTicket.id"
|
||||||
|
:to="{ name: 'Ticket', params: { id: relatedTicket.id } }"
|
||||||
|
:ticket="relatedTicket"
|
||||||
|
></TicketSnippet>
|
||||||
|
</v-list>
|
||||||
<v-dialog v-model="relatedDialog" max-width="800px">
|
<v-dialog v-model="relatedDialog" max-width="800px">
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>
|
<v-card-title>
|
||||||
|
|||||||
Reference in New Issue
Block a user