Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/resources/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ resource "coder_app" "code-server" {
display_name = "VS Code"
icon = "${data.coder_workspace.me.access_url}/icon/code.svg"
url = "http://localhost:13337"
tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button."
share = "owner"
subdomain = false
open_in = "window"
Expand Down Expand Up @@ -71,6 +72,7 @@ resource "coder_app" "vim" {
- `order` (Number) The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order).
- `share` (String) Determines the level which the application is shared at. Valid levels are `"owner"` (default), `"authenticated"` and `"public"`. Level `"owner"` disables sharing on the app, so only the workspace owner can access it. Level `"authenticated"` shares the app with all authenticated users. Level `"public"` shares it with any user, including unauthenticated users. Permitted application sharing levels can be configured site-wide via a flag on `coder server` (Enterprise only).
- `subdomain` (Boolean) Determines whether the app will be accessed via it's own subdomain or whether it will be accessed via a path on Coder. If wildcards have not been setup by the administrator then apps with `subdomain` set to `true` will not be accessible. Defaults to `false`.
- `tooltip` (String) String with markdown support to display over the app icon in a workspace dashboard.
- `url` (String) An external url if `external=true` or a URL to be proxied to from inside the workspace. This should be of the form `http://localhost:PORT[/SUBPATH]`. Either `command` or `url` may be specified, but not both.

### Read-Only
Expand Down
1 change: 1 addition & 0 deletions examples/resources/coder_app/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ resource "coder_app" "code-server" {
display_name = "VS Code"
icon = "${data.coder_workspace.me.access_url}/icon/code.svg"
url = "http://localhost:13337"
tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button."
share = "owner"
subdomain = false
open_in = "window"
Expand Down
18 changes: 18 additions & 0 deletions provider/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var (
const (
appDisplayNameMaxLength = 64 // database column limit
appGroupNameMaxLength = 64
appTooltipMaxLength = 512
)

func appResource() *schema.Resource {
Expand Down Expand Up @@ -273,6 +274,23 @@ func appResource() *schema.Resource {
return diag.Errorf(`invalid "coder_app" open_in value, must be one of "tab", "slim-window": %q`, valStr)
},
},
"tooltip": {
Type: schema.TypeString,
Description: "String with markdown support to display over the app icon in a workspace dashboard.",
ForceNew: true,
Optional: true,
ValidateDiagFunc: func(val any, c cty.Path) diag.Diagnostics {
valStr, ok := val.(string)
if !ok {
return diag.Errorf("expected string, got %T", val)
}

if len(valStr) > appTooltipMaxLength {
return diag.Errorf("tooltip is too long (max %d characters)", appTooltipMaxLength)
}
return nil
},
},
},
}
}
65 changes: 65 additions & 0 deletions provider/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func TestApp(t *testing.T) {
order = 4
hidden = false
open_in = "slim-window"
tooltip = "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop#install-coder-desktop) to use this button."
}
`,
Check: func(state *terraform.State) error {
Expand All @@ -68,6 +69,7 @@ func TestApp(t *testing.T) {
"order",
"hidden",
"open_in",
"tooltip",
} {
value := resource.Primary.Attributes[key]
t.Logf("%q = %q", key, value)
Expand Down Expand Up @@ -535,4 +537,67 @@ func TestApp(t *testing.T) {
})
}
})

t.Run("Tooltip", func(t *testing.T) {
t.Parallel()

cases := []struct {
name string
tooltip string
expectError *regexp.Regexp
}{
{
name: "Empty",
tooltip: "",
},
{
name: "ValidTooltip",
tooltip: "You need to [Install Coder Desktop](https://coder.com/docs/user-guides/desktop" +
"#install-coder-desktop) to use this button.",
},
{
name: "TooltipTooLong", // > 512 characters
tooltip: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " +
"incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud " +
"exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " +
"in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint " +
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. " +
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque.",
expectError: regexp.MustCompile("tooltip is too long"),
},
}

for _, c := range cases {
c := c

t.Run(c.name, func(t *testing.T) {
t.Parallel()

config := fmt.Sprintf(`
provider "coder" {}
resource "coder_agent" "dev" {
os = "linux"
arch = "amd64"
}
resource "coder_app" "code-server" {
agent_id = coder_agent.dev.id
slug = "code-server"
display_name = "Testing"
url = "http://localhost:13337"
open_in = "slim-window"
tooltip = "%s"
}
`, c.tooltip)

resource.Test(t, resource.TestCase{
ProviderFactories: coderFactory(),
IsUnitTest: true,
Steps: []resource.TestStep{{
Config: config,
ExpectError: c.expectError,
}},
})
})
}
})
}
Loading