mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 01:28:45 +01:00
fix(ui): Include application name in status badge (#17126)
* Added application name to badge Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * Rever svg change Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * Doc for disabling application name Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * Flag to not display application name Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * Added tests Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * Make no app name the default Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * Have enable app name as a query parameter Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * Have enable app name as a query parameter Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * argocd to original Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> * Update docs/user-guide/status-badge.md Signed-off-by: Dan Garfield <dan@codefresh.io> Signed-off-by: Dan Garfield <dan@codefresh.io> --------- Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com> Signed-off-by: Dan Garfield <dan@codefresh.io> Co-authored-by: sshenoy6 <sonamkaup_shenoy@intuit.com> Co-authored-by: Dan Garfield <dan@codefresh.io>
This commit is contained in:
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
@@ -308,9 +308,9 @@ data:
|
||||
# have either a permanent banner or a regular closeable banner, and NOT both. eg. A user can't dismiss a
|
||||
# notification message (closeable) banner, to then immediately see a permanent banner.
|
||||
# ui.bannerpermanent: "true"
|
||||
# An option to specify the position of the banner, either the top or bottom of the page, or both. The valid values
|
||||
# are: "top", "bottom" and "both". The default (if the option is not provided), is "top". If "both" is specified, then
|
||||
# the content appears both at the top and the bottom of the page. Uncomment the following line to make the banner appear
|
||||
# An option to specify the position of the banner, either the top or bottom of the page, or both. The valid values
|
||||
# are: "top", "bottom" and "both". The default (if the option is not provided), is "top". If "both" is specified, then
|
||||
# the content appears both at the top and the bottom of the page. Uncomment the following line to make the banner appear
|
||||
# at the bottom of the page. Change the value as needed.
|
||||
# ui.bannerposition: "bottom"
|
||||
|
||||
@@ -413,4 +413,4 @@ data:
|
||||
# Mandatory if multiple services are specified.
|
||||
cluster:
|
||||
name: some-cluster
|
||||
server: https://some-cluster
|
||||
server: https://some-cluster
|
||||
@@ -9,7 +9,12 @@ To show this badge, use the following URL format `${argoCdBaseUrl}/api/badge?nam
|
||||
The URLs for status image are available on application details page:
|
||||
|
||||
1. Navigate to application details page and click on 'Details' button.
|
||||
1. Scroll down to 'Status Badge' section.
|
||||
1. Select required template such as URL, Markdown etc.
|
||||
2. Scroll down to 'Status Badge' section.
|
||||
3. Select required template such as URL, Markdown etc.
|
||||
for the status image URL in markdown, html, etc are available .
|
||||
1. Copy the text and paste it into your README or website.
|
||||
4. Copy the text and paste it into your README or website.
|
||||
|
||||
The application name may optionally be displayed in the status badge by adding the `?showAppName=true` query parameter.
|
||||
|
||||
For example, `${argoCdBaseUrl}/api/badge?name=${appName}&showAppName=true`.
|
||||
To remove the application name from the badge, remove the query parameter from the URL or set it to `false`.
|
||||
@@ -42,10 +42,28 @@ var (
|
||||
leftTextPattern = regexp.MustCompile(`id="leftText" [^>]*>([^<]*)`)
|
||||
rightTextPattern = regexp.MustCompile(`id="rightText" [^>]*>([^<]*)`)
|
||||
revisionTextPattern = regexp.MustCompile(`id="revisionText" [^>]*>([^<]*)`)
|
||||
titleTextPattern = regexp.MustCompile(`id="titleText" [^>]*>([^<]*)`)
|
||||
titleRectWidthPattern = regexp.MustCompile(`(id="titleRect" .* width=)("0")`)
|
||||
rightRectWidthPattern = regexp.MustCompile(`(id="rightRect" .* width=)("\d*")`)
|
||||
leftRectYCoodPattern = regexp.MustCompile(`(id="leftRect" .* y=)("\d*")`)
|
||||
rightRectYCoodPattern = regexp.MustCompile(`(id="rightRect" .* y=)("\d*")`)
|
||||
revisionRectYCoodPattern = regexp.MustCompile(`(id="revisionRect" .* y=)("\d*")`)
|
||||
leftTextYCoodPattern = regexp.MustCompile(`(id="leftText" .* y=)("\d*")`)
|
||||
rightTextYCoodPattern = regexp.MustCompile(`(id="rightText" .* y=)("\d*")`)
|
||||
revisionTextYCoodPattern = regexp.MustCompile(`(id="revisionText" .* y=)("\d*")`)
|
||||
svgHeightPattern = regexp.MustCompile(`^(<svg .* height=)("\d*")`)
|
||||
logoYCoodPattern = regexp.MustCompile(`(<image .* y=)("\d*")`)
|
||||
)
|
||||
|
||||
const (
|
||||
svgWidthWithRevision = 192
|
||||
svgWidthWithRevision = 192
|
||||
svgWidthWithoutRevision = 131
|
||||
svgHeightWithAppName = 40
|
||||
badgeRowHeight = 20
|
||||
statusRowYCoodWithAppName = 330
|
||||
logoYCoodWithAppName = 22
|
||||
leftRectWidth = 77
|
||||
widthPerChar = 6
|
||||
)
|
||||
|
||||
func replaceFirstGroupSubMatch(re *regexp.Regexp, str string, repl string) string {
|
||||
@@ -71,9 +89,12 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
health := healthutil.HealthStatusUnknown
|
||||
status := appv1.SyncStatusCodeUnknown
|
||||
revision := ""
|
||||
applicationName := ""
|
||||
revisionEnabled := false
|
||||
enabled := false
|
||||
displayAppName := false
|
||||
notFound := false
|
||||
svgWidth := svgWidthWithoutRevision
|
||||
if sets, err := h.settingsMgr.GetSettings(); err == nil {
|
||||
enabled = sets.StatusBadgeEnabled
|
||||
}
|
||||
@@ -100,6 +121,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if app, err := h.appClientset.ArgoprojV1alpha1().Applications(reqNs).Get(context.Background(), name[0], v1.GetOptions{}); err == nil {
|
||||
health = app.Status.Health.Status
|
||||
status = app.Status.Sync.Status
|
||||
applicationName = name[0]
|
||||
if app.Status.OperationState != nil && app.Status.OperationState.SyncResult != nil {
|
||||
revision = app.Status.OperationState.SyncResult.Revision
|
||||
}
|
||||
@@ -175,6 +197,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if !notFound && revisionEnabled && revision != "" {
|
||||
// Increase width of SVG and enable display of revision components
|
||||
badge = svgWidthPattern.ReplaceAllString(badge, fmt.Sprintf(`<svg width="%d" $2`, svgWidthWithRevision))
|
||||
svgWidth = svgWidthWithRevision
|
||||
badge = displayNonePattern.ReplaceAllString(badge, `display="inline"`)
|
||||
badge = revisionRectColorPattern.ReplaceAllString(badge, fmt.Sprintf(`id="revisionRect" fill="%s" $2`, rightColorString))
|
||||
shortRevision := revision
|
||||
@@ -184,6 +207,29 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
badge = replaceFirstGroupSubMatch(revisionTextPattern, badge, fmt.Sprintf("(%s)", shortRevision))
|
||||
}
|
||||
|
||||
if showAppNameParam, ok := r.URL.Query()["showAppName"]; ok && enabled && strings.EqualFold(showAppNameParam[0], "true") {
|
||||
displayAppName = true
|
||||
}
|
||||
|
||||
if displayAppName && applicationName != "" {
|
||||
titleRectWidth := len(applicationName) * widthPerChar
|
||||
var longerWidth int = max(titleRectWidth, svgWidth)
|
||||
rightRectWidth := longerWidth - leftRectWidth
|
||||
fmt.Println(len(applicationName))
|
||||
badge = titleRectWidthPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, longerWidth))
|
||||
badge = rightRectWidthPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, rightRectWidth))
|
||||
badge = replaceFirstGroupSubMatch(titleTextPattern, badge, applicationName)
|
||||
badge = leftRectYCoodPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, badgeRowHeight))
|
||||
badge = rightRectYCoodPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, badgeRowHeight))
|
||||
badge = revisionRectYCoodPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, badgeRowHeight))
|
||||
badge = leftTextYCoodPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, statusRowYCoodWithAppName))
|
||||
badge = rightTextYCoodPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, statusRowYCoodWithAppName))
|
||||
badge = revisionTextYCoodPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, statusRowYCoodWithAppName))
|
||||
badge = svgHeightPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, svgHeightWithAppName))
|
||||
badge = logoYCoodPattern.ReplaceAllString(badge, fmt.Sprintf(`$1"%d"`, logoYCoodWithAppName))
|
||||
badge = svgWidthPattern.ReplaceAllString(badge, fmt.Sprintf(`<svg width="%d" $2`, longerWidth))
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "image/svg+xml")
|
||||
|
||||
//Ask cache's to not cache the contents in order prevent the badge from becoming stale
|
||||
|
||||
@@ -88,6 +88,7 @@ func TestHandlerFeatureIsEnabled(t *testing.T) {
|
||||
assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.NotContains(t, response, "test-app")
|
||||
assert.NotContains(t, response, "(aa29b85)")
|
||||
}
|
||||
|
||||
@@ -148,6 +149,7 @@ func TestHandlerFeatureProjectIsEnabled(t *testing.T) {
|
||||
assert.Equal(t, toRGBString(tt.statusColor), rightRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, tt.health, leftTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, tt.status, rightTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "\"20\"", svgHeightPattern.FindStringSubmatch(response)[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,6 +172,7 @@ func TestHandlerNamespacesIsEnabled(t *testing.T) {
|
||||
assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.NotContains(t, response, "test-app")
|
||||
assert.NotContains(t, response, "(aa29b85)")
|
||||
})
|
||||
|
||||
@@ -268,6 +271,7 @@ func TestHandlerFeatureIsEnabledRevisionIsEnabled(t *testing.T) {
|
||||
assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.NotContains(t, response, "test-app")
|
||||
assert.Contains(t, response, "(aa29b85)")
|
||||
}
|
||||
|
||||
@@ -291,6 +295,7 @@ func TestHandlerRevisionIsEnabledNoOperationState(t *testing.T) {
|
||||
assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.NotContains(t, response, "test-app")
|
||||
assert.NotContains(t, response, "(aa29b85)")
|
||||
}
|
||||
|
||||
@@ -331,4 +336,59 @@ func TestHandlerFeatureIsDisabled(t *testing.T) {
|
||||
assert.Equal(t, toRGBString(Purple), rightRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Unknown", leftTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Unknown", rightTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.NotContains(t, response, "test-app")
|
||||
assert.Equal(t, "\"20\"", svgHeightPattern.FindStringSubmatch(response)[2])
|
||||
}
|
||||
|
||||
func TestHandlerApplicationNameInBadgeIsEnabled(t *testing.T) {
|
||||
settingsMgr := settings.NewSettingsManager(context.Background(), fake.NewSimpleClientset(&argoCDCm, &argoCDSecret), "default")
|
||||
handler := NewHandler(appclientset.NewSimpleClientset(&testApp), settingsMgr, "default", []string{})
|
||||
req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&showAppName=true", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control"))
|
||||
assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin"))
|
||||
|
||||
response := rr.Body.String()
|
||||
assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.NotContains(t, response, "(aa29b85)")
|
||||
|
||||
assert.Equal(t, "test-app", titleTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, fmt.Sprintf("\"%d\"", svgHeightWithAppName), svgHeightPattern.FindStringSubmatch(response)[2])
|
||||
assert.Equal(t, fmt.Sprintf("\"%d\"", badgeRowHeight), leftRectYCoodPattern.FindStringSubmatch(response)[2])
|
||||
assert.Equal(t, fmt.Sprintf("\"%d\"", badgeRowHeight), rightRectYCoodPattern.FindStringSubmatch(response)[2])
|
||||
assert.Equal(t, fmt.Sprintf("\"%d\"", badgeRowHeight), revisionRectYCoodPattern.FindStringSubmatch(response)[2])
|
||||
assert.Equal(t, fmt.Sprintf("\"%d\"", logoYCoodWithAppName), logoYCoodPattern.FindStringSubmatch(response)[2])
|
||||
}
|
||||
|
||||
func TestHandlerApplicationNameInBadgeIsDisabled(t *testing.T) {
|
||||
|
||||
settingsMgr := settings.NewSettingsManager(context.Background(), fake.NewSimpleClientset(&argoCDCm, &argoCDSecret), "default")
|
||||
handler := NewHandler(appclientset.NewSimpleClientset(&testApp), settingsMgr, "default", []string{})
|
||||
req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control"))
|
||||
assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin"))
|
||||
|
||||
response := rr.Body.String()
|
||||
assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1])
|
||||
assert.Equal(t, "\"20\"", svgHeightPattern.FindStringSubmatch(response)[2])
|
||||
assert.Equal(t, "\"0\"", leftRectYCoodPattern.FindStringSubmatch(response)[2])
|
||||
assert.Equal(t, "\"0\"", rightRectYCoodPattern.FindStringSubmatch(response)[2])
|
||||
assert.Equal(t, "\"0\"", revisionRectYCoodPattern.FindStringSubmatch(response)[2])
|
||||
assert.Equal(t, "\"2\"", logoYCoodPattern.FindStringSubmatch(response)[2])
|
||||
assert.NotContains(t, response, "test-app")
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export const BadgePanel = ({app, project, appNamespace, nsEnabled}: {app?: strin
|
||||
let entityURL = '';
|
||||
let alt = '';
|
||||
if (app) {
|
||||
badgeURL = `${root}api/badge?name=${app}&revision=true`;
|
||||
badgeURL = `${root}api/badge?name=${app}&revision=true&showAppName=true`;
|
||||
if (nsEnabled) {
|
||||
badgeURL += `&namespace=${appNamespace}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user