mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: Enable custom support links (#6313)
* backend: support links * frontend: Support links * fmt * test: CODER_SUPPORT_LINKS_0_NAME * Go tests * Use UpdateAppearanceConfig * ui: UpdateAppearanceConfig * fix: fmt * Fix: site * Fix: site tests * fix: fmt * fix * test: check default support links
This commit is contained in:
@@ -15,6 +15,24 @@ import (
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
var DefaultSupportLinks = []codersdk.LinkConfig{
|
||||
{
|
||||
Name: "Documentation",
|
||||
Target: "https://coder.com/docs/coder-oss",
|
||||
Icon: "docs",
|
||||
},
|
||||
{
|
||||
Name: "Report a bug",
|
||||
Target: "https://github.com/coder/coder/issues/new?labels=needs+grooming&body={CODER_BUILD_INFO}",
|
||||
Icon: "bug",
|
||||
},
|
||||
{
|
||||
Name: "Join the Coder Discord",
|
||||
Target: "https://coder.com/chat?utm_source=coder&utm_medium=coder&utm_campaign=server-footer",
|
||||
Icon: "chat",
|
||||
},
|
||||
}
|
||||
|
||||
// @Summary Get appearance
|
||||
// @ID get-appearance
|
||||
// @Security CoderSessionToken
|
||||
@@ -30,7 +48,9 @@ func (api *API) appearance(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
if !isEntitled {
|
||||
httpapi.Write(ctx, rw, http.StatusOK, codersdk.AppearanceConfig{})
|
||||
httpapi.Write(ctx, rw, http.StatusOK, codersdk.AppearanceConfig{
|
||||
SupportLinks: DefaultSupportLinks,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -67,6 +87,12 @@ func (api *API) appearance(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if len(api.DeploymentConfig.Support.Links.Value) == 0 {
|
||||
cfg.SupportLinks = DefaultSupportLinks
|
||||
} else {
|
||||
cfg.SupportLinks = api.DeploymentConfig.Support.Links.Value
|
||||
}
|
||||
|
||||
httpapi.Write(r.Context(), rw, http.StatusOK, cfg)
|
||||
}
|
||||
|
||||
@@ -87,8 +113,8 @@ func validateHexColor(color string) error {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param request body codersdk.AppearanceConfig true "Update appearance request"
|
||||
// @Success 200 {object} codersdk.AppearanceConfig
|
||||
// @Param request body codersdk.UpdateAppearanceConfig true "Update appearance request"
|
||||
// @Success 200 {object} codersdk.UpdateAppearanceConfig
|
||||
// @Router /appearance [put]
|
||||
func (api *API) putAppearance(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
@@ -100,7 +126,7 @@ func (api *API) putAppearance(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var appearance codersdk.AppearanceConfig
|
||||
var appearance codersdk.UpdateAppearanceConfig
|
||||
if !httpapi.Read(ctx, rw, r, &appearance) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/codersdk"
|
||||
"github.com/coder/coder/enterprise/coderd"
|
||||
"github.com/coder/coder/enterprise/coderd/coderdenttest"
|
||||
"github.com/coder/coder/enterprise/coderd/license"
|
||||
"github.com/coder/coder/testutil"
|
||||
@@ -43,16 +44,20 @@ func TestServiceBanners(t *testing.T) {
|
||||
|
||||
basicUserClient, _ := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID)
|
||||
|
||||
uac := codersdk.UpdateAppearanceConfig{
|
||||
ServiceBanner: sb.ServiceBanner,
|
||||
}
|
||||
// Regular user should be unable to set the banner
|
||||
sb.ServiceBanner.Enabled = true
|
||||
err = basicUserClient.UpdateAppearance(ctx, sb)
|
||||
uac.ServiceBanner.Enabled = true
|
||||
|
||||
err = basicUserClient.UpdateAppearance(ctx, uac)
|
||||
require.Error(t, err)
|
||||
var sdkError *codersdk.Error
|
||||
require.True(t, errors.As(err, &sdkError))
|
||||
require.Equal(t, http.StatusForbidden, sdkError.StatusCode())
|
||||
|
||||
// But an admin can
|
||||
wantBanner := sb
|
||||
wantBanner := uac
|
||||
wantBanner.ServiceBanner.Enabled = true
|
||||
wantBanner.ServiceBanner.Message = "Hey"
|
||||
wantBanner.ServiceBanner.BackgroundColor = "#00FF00"
|
||||
@@ -60,10 +65,67 @@ func TestServiceBanners(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
gotBanner, err := adminClient.Appearance(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantBanner, gotBanner)
|
||||
gotBanner.SupportLinks = nil // clean "support links" before comparison
|
||||
require.Equal(t, wantBanner.ServiceBanner, gotBanner.ServiceBanner)
|
||||
|
||||
// But even an admin can't give a bad color
|
||||
wantBanner.ServiceBanner.BackgroundColor = "#bad color"
|
||||
err = adminClient.UpdateAppearance(ctx, wantBanner)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCustomSupportLinks(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
supportLinks := []codersdk.LinkConfig{
|
||||
{
|
||||
Name: "First link",
|
||||
Target: "http://first-link-1",
|
||||
Icon: "chat",
|
||||
},
|
||||
{
|
||||
Name: "Second link",
|
||||
Target: "http://second-link-2",
|
||||
Icon: "bug",
|
||||
},
|
||||
}
|
||||
cfg := coderdtest.DeploymentConfig(t)
|
||||
cfg.Support = new(codersdk.SupportConfig)
|
||||
cfg.Support.Links = &codersdk.DeploymentConfigField[[]codersdk.LinkConfig]{
|
||||
Value: supportLinks,
|
||||
}
|
||||
|
||||
client := coderdenttest.New(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentConfig: cfg,
|
||||
},
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
coderdenttest.AddLicense(t, client, coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureAppearance: 1,
|
||||
},
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
|
||||
defer cancel()
|
||||
|
||||
appearance, err := client.Appearance(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, supportLinks, appearance.SupportLinks)
|
||||
}
|
||||
|
||||
func TestDefaultSupportLinks(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdenttest.New(t, nil)
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
// Don't need to set the license, as default links are passed without it.
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
|
||||
defer cancel()
|
||||
|
||||
appearance, err := client.Appearance(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, coderd.DefaultSupportLinks, appearance.SupportLinks)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user