Skip to content

Commit

Permalink
Support github issue forms for "Ticket" feature (#1775)
Browse files Browse the repository at this point in the history
* support github issue forms

* add comments

* PR feedback
  • Loading branch information
petersutter authored Apr 4, 2024
1 parent 9ad2286 commit 98975ca
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -626,10 +626,12 @@ Object {
"ignore1",
"ignore2",
],
"issueDescriptionTemplate": "issue description",
"newTicketLabels": Array [
"default-label",
],
"newIssue": Object {
"body": "issue description",
"labels": Array [
"default-label",
],
},
},
},
"gitHub": Object {
Expand Down Expand Up @@ -664,10 +666,12 @@ Object {
"ignore1",
"ignore2",
],
"issueDescriptionTemplate": "issue description",
"newTicketLabels": Array [
"default-label",
],
"newIssue": Object {
"body": "issue description",
"labels": Array [
"default-label",
],
},
},
},
"gitHub": Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,10 @@ describe('gardener-dashboard', function () {
avatarSource: 'gravatar',
gitHubRepoUrl: 'https://github.com/gardener/tickets',
hideClustersWithLabels: ['ignore1', 'ignore2'],
newTicketLabels: ['default-label'],
issueDescriptionTemplate: 'issue description'
newIssue: {
labels: ['default-label'],
body: 'issue description'
}
}
},
gitHub: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,11 @@ data:
- {{ . }}
{{- end }}
{{- end }}
{{- if .Values.global.dashboard.frontendConfig.ticket.newTicketLabels }}
newTicketLabels:
{{- range .Values.global.dashboard.frontendConfig.ticket.newTicketLabels }}
- {{ . }}
{{- end }}
{{- end }}
gitHubRepoUrl: {{ .Values.global.dashboard.frontendConfig.ticket.gitHubRepoUrl }}
avatarSource: {{ .Values.global.dashboard.frontendConfig.ticket.avatarSource | default "github" }}
issueDescriptionTemplate: {{ quote .Values.global.dashboard.frontendConfig.ticket.issueDescriptionTemplate }}
{{- if .Values.global.dashboard.frontendConfig.ticket.newIssue }}
newIssue: {{ toYaml .Values.global.dashboard.frontendConfig.ticket.newIssue | trim | nindent 10 }}
{{- end }}
{{- end }}
features:
terminalEnabled: {{ .Values.global.dashboard.frontendConfig.features.terminalEnabled | default false }}
Expand Down
57 changes: 31 additions & 26 deletions charts/gardener-dashboard/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,8 @@ global:
# gitHubRepoUrl: https://foo-github.aaakk.us.kg/dummyorg/dummyrepo
# hideClustersWithLabels: # hides clusters with labels on the 'ALL PROJECTS' page if the respective table option is enabled
# - ignore
# newTicketLabels: # these are the labels that are automatically preselected when creating a new ticket
# - default-label
# # Available issue description template variables:

# # Available template variables:
# # - `${shootName}`: name of the shoot
# # - `${shootNamespace}`: namespace of the shoot
# # - `${shootCreatedAt}`: creation timestamp of the shoot, format 'YYYY-MM-DD'
Expand All @@ -198,29 +197,35 @@ global:
# # accessRestrictions[].options[].title: option title
# # accessRestrictions[].options[].description: option description
# # accessRestrictions[].options[].key: unique identifier
# issueDescriptionTemplate: |
# ## Which cluster is affected?

# `Cluster Details Dashboard Link`: [${projectName}/${shootName}](${shootUrl})
# `Operating System`: ${machineImageNames}
# `Platform`: ${providerType}
# <% if(accessRestrictions.length) { %>
# ## Attention: This cluster has access restrictions
# <% accessRestrictions.forEach(accessRestriction => { %>
# - <%- accessRestriction.title %><% accessRestriction.options.forEach(option => { %>
# - <%- option.title %><% }) }) %>
# <%
# }%>
# ## What happened?

# ## What you expected to happen?

# ## When did it happen or started to happen?
# `Timestamp`: ${utcDateTimeNow}

# ## How would we reproduce it?

# ## Anything else we need to know?
# newIssue:
# title: "[${shootNamespace}/${shootName}] <problem>"
# labels: # these are the labels that are automatically preselected when creating a new ticket
# - default-label
# # GitHub issue forms
# fileName: shoot_issue.yaml
# affectedCluster: "${shootUrl}" # example template form element id
# # Regular GitHub issue
# body: | # do not set `body`, if you use GitHub issue forms
# ## Which cluster is affected?

# `Cluster Details Dashboard Link`: [${projectName}/${shootName}](${shootUrl})
# `Operating System`: ${machineImageNames}
# `Platform`: ${providerType}
# <% if(accessRestrictions.length) { %>
# ## Attention: This cluster has access restrictions
# <% accessRestrictions.forEach(accessRestriction => { %>- ${accessRestriction.title}<% accessRestriction.options.forEach(option => { %>
# - ${option.title}<% }) }) %>
# <% } %>
# ## What happened?

# ## What you expected to happen?

# ## When did it happen or started to happen?
# `Timestamp`: ${utcDateTimeNow}

# ## How would we reproduce it?

# ## Anything else we need to know?
defaultHibernationSchedule:
evaluation:
- start: 00 17 * * 1,2,3,4,5
Expand Down
75 changes: 47 additions & 28 deletions frontend/src/components/GTicketsCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ SPDX-License-Identifier: Apache-2.0
<v-btn
variant="tonal"
color="primary"
:href="sanitizeUrl(createTicketLink)"
:href="sanitizeUrl(ticketLink)"
target="_blank"
rel="noopener"
title="Create Ticket"
Expand All @@ -35,7 +35,7 @@ SPDX-License-Identifier: Apache-2.0
<v-btn
variant="tonal"
color="primary"
:href="sanitizeUrl(createTicketLink)"
:href="sanitizeUrl(ticketLink)"
target="_blank"
rel="noopener"
title="Create Ticket"
Expand Down Expand Up @@ -64,7 +64,6 @@ import moment from '@/utils/moment'

import {
get,
join,
map,
template,
uniq,
Expand All @@ -86,16 +85,29 @@ export default {
name: this.shootName,
})
},
newIssue () {
return get(this.ticketConfig, 'newIssue', {})
},
gitHubRepoUrl () {
return get(this.ticketConfig, 'gitHubRepoUrl')
},
newTicketLabels () {
return get(this.ticketConfig, 'newTicketLabels')
shootUrl () {
const url = new URL(`/namespace/${this.shootNamespace}/shoots/${this.shootName}`, window.location)
return url.toString()
},
issueDescription () {
const descriptionTemplate = get(this.ticketConfig, 'issueDescriptionTemplate')
const compiled = template(descriptionTemplate)
return compiled({
shootMachineImageNames () {
const workers = get(this.shootItem, 'spec.provider.workers')
let imageNames = map(workers, worker => get(worker, 'machine.image.name'))
imageNames = uniq(imageNames)
return imageNames.join(', ')
},
ticketLink () {
const newIssue = this.newIssue
if (!newIssue.title) {
newIssue.title = `[${this.shootNamespace}/${this.shootName}]`
}

const options = {
shootName: this.shootName,
shootNamespace: this.shootNamespace,
shootCreatedAt: this.shootCreatedAt,
Expand All @@ -107,32 +119,39 @@ export default {
utcDateTimeNow: moment().utc().format(),
seedName: this.shootSeedName,
accessRestrictions: this.shootSelectedAccessRestrictions,
})
},
shootUrl () {
return `${window.location.origin}/namespace/${this.shootNamespace}/shoots/${this.shootName}`
},
shootMachineImageNames () {
const workers = get(this.shootItem, 'spec.provider.workers')
let imageNames = map(workers, worker => get(worker, 'machine.image.name'))
imageNames = uniq(imageNames)
return imageNames.join(', ')
},
newTicketLabelsString () {
return join(this.newTicketLabels, ',')
},
createTicketLink () {
const ticketTitle = encodeURIComponent(`[${this.shootProjectName}/${this.shootName}]`)
const body = encodeURIComponent(this.issueDescription)
const newTicketLabels = encodeURIComponent(this.newTicketLabelsString)
}

return `${this.gitHubRepoUrl}/issues/new?title=${ticketTitle}&body=${body}&labels=${newTicketLabels}`
const baseUrl = new URL(this.gitHubRepoUrl)
if (!baseUrl.pathname.endsWith('/')) {
baseUrl.pathname += '/'
}
const url = new URL('issues/new', baseUrl)
for (const [key, value] of Object.entries(newIssue)) {
if (typeof value === 'string') {
const templatedValue = this.applyTemplate(value, options)
url.searchParams.append(key, templatedValue)
} else if (Array.isArray(value)) {
const templatedValues = value.map(v => {
return this.applyTemplate(v, options)
})
url.searchParams.append(key, templatedValues)
}
}
return url.toString()
},
},
methods: {
...mapActions(useTicketStore, {
ticketsByProjectAndName: 'issues',
}),
applyTemplate (value, options) {
if (!value) {
return ''
}

const compiled = template(value)
return compiled(options)
},
},
}
</script>
Expand Down

0 comments on commit 98975ca

Please sign in to comment.